mirror of https://github.com/usbharu/Hideout.git
feat: ActivityPub関係のリクエストは署名を検証するように
This commit is contained in:
parent
d6fe604253
commit
de4d5ca339
|
@ -7,7 +7,16 @@ import com.nimbusds.jose.jwk.source.ImmutableJWKSet
|
||||||
import com.nimbusds.jose.jwk.source.JWKSource
|
import com.nimbusds.jose.jwk.source.JWKSource
|
||||||
import com.nimbusds.jose.proc.SecurityContext
|
import com.nimbusds.jose.proc.SecurityContext
|
||||||
import dev.usbharu.hideout.domain.model.UserDetailsImpl
|
import dev.usbharu.hideout.domain.model.UserDetailsImpl
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
|
import dev.usbharu.hideout.service.signature.HttpSignatureFilter
|
||||||
|
import dev.usbharu.hideout.service.signature.HttpSignatureUserDetailsService
|
||||||
|
import dev.usbharu.hideout.service.signature.HttpSignatureVerifierComposite
|
||||||
import dev.usbharu.hideout.util.RsaUtil
|
import dev.usbharu.hideout.util.RsaUtil
|
||||||
|
import dev.usbharu.httpsignature.sign.RsaSha256HttpSignatureSigner
|
||||||
|
import dev.usbharu.httpsignature.verify.DefaultSignatureHeaderParser
|
||||||
|
import dev.usbharu.httpsignature.verify.RsaSha256HttpSignatureVerifier
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer
|
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer
|
||||||
import org.springframework.boot.autoconfigure.security.servlet.PathRequest
|
import org.springframework.boot.autoconfigure.security.servlet.PathRequest
|
||||||
|
@ -19,9 +28,13 @@ import org.springframework.core.annotation.Order
|
||||||
import org.springframework.http.HttpMethod
|
import org.springframework.http.HttpMethod
|
||||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder
|
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder
|
||||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
|
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
|
||||||
|
import org.springframework.security.authentication.AccountStatusUserDetailsChecker
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager
|
||||||
import org.springframework.security.config.Customizer
|
import org.springframework.security.config.Customizer
|
||||||
|
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||||
|
import org.springframework.security.config.http.SessionCreationPolicy
|
||||||
import org.springframework.security.core.Authentication
|
import org.springframework.security.core.Authentication
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder
|
import org.springframework.security.crypto.password.PasswordEncoder
|
||||||
|
@ -33,6 +46,7 @@ import org.springframework.security.oauth2.server.authorization.token.JwtEncodin
|
||||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer
|
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer
|
||||||
import org.springframework.security.web.SecurityFilterChain
|
import org.springframework.security.web.SecurityFilterChain
|
||||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint
|
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint
|
||||||
|
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider
|
||||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher
|
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher
|
||||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector
|
import org.springframework.web.servlet.handler.HandlerMappingIntrospector
|
||||||
import java.security.KeyPairGenerator
|
import java.security.KeyPairGenerator
|
||||||
|
@ -42,11 +56,63 @@ import java.util.*
|
||||||
|
|
||||||
@EnableWebSecurity(debug = false)
|
@EnableWebSecurity(debug = false)
|
||||||
@Configuration
|
@Configuration
|
||||||
@Suppress("FunctionMaxLength ")
|
@Suppress("FunctionMaxLength")
|
||||||
class SecurityConfig {
|
class SecurityConfig {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private lateinit var userQueryService: UserQueryService
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun authenticationManager(authenticationConfiguration: AuthenticationConfiguration): AuthenticationManager? {
|
||||||
|
return authenticationConfiguration.authenticationManager
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Order(1)
|
@Order(1)
|
||||||
|
fun httpSignatureFilterChain(http: HttpSecurity, httpSignatureFilter: HttpSignatureFilter): SecurityFilterChain {
|
||||||
|
http.securityMatcher("/inbox", "/outbox", "/users/*/inbox", "/users/*/outbox")
|
||||||
|
.addFilter(httpSignatureFilter)
|
||||||
|
.authorizeHttpRequests {
|
||||||
|
it.anyRequest().permitAll()
|
||||||
|
}
|
||||||
|
.csrf {
|
||||||
|
it.disable()
|
||||||
|
}
|
||||||
|
.sessionManagement {
|
||||||
|
it.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||||
|
}
|
||||||
|
return http.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun getHttpSignatureFilter(authenticationManager: AuthenticationManager): HttpSignatureFilter {
|
||||||
|
val httpSignatureFilter = HttpSignatureFilter(DefaultSignatureHeaderParser())
|
||||||
|
httpSignatureFilter.setAuthenticationManager(authenticationManager)
|
||||||
|
return httpSignatureFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun httpSignatureAuthenticationProvider(transaction: Transaction): PreAuthenticatedAuthenticationProvider {
|
||||||
|
val provider = PreAuthenticatedAuthenticationProvider()
|
||||||
|
provider.setPreAuthenticatedUserDetailsService(
|
||||||
|
HttpSignatureUserDetailsService(
|
||||||
|
userQueryService, HttpSignatureVerifierComposite(
|
||||||
|
mapOf(
|
||||||
|
"rsa-sha256" to RsaSha256HttpSignatureVerifier(
|
||||||
|
DefaultSignatureHeaderParser(),
|
||||||
|
RsaSha256HttpSignatureSigner()
|
||||||
|
)
|
||||||
|
), DefaultSignatureHeaderParser()
|
||||||
|
), transaction
|
||||||
|
)
|
||||||
|
)
|
||||||
|
provider.setUserDetailsChecker(AccountStatusUserDetailsChecker())
|
||||||
|
return provider
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Order(2)
|
||||||
fun oauth2SecurityFilterChain(http: HttpSecurity, introspector: HandlerMappingIntrospector): SecurityFilterChain {
|
fun oauth2SecurityFilterChain(http: HttpSecurity, introspector: HandlerMappingIntrospector): SecurityFilterChain {
|
||||||
val builder = MvcRequestMatcher.Builder(introspector)
|
val builder = MvcRequestMatcher.Builder(introspector)
|
||||||
|
|
||||||
|
@ -64,7 +130,7 @@ class SecurityConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Order(2)
|
@Order(4)
|
||||||
fun defaultSecurityFilterChain(http: HttpSecurity, introspector: HandlerMappingIntrospector): SecurityFilterChain {
|
fun defaultSecurityFilterChain(http: HttpSecurity, introspector: HandlerMappingIntrospector): SecurityFilterChain {
|
||||||
val builder = MvcRequestMatcher.Builder(introspector)
|
val builder = MvcRequestMatcher.Builder(introspector)
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ class HttpSignatureFilter(private val httpSignatureHeaderParser: SignatureHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
return HttpRequest(
|
return HttpRequest(
|
||||||
URL(url + request.queryString),
|
URL(url + request.queryString.orEmpty()),
|
||||||
HttpHeaders(headers),
|
HttpHeaders(headers),
|
||||||
method
|
method
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,6 +3,7 @@ package dev.usbharu.hideout.service.signature
|
||||||
import dev.usbharu.hideout.exception.FailedToGetResourcesException
|
import dev.usbharu.hideout.exception.FailedToGetResourcesException
|
||||||
import dev.usbharu.hideout.exception.HttpSignatureVerifyException
|
import dev.usbharu.hideout.exception.HttpSignatureVerifyException
|
||||||
import dev.usbharu.hideout.query.UserQueryService
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
import dev.usbharu.hideout.util.RsaUtil
|
import dev.usbharu.hideout.util.RsaUtil
|
||||||
import dev.usbharu.httpsignature.common.HttpRequest
|
import dev.usbharu.httpsignature.common.HttpRequest
|
||||||
import dev.usbharu.httpsignature.common.PublicKey
|
import dev.usbharu.httpsignature.common.PublicKey
|
||||||
|
@ -16,10 +17,14 @@ import org.springframework.security.web.authentication.preauth.PreAuthenticatedA
|
||||||
|
|
||||||
class HttpSignatureUserDetailsService(
|
class HttpSignatureUserDetailsService(
|
||||||
private val userQueryService: UserQueryService,
|
private val userQueryService: UserQueryService,
|
||||||
private val httpSignatureVerifier: HttpSignatureVerifier
|
private val httpSignatureVerifier: HttpSignatureVerifier,
|
||||||
|
private val transaction: Transaction
|
||||||
) :
|
) :
|
||||||
AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {
|
AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {
|
||||||
override fun loadUserDetails(token: PreAuthenticatedAuthenticationToken): UserDetails = runBlocking {
|
override fun loadUserDetails(token: PreAuthenticatedAuthenticationToken): UserDetails = runBlocking {
|
||||||
|
transaction.transaction {
|
||||||
|
|
||||||
|
|
||||||
if (token.principal !is String) {
|
if (token.principal !is String) {
|
||||||
throw IllegalStateException("Token is not String")
|
throw IllegalStateException("Token is not String")
|
||||||
}
|
}
|
||||||
|
@ -51,4 +56,5 @@ class HttpSignatureUserDetailsService(
|
||||||
authorities = mutableListOf()
|
authorities = mutableListOf()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,4 +13,5 @@
|
||||||
<logger name="Exposed" level="INFO"/>
|
<logger name="Exposed" level="INFO"/>
|
||||||
<logger name="io.ktor.server.plugins.contentnegotiation" level="INFO"/>
|
<logger name="io.ktor.server.plugins.contentnegotiation" level="INFO"/>
|
||||||
<logger name="org.springframework.web.filter.CommonsRequestLoggingFilter" level="INFO"/>
|
<logger name="org.springframework.web.filter.CommonsRequestLoggingFilter" level="INFO"/>
|
||||||
|
<logger name="org.mongodb.driver.protocol.command" level="INFO"/>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
Loading…
Reference in New Issue