mirror of https://github.com/usbharu/Hideout.git
test: リフレッシュトークンのテストを追加
This commit is contained in:
parent
c50f8a0594
commit
2734ea3ffc
|
@ -35,7 +35,7 @@ fun Application.configureSecurity(
|
|||
acceptLeeway(3)
|
||||
}
|
||||
validate { jwtCredential ->
|
||||
if (jwtCredential.payload.getClaim("username").asString().isNotEmpty()) {
|
||||
if (jwtCredential.payload.getClaim("username")?.asString().isNullOrBlank().not()) {
|
||||
JWTPrincipal(jwtCredential.payload)
|
||||
} else {
|
||||
null
|
||||
|
|
|
@ -11,7 +11,9 @@ import dev.usbharu.hideout.config.ConfigData
|
|||
import dev.usbharu.hideout.domain.model.hideout.dto.JwtToken
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.Jwt
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||
import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken
|
||||
import dev.usbharu.hideout.domain.model.hideout.form.UserLogin
|
||||
import dev.usbharu.hideout.exception.InvalidRefreshTokenException
|
||||
import dev.usbharu.hideout.repository.IUserRepository
|
||||
import dev.usbharu.hideout.service.IJwtService
|
||||
import dev.usbharu.hideout.service.IMetaService
|
||||
|
@ -21,17 +23,11 @@ import dev.usbharu.hideout.util.JsonWebKeyUtil
|
|||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.config.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
import io.ktor.server.testing.*
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.ArgumentMatchers.anyString
|
||||
import org.mockito.kotlin.any
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.eq
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.*
|
||||
import java.security.KeyPairGenerator
|
||||
import java.security.interfaces.RSAPrivateKey
|
||||
import java.security.interfaces.RSAPublicKey
|
||||
|
@ -246,7 +242,7 @@ class SecurityKtTest {
|
|||
val jwkProvider = mock<JwkProvider> {
|
||||
onBlocking { get(anyString()) }.doReturn(
|
||||
Jwk.fromValues(
|
||||
(readValue["keys"] as List<Map<String,Any>>)[0]
|
||||
(readValue["keys"] as List<Map<String, Any>>)[0]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -256,27 +252,294 @@ class SecurityKtTest {
|
|||
configureSerialization()
|
||||
configureSecurity(mock(), metaService, userRepository, jwtService, jwkProvider)
|
||||
}
|
||||
externalServices {
|
||||
hosts("http://localhost:8080") {
|
||||
routing {
|
||||
get("/.well-known/jwks.json") {
|
||||
call.application.log.info("aaaaaaaaaaaaaa")
|
||||
println("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
|
||||
call.respondText(
|
||||
contentType = ContentType.Application.Json,
|
||||
text = JsonWebKeyUtil.publicKeyToJwk(rsaPublicKey, kid.toString())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
client.get("/auth-check") {
|
||||
header("Authorization", "Bearer $token")
|
||||
}.apply {
|
||||
assertEquals(HttpStatusCode.OK, call.response.status)
|
||||
assertEquals("Hello \"test\"",call.response.bodyAsText())
|
||||
assertEquals("Hello \"test\"", call.response.bodyAsText())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `auth-check 期限切れのトークンではアクセスできない`() = testApplication {
|
||||
environment {
|
||||
config = ApplicationConfig("empty.conf")
|
||||
}
|
||||
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
|
||||
keyPairGenerator.initialize(2048)
|
||||
val keyPair = keyPairGenerator.generateKeyPair()
|
||||
val rsaPublicKey = keyPair.public as RSAPublicKey
|
||||
|
||||
Config.configData = ConfigData(url = "https://localhost", objectMapper = jacksonObjectMapper())
|
||||
|
||||
|
||||
val now = Instant.now()
|
||||
val kid = UUID.randomUUID()
|
||||
val token = JWT.create()
|
||||
.withAudience("${Config.configData.url}/users/test")
|
||||
.withIssuer(Config.configData.url)
|
||||
.withKeyId(kid.toString())
|
||||
.withClaim("username", "test")
|
||||
.withExpiresAt(now.minus(30, ChronoUnit.MINUTES))
|
||||
.sign(Algorithm.RSA256(rsaPublicKey, keyPair.private as RSAPrivateKey))
|
||||
val metaService = mock<IMetaService> {
|
||||
onBlocking { getJwtMeta() }.doReturn(
|
||||
Jwt(
|
||||
kid,
|
||||
Base64Util.encode(keyPair.private.encoded),
|
||||
Base64Util.encode(rsaPublicKey.encoded)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
val readValue = Config.configData.objectMapper.readerFor(Map::class.java)
|
||||
.readValue<MutableMap<String, Any>?>(
|
||||
JsonWebKeyUtil.publicKeyToJwk(
|
||||
rsaPublicKey,
|
||||
kid.toString()
|
||||
)
|
||||
)
|
||||
val jwkProvider = mock<JwkProvider> {
|
||||
onBlocking { get(anyString()) }.doReturn(
|
||||
Jwk.fromValues(
|
||||
(readValue["keys"] as List<Map<String, Any>>)[0]
|
||||
)
|
||||
)
|
||||
}
|
||||
val userRepository = mock<IUserRepository>()
|
||||
val jwtService = mock<IJwtService>()
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), metaService, userRepository, jwtService, jwkProvider)
|
||||
}
|
||||
client.get("/auth-check") {
|
||||
header("Authorization", "Bearer $token")
|
||||
}.apply {
|
||||
assertEquals(HttpStatusCode.Unauthorized, call.response.status)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `auth-check issuerが間違っているとアクセスできない`() = testApplication {
|
||||
environment {
|
||||
config = ApplicationConfig("empty.conf")
|
||||
}
|
||||
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
|
||||
keyPairGenerator.initialize(2048)
|
||||
val keyPair = keyPairGenerator.generateKeyPair()
|
||||
val rsaPublicKey = keyPair.public as RSAPublicKey
|
||||
|
||||
Config.configData = ConfigData(url = "https://localhost", objectMapper = jacksonObjectMapper())
|
||||
|
||||
|
||||
val now = Instant.now()
|
||||
val kid = UUID.randomUUID()
|
||||
val token = JWT.create()
|
||||
.withAudience("${Config.configData.url}/users/test")
|
||||
.withIssuer("https://example.com")
|
||||
.withKeyId(kid.toString())
|
||||
.withClaim("username", "test")
|
||||
.withExpiresAt(now.plus(30, ChronoUnit.MINUTES))
|
||||
.sign(Algorithm.RSA256(rsaPublicKey, keyPair.private as RSAPrivateKey))
|
||||
val metaService = mock<IMetaService> {
|
||||
onBlocking { getJwtMeta() }.doReturn(
|
||||
Jwt(
|
||||
kid,
|
||||
Base64Util.encode(keyPair.private.encoded),
|
||||
Base64Util.encode(rsaPublicKey.encoded)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
val readValue = Config.configData.objectMapper.readerFor(Map::class.java)
|
||||
.readValue<MutableMap<String, Any>?>(
|
||||
JsonWebKeyUtil.publicKeyToJwk(
|
||||
rsaPublicKey,
|
||||
kid.toString()
|
||||
)
|
||||
)
|
||||
val jwkProvider = mock<JwkProvider> {
|
||||
onBlocking { get(anyString()) }.doReturn(
|
||||
Jwk.fromValues(
|
||||
(readValue["keys"] as List<Map<String, Any>>)[0]
|
||||
)
|
||||
)
|
||||
}
|
||||
val userRepository = mock<IUserRepository>()
|
||||
val jwtService = mock<IJwtService>()
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), metaService, userRepository, jwtService, jwkProvider)
|
||||
}
|
||||
client.get("/auth-check") {
|
||||
header("Authorization", "Bearer $token")
|
||||
}.apply {
|
||||
assertEquals(HttpStatusCode.Unauthorized, call.response.status)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `auth-check usernameが空だと失敗する`() = testApplication {
|
||||
environment {
|
||||
config = ApplicationConfig("empty.conf")
|
||||
}
|
||||
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
|
||||
keyPairGenerator.initialize(2048)
|
||||
val keyPair = keyPairGenerator.generateKeyPair()
|
||||
val rsaPublicKey = keyPair.public as RSAPublicKey
|
||||
|
||||
Config.configData = ConfigData(url = "https://localhost", objectMapper = jacksonObjectMapper())
|
||||
|
||||
|
||||
val now = Instant.now()
|
||||
val kid = UUID.randomUUID()
|
||||
val token = JWT.create()
|
||||
.withAudience("${Config.configData.url}/users/test")
|
||||
.withIssuer(Config.configData.url)
|
||||
.withKeyId(kid.toString())
|
||||
.withClaim("username", "")
|
||||
.withExpiresAt(now.plus(30, ChronoUnit.MINUTES))
|
||||
.sign(Algorithm.RSA256(rsaPublicKey, keyPair.private as RSAPrivateKey))
|
||||
val metaService = mock<IMetaService> {
|
||||
onBlocking { getJwtMeta() }.doReturn(
|
||||
Jwt(
|
||||
kid,
|
||||
Base64Util.encode(keyPair.private.encoded),
|
||||
Base64Util.encode(rsaPublicKey.encoded)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
val readValue = Config.configData.objectMapper.readerFor(Map::class.java)
|
||||
.readValue<MutableMap<String, Any>?>(
|
||||
JsonWebKeyUtil.publicKeyToJwk(
|
||||
rsaPublicKey,
|
||||
kid.toString()
|
||||
)
|
||||
)
|
||||
val jwkProvider = mock<JwkProvider> {
|
||||
onBlocking { get(anyString()) }.doReturn(
|
||||
Jwk.fromValues(
|
||||
(readValue["keys"] as List<Map<String, Any>>)[0]
|
||||
)
|
||||
)
|
||||
}
|
||||
val userRepository = mock<IUserRepository>()
|
||||
val jwtService = mock<IJwtService>()
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), metaService, userRepository, jwtService, jwkProvider)
|
||||
}
|
||||
client.get("/auth-check") {
|
||||
header("Authorization", "Bearer $token")
|
||||
}.apply {
|
||||
assertEquals(HttpStatusCode.Unauthorized, call.response.status)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `auth-check usernameが存在しないと失敗する`() = testApplication {
|
||||
environment {
|
||||
config = ApplicationConfig("empty.conf")
|
||||
}
|
||||
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
|
||||
keyPairGenerator.initialize(2048)
|
||||
val keyPair = keyPairGenerator.generateKeyPair()
|
||||
val rsaPublicKey = keyPair.public as RSAPublicKey
|
||||
|
||||
Config.configData = ConfigData(url = "https://localhost", objectMapper = jacksonObjectMapper())
|
||||
|
||||
|
||||
val now = Instant.now()
|
||||
val kid = UUID.randomUUID()
|
||||
val token = JWT.create()
|
||||
.withAudience("${Config.configData.url}/users/test")
|
||||
.withIssuer(Config.configData.url)
|
||||
.withKeyId(kid.toString())
|
||||
.withExpiresAt(now.plus(30, ChronoUnit.MINUTES))
|
||||
.sign(Algorithm.RSA256(rsaPublicKey, keyPair.private as RSAPrivateKey))
|
||||
val metaService = mock<IMetaService> {
|
||||
onBlocking { getJwtMeta() }.doReturn(
|
||||
Jwt(
|
||||
kid,
|
||||
Base64Util.encode(keyPair.private.encoded),
|
||||
Base64Util.encode(rsaPublicKey.encoded)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
val readValue = Config.configData.objectMapper.readerFor(Map::class.java)
|
||||
.readValue<MutableMap<String, Any>?>(
|
||||
JsonWebKeyUtil.publicKeyToJwk(
|
||||
rsaPublicKey,
|
||||
kid.toString()
|
||||
)
|
||||
)
|
||||
val jwkProvider = mock<JwkProvider> {
|
||||
onBlocking { get(anyString()) }.doReturn(
|
||||
Jwk.fromValues(
|
||||
(readValue["keys"] as List<Map<String, Any>>)[0]
|
||||
)
|
||||
)
|
||||
}
|
||||
val userRepository = mock<IUserRepository>()
|
||||
val jwtService = mock<IJwtService>()
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), metaService, userRepository, jwtService, jwkProvider)
|
||||
}
|
||||
client.get("/auth-check") {
|
||||
header("Authorization", "Bearer $token")
|
||||
}.apply {
|
||||
assertEquals(HttpStatusCode.Unauthorized, call.response.status)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `refresh-token リフレッシュトークンが正当だとトークンを発行する`() = testApplication {
|
||||
Config.configData = ConfigData(url = "https://localhost", objectMapper = jacksonObjectMapper())
|
||||
environment {
|
||||
config = ApplicationConfig("empty.conf")
|
||||
}
|
||||
val jwtService = mock<IJwtService> {
|
||||
onBlocking { refreshToken(any()) }.doReturn(JwtToken("token", "refreshToken2"))
|
||||
}
|
||||
application {
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), jwtService, mock())
|
||||
}
|
||||
client.post("/refresh-token") {
|
||||
header("Content-Type", "application/json")
|
||||
setBody(Config.configData.objectMapper.writeValueAsString(RefreshToken("refreshToken")))
|
||||
}.apply {
|
||||
assertEquals(HttpStatusCode.OK, call.response.status)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `refresh-token リフレッシュトークンが不正だと失敗する`() = testApplication {
|
||||
Config.configData = ConfigData(url = "https://localhost", objectMapper = jacksonObjectMapper())
|
||||
environment {
|
||||
config = ApplicationConfig("empty.conf")
|
||||
}
|
||||
val jwtService = mock<IJwtService> {
|
||||
onBlocking { refreshToken(any()) } doThrow InvalidRefreshTokenException("Invalid Refresh Token")
|
||||
}
|
||||
application {
|
||||
configureStatusPages()
|
||||
configureSerialization()
|
||||
configureSecurity(mock(), mock(), mock(), jwtService, mock())
|
||||
}
|
||||
client.post("/refresh-token") {
|
||||
header("Content-Type", "application/json")
|
||||
setBody(Config.configData.objectMapper.writeValueAsString(RefreshToken("InvalidRefreshToken")))
|
||||
}.apply {
|
||||
assertEquals(HttpStatusCode.BadRequest, call.response.status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue