mirror of https://github.com/usbharu/Hideout.git
test: Inboxのセキュリティテストを追加
This commit is contained in:
parent
3a0d91de79
commit
ee0ad59d40
|
@ -202,6 +202,8 @@ dependencies {
|
||||||
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.1")
|
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.1")
|
||||||
|
|
||||||
intTestImplementation("org.springframework.boot:spring-boot-starter-test")
|
intTestImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||||
|
intTestImplementation("org.springframework.security:spring-security-test")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
detekt {
|
detekt {
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
package activitypub.inbox
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.SpringApplication
|
||||||
|
import org.junit.jupiter.api.BeforeEach
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest
|
||||||
|
import org.springframework.boot.test.context.TestConfiguration
|
||||||
|
import org.springframework.context.annotation.Bean
|
||||||
|
import org.springframework.http.MediaType
|
||||||
|
import org.springframework.security.test.context.support.WithAnonymousUser
|
||||||
|
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity
|
||||||
|
import org.springframework.test.web.servlet.MockMvc
|
||||||
|
import org.springframework.test.web.servlet.post
|
||||||
|
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder
|
||||||
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders
|
||||||
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
import org.springframework.web.context.WebApplicationContext
|
||||||
|
import util.TestTransaction
|
||||||
|
import util.WithHttpSignature
|
||||||
|
|
||||||
|
@SpringBootTest(classes = [SpringApplication::class])
|
||||||
|
@AutoConfigureMockMvc
|
||||||
|
@Transactional
|
||||||
|
class InboxTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private lateinit var context: WebApplicationContext
|
||||||
|
|
||||||
|
private lateinit var mockMvc: MockMvc
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
fun setUp() {
|
||||||
|
mockMvc = MockMvcBuilders.webAppContextSetup(context)
|
||||||
|
.apply<DefaultMockMvcBuilder>(springSecurity())
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithAnonymousUser
|
||||||
|
fun `匿名でinboxにPOSTしたら401`() {
|
||||||
|
mockMvc
|
||||||
|
.post("/inbox") {
|
||||||
|
content = "{}"
|
||||||
|
contentType = MediaType.APPLICATION_JSON
|
||||||
|
}
|
||||||
|
.andExpect { status { isUnauthorized() } }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithHttpSignature
|
||||||
|
fun 有効なHttpSignatureでPOSTしたら202() {
|
||||||
|
mockMvc
|
||||||
|
.post("/inbox") {
|
||||||
|
content = "{}"
|
||||||
|
contentType = MediaType.APPLICATION_JSON
|
||||||
|
}
|
||||||
|
.asyncDispatch()
|
||||||
|
.andExpect { status { isAccepted() } }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithAnonymousUser
|
||||||
|
fun `匿名でuser-inboxにPOSTしたら401`() {
|
||||||
|
mockMvc
|
||||||
|
.post("/users/hoge/inbox") {
|
||||||
|
content = "{}"
|
||||||
|
contentType = MediaType.APPLICATION_JSON
|
||||||
|
}
|
||||||
|
.andExpect { status { isUnauthorized() } }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithHttpSignature
|
||||||
|
fun 有効なHttpSignaturesでPOSTしたら202() {
|
||||||
|
mockMvc
|
||||||
|
.post("/users/hoge/inbox") {
|
||||||
|
content = "{}"
|
||||||
|
contentType = MediaType.APPLICATION_JSON
|
||||||
|
}
|
||||||
|
.asyncDispatch()
|
||||||
|
.andExpect { status { isAccepted() } }
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestConfiguration
|
||||||
|
class Configuration {
|
||||||
|
@Bean
|
||||||
|
fun testTransaction() = TestTransaction
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import org.springframework.core.annotation.AliasFor
|
||||||
|
import org.springframework.security.test.context.support.TestExecutionEvent
|
||||||
|
import org.springframework.security.test.context.support.WithSecurityContext
|
||||||
|
import java.lang.annotation.Inherited
|
||||||
|
|
||||||
|
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.TYPE)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
@Inherited
|
||||||
|
@MustBeDocumented
|
||||||
|
@WithSecurityContext(factory = WithHttpSignatureSecurityContextFactory::class)
|
||||||
|
annotation class WithHttpSignature(
|
||||||
|
@get:AliasFor(
|
||||||
|
annotation = WithSecurityContext::class
|
||||||
|
) val setupBefore: TestExecutionEvent = TestExecutionEvent.TEST_METHOD
|
||||||
|
)
|
|
@ -0,0 +1,39 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.infrastructure.springframework.httpsignature.HttpSignatureUser
|
||||||
|
import dev.usbharu.httpsignature.common.HttpHeaders
|
||||||
|
import dev.usbharu.httpsignature.common.HttpMethod
|
||||||
|
import dev.usbharu.httpsignature.common.HttpRequest
|
||||||
|
import org.springframework.security.core.context.SecurityContext
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder
|
||||||
|
import org.springframework.security.test.context.support.WithSecurityContextFactory
|
||||||
|
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
|
class WithHttpSignatureSecurityContextFactory : WithSecurityContextFactory<WithHttpSignature> {
|
||||||
|
|
||||||
|
private val securityContextStrategy = SecurityContextHolder.getContextHolderStrategy()
|
||||||
|
|
||||||
|
override fun createSecurityContext(annotation: WithHttpSignature): SecurityContext {
|
||||||
|
val httpSignatureUser = HttpSignatureUser(
|
||||||
|
"user",
|
||||||
|
"example.com",
|
||||||
|
12345,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
mutableListOf()
|
||||||
|
)
|
||||||
|
val preAuthenticatedAuthenticationToken = PreAuthenticatedAuthenticationToken(
|
||||||
|
"user", HttpRequest(
|
||||||
|
URL("https://example.com/inbox"),
|
||||||
|
HttpHeaders(mapOf()), HttpMethod.GET
|
||||||
|
)
|
||||||
|
)
|
||||||
|
preAuthenticatedAuthenticationToken.details = httpSignatureUser
|
||||||
|
preAuthenticatedAuthenticationToken.isAuthenticated = true
|
||||||
|
val emptyContext = securityContextStrategy.createEmptyContext()
|
||||||
|
emptyContext.authentication = preAuthenticatedAuthenticationToken
|
||||||
|
return emptyContext
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
<configuration>
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{x-request-id}] %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
<root level="TRACE">
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
|
</root>
|
||||||
|
</configuration>
|
|
@ -48,7 +48,6 @@ open class JsonLd {
|
||||||
|
|
||||||
class ContextDeserializer : JsonDeserializer<String>() {
|
class ContextDeserializer : JsonDeserializer<String>() {
|
||||||
|
|
||||||
|
|
||||||
override fun deserialize(
|
override fun deserialize(
|
||||||
p0: com.fasterxml.jackson.core.JsonParser?,
|
p0: com.fasterxml.jackson.core.JsonParser?,
|
||||||
p1: com.fasterxml.jackson.databind.DeserializationContext?
|
p1: com.fasterxml.jackson.databind.DeserializationContext?
|
||||||
|
@ -72,7 +71,6 @@ class ContextSerializer : JsonSerializer<List<String>>() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun serialize(value: List<String>?, gen: JsonGenerator?, serializers: SerializerProvider) {
|
override fun serialize(value: List<String>?, gen: JsonGenerator?, serializers: SerializerProvider) {
|
||||||
|
|
||||||
if (value.isNullOrEmpty()) {
|
if (value.isNullOrEmpty()) {
|
||||||
serializers.defaultSerializeNull(gen)
|
serializers.defaultSerializeNull(gen)
|
||||||
return
|
return
|
||||||
|
|
|
@ -24,7 +24,6 @@ open class Object : JsonLd {
|
||||||
this.id = id
|
this.id = id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other !is Object) return false
|
if (other !is Object) return false
|
||||||
|
|
|
@ -59,7 +59,7 @@ import java.security.interfaces.RSAPrivateKey
|
||||||
import java.security.interfaces.RSAPublicKey
|
import java.security.interfaces.RSAPublicKey
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@EnableWebSecurity(debug = false)
|
@EnableWebSecurity(debug = true)
|
||||||
@Configuration
|
@Configuration
|
||||||
@Suppress("FunctionMaxLength", "TooManyFunctions")
|
@Suppress("FunctionMaxLength", "TooManyFunctions")
|
||||||
class SecurityConfig {
|
class SecurityConfig {
|
||||||
|
@ -82,7 +82,7 @@ class SecurityConfig {
|
||||||
HttpSignatureFilter::class.java
|
HttpSignatureFilter::class.java
|
||||||
)
|
)
|
||||||
.authorizeHttpRequests {
|
.authorizeHttpRequests {
|
||||||
it.anyRequest().permitAll()
|
it.anyRequest().authenticated()
|
||||||
}
|
}
|
||||||
.csrf {
|
.csrf {
|
||||||
it.disable()
|
it.disable()
|
||||||
|
@ -110,7 +110,6 @@ class SecurityConfig {
|
||||||
AuthenticationEntryPointFailureHandler(HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
|
AuthenticationEntryPointFailureHandler(HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
|
||||||
authenticationEntryPointFailureHandler.setRethrowAuthenticationServiceException(false)
|
authenticationEntryPointFailureHandler.setRethrowAuthenticationServiceException(false)
|
||||||
httpSignatureFilter.setAuthenticationFailureHandler(authenticationEntryPointFailureHandler)
|
httpSignatureFilter.setAuthenticationFailureHandler(authenticationEntryPointFailureHandler)
|
||||||
|
|
||||||
return httpSignatureFilter
|
return httpSignatureFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue