feat(ai-character): 관리자 API Phase 1 기반을 추가한다
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
package kr.co.vividnext.sodalive.jwt
|
||||
|
||||
import io.jsonwebtoken.Jwts
|
||||
import io.jsonwebtoken.SignatureAlgorithm
|
||||
import io.jsonwebtoken.io.Decoders
|
||||
import io.jsonwebtoken.security.Keys
|
||||
import kr.co.vividnext.sodalive.common.SodaException
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.member.token.MemberToken
|
||||
import kr.co.vividnext.sodalive.member.token.MemberTokenRepository
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertThrows
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.ValueSource
|
||||
import org.mockito.Mockito
|
||||
import java.util.Base64
|
||||
import java.util.Date
|
||||
import java.util.Optional
|
||||
|
||||
class TokenProviderTest {
|
||||
private lateinit var tokenProvider: TokenProvider
|
||||
private lateinit var memberRepository: MemberRepository
|
||||
private lateinit var tokenRepository: MemberTokenRepository
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
memberRepository = Mockito.mock(MemberRepository::class.java)
|
||||
tokenRepository = Mockito.mock(MemberTokenRepository::class.java)
|
||||
tokenProvider = TokenProvider(
|
||||
secret = SECRET,
|
||||
tokenValidityInSeconds = 3600,
|
||||
repository = memberRepository,
|
||||
tokenRepository = tokenRepository
|
||||
)
|
||||
tokenProvider.afterPropertiesSet()
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("subject가 없는 서명 JWT는 bad_credentials로 변환된다")
|
||||
fun shouldRejectSignedJwtWithoutSubjectAsBadCredentials() {
|
||||
val token = signedToken(subject = null)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
tokenProvider.getAuthentication(token)
|
||||
}
|
||||
|
||||
assertEquals("common.error.bad_credentials", exception.messageKey)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("숫자가 아닌 subject의 서명 JWT는 bad_credentials로 변환된다")
|
||||
fun shouldRejectSignedJwtWithNonNumericSubjectAsBadCredentials() {
|
||||
val token = signedToken(subject = "not-a-number")
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
tokenProvider.getAuthentication(token)
|
||||
}
|
||||
|
||||
assertEquals("common.error.bad_credentials", exception.messageKey)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("auth claim이 없는 서명 JWT는 bad_credentials로 변환된다")
|
||||
fun shouldRejectSignedJwtWithoutAuthoritiesClaimAsBadCredentials() {
|
||||
val token = signedToken(subject = MEMBER_ID.toString(), authorities = null)
|
||||
allowStoredToken(token)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
tokenProvider.getAuthentication(token)
|
||||
}
|
||||
|
||||
assertEquals("common.error.bad_credentials", exception.messageKey)
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = ["", " ", "ROLE_ADMIN,", ",ROLE_ADMIN", "ROLE_ADMIN,,ROLE_USER"])
|
||||
@DisplayName("비어 있는 authority를 포함한 서명 JWT는 bad_credentials로 변환된다")
|
||||
fun shouldRejectSignedJwtWithBlankAuthorityAsBadCredentials(authorities: String) {
|
||||
val token = signedToken(subject = MEMBER_ID.toString(), authorities = authorities)
|
||||
allowStoredToken(token)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
tokenProvider.getAuthentication(token)
|
||||
}
|
||||
|
||||
assertEquals("common.error.bad_credentials", exception.messageKey)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("문자열이 아닌 auth claim의 서명 JWT는 bad_credentials로 변환된다")
|
||||
fun shouldRejectSignedJwtWithNonStringAuthoritiesClaimAsBadCredentials() {
|
||||
val token = signedToken(subject = MEMBER_ID.toString(), authorities = 1)
|
||||
allowStoredToken(token)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
tokenProvider.getAuthentication(token)
|
||||
}
|
||||
|
||||
assertEquals("common.error.bad_credentials", exception.messageKey)
|
||||
}
|
||||
|
||||
private fun allowStoredToken(token: String) {
|
||||
val member = Member(
|
||||
email = "admin@example.com",
|
||||
password = "password",
|
||||
nickname = "admin",
|
||||
role = MemberRole.ADMIN
|
||||
).apply { id = MEMBER_ID }
|
||||
Mockito.`when`(tokenRepository.findById(MEMBER_ID))
|
||||
.thenReturn(Optional.of(MemberToken(MEMBER_ID, mutableSetOf(token))))
|
||||
Mockito.`when`(memberRepository.findById(MEMBER_ID)).thenReturn(Optional.of(member))
|
||||
}
|
||||
|
||||
private fun signedToken(subject: String?, authorities: Any? = "ROLE_ADMIN"): String {
|
||||
val builder = Jwts.builder()
|
||||
.signWith(Keys.hmacShaKeyFor(Decoders.BASE64.decode(SECRET)), SignatureAlgorithm.HS512)
|
||||
.setExpiration(Date(System.currentTimeMillis() + 60_000))
|
||||
|
||||
if (subject != null) {
|
||||
builder.setSubject(subject)
|
||||
}
|
||||
if (authorities != null) {
|
||||
builder.claim("auth", authorities)
|
||||
}
|
||||
|
||||
return builder.compact()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MEMBER_ID = 1L
|
||||
private val SECRET = Base64.getEncoder().encodeToString("a".repeat(64).toByteArray())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user