diff --git a/spring/pom.xml b/spring/pom.xml
index ee1a27be..6cfb9da0 100644
--- a/spring/pom.xml
+++ b/spring/pom.xml
@@ -54,6 +54,10 @@
org.springframework.boot
spring-boot-starter-oauth2-client
+
+ org.springframework.boot
+ spring-boot-starter-oauth2-resource-server
+
org.springframework.security
spring-security-test
diff --git a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/configs/securities/CustomOAuthorizationRequestResolver.kt b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/configs/securities/CustomOAuthorizationRequestResolver.kt
index acd716a2..4b0020cc 100644
--- a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/configs/securities/CustomOAuthorizationRequestResolver.kt
+++ b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/configs/securities/CustomOAuthorizationRequestResolver.kt
@@ -114,7 +114,11 @@ class CustomOAuthorizationRequestResolver(
val identityProviders = IdentityProvider.values().map { it.queryParam }
val targetIdentityProvider = originalRequest.parameterMap["type"]?.find { it in identityProviders }
authorizationRequestCustomizer = Consumer {
- it.parameters { params -> params["connection"] = targetIdentityProvider ?: "google-oauth2" }
+ it.parameters { params ->
+ params["connection"] = targetIdentityProvider ?: "google-oauth2"
+ //To obtain a JWT token from Auth0, it is necessary to configure the audience for the access token.
+ params["audience"] = "https://api.gaas.waterballsa.tw"
+ }
}
return resolve(request, registrationId, redirectUriAction)!!
diff --git a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/configs/securities/CustomSuccessHandler.kt b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/configs/securities/CustomSuccessHandler.kt
new file mode 100644
index 00000000..e6be1aaf
--- /dev/null
+++ b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/configs/securities/CustomSuccessHandler.kt
@@ -0,0 +1,38 @@
+package tw.waterballsa.gaas.spring.configs.securities
+
+import org.springframework.beans.factory.annotation.Value
+import org.springframework.security.core.Authentication
+import org.springframework.security.oauth2.client.OAuth2AuthorizedClient
+import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService
+import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken
+import org.springframework.security.oauth2.core.oidc.user.OidcUser
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler
+import tw.waterballsa.gaas.application.usecases.CreateUserUseCase
+import javax.servlet.http.HttpServletRequest
+import javax.servlet.http.HttpServletResponse
+
+class CustomSuccessHandler(
+ private val authorizedClientService: OAuth2AuthorizedClientService,
+ private val createUserUseCase: CreateUserUseCase
+) : AuthenticationSuccessHandler {
+ @Value("\${frontend}")
+ private lateinit var frontendUrl: String
+
+ override fun onAuthenticationSuccess(
+ request: HttpServletRequest,
+ response: HttpServletResponse,
+ authentication: Authentication
+ ) {
+ authentication as OAuth2AuthenticationToken
+
+ val email = authentication.principal.let { it as OidcUser }.email
+ createUserUseCase.execute(CreateUserUseCase.Request(email))
+
+ val accessTokenValue = authorizedClientService.loadAuthorizedClient(
+ authentication.authorizedClientRegistrationId,
+ authentication.name
+ )
+ .accessToken.tokenValue
+ response.sendRedirect("$frontendUrl/auth/token/$accessTokenValue")
+ }
+}
\ No newline at end of file
diff --git a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/configs/securities/IdTokenAuthenticationFilter.kt b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/configs/securities/IdTokenAuthenticationFilter.kt
deleted file mode 100644
index 926d8930..00000000
--- a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/configs/securities/IdTokenAuthenticationFilter.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package tw.waterballsa.gaas.spring.configs.securities
-
-import org.springframework.http.HttpHeaders.AUTHORIZATION
-import org.springframework.security.core.GrantedAuthority
-import org.springframework.security.core.context.SecurityContextHolder
-import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken
-import org.springframework.security.oauth2.client.oidc.authentication.OidcIdTokenDecoderFactory
-import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository
-import org.springframework.security.oauth2.core.oidc.OidcIdToken
-import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser
-import org.springframework.security.oauth2.core.oidc.user.OidcUser
-import org.springframework.security.oauth2.jwt.JwtException
-import org.springframework.web.filter.OncePerRequestFilter
-import javax.servlet.FilterChain
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
-
-class IdTokenAuthenticationFilter(
- clientRegistrationRepository: ClientRegistrationRepository
-) : OncePerRequestFilter() {
- companion object {
- private const val REGISTRATION_ID = "auth0"
- }
-
- private val registration by lazy { clientRegistrationRepository.findByRegistrationId(REGISTRATION_ID) }
- private val jwtDecoder by lazy { OidcIdTokenDecoderFactory().createDecoder(registration) }
-
- override fun doFilterInternal(
- request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain
- ) {
- request.bearerToken()
- ?.toOidcUser()
- ?.run {
- SecurityContextHolder.getContext().authentication = toOAuth2AuthenticationToken(REGISTRATION_ID)
- }
- filterChain.doFilter(request, response)
- }
-
- private fun String.toOidcUser(): OidcUser? = try {
- jwtDecoder.decode(this)
- ?.let { OidcIdToken(it.tokenValue, it.issuedAt, it.expiresAt, it.claims) }
- ?.let { DefaultOidcUser(emptyList(), it) }
- } catch (e: JwtException) {
- // id token not accept
- null
- }
-
- private fun OidcUser.toOAuth2AuthenticationToken(registrationId: String) = OAuth2AuthenticationToken(
- this, emptyList(), registrationId
- )
-}
-
-private fun HttpServletRequest.bearerToken(): String? = this.getHeader(AUTHORIZATION)
- ?.takeIf { it.startsWith("Bearer ") }
- ?.split(" ")
- ?.last()
\ No newline at end of file
diff --git a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/configs/securities/SecurityConfig.kt b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/configs/securities/SecurityConfig.kt
index 70090979..31de0837 100644
--- a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/configs/securities/SecurityConfig.kt
+++ b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/configs/securities/SecurityConfig.kt
@@ -3,6 +3,7 @@ package tw.waterballsa.gaas.spring.configs.securities
import org.springframework.context.annotation.Bean
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
+import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository
@@ -11,12 +12,15 @@ import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser
import org.springframework.security.oauth2.core.oidc.user.OidcUser
import org.springframework.security.web.AuthenticationEntryPoint
import org.springframework.security.web.SecurityFilterChain
-import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler
+import tw.waterballsa.gaas.application.usecases.CreateUserUseCase
import javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED
@EnableWebSecurity
class SecurityConfig(
private val clientRegistrationRepository: ClientRegistrationRepository,
+ private val authorizedClientService: OAuth2AuthorizedClientService,
+ private val createUserUseCase: CreateUserUseCase
) {
@Bean
@@ -29,7 +33,7 @@ class SecurityConfig(
.anyRequest().authenticated()
.and()
.oauth2Login()
- .defaultSuccessUrl("/login-successfully", true)
+ .successHandler(successHandler())
.authorizationEndpoint()
.authorizationRequestResolver(
CustomOAuthorizationRequestResolver(
@@ -41,14 +45,19 @@ class SecurityConfig(
.userInfoEndpoint().oidcUserService(oidcUserService())
.and()
.and()
+ .oauth2ResourceServer().jwt().and()
+ .and()
.exceptionHandling()
.authenticationEntryPoint(redirectToLoginEndPoint())
- .and()
- .addFilterBefore(IdTokenAuthenticationFilter(clientRegistrationRepository), UsernamePasswordAuthenticationFilter::class.java)
return http.build()
}
+ @Bean
+ fun successHandler(): AuthenticationSuccessHandler{
+ return CustomSuccessHandler(authorizedClientService, createUserUseCase);
+ }
+
private fun oidcUserService(): OAuth2UserService {
val userService = OidcUserService()
return OAuth2UserService { request: OidcUserRequest? ->
diff --git a/spring/src/main/resources/application-dev.yaml b/spring/src/main/resources/application-dev.yaml
index 8c0c2a4e..ec57257e 100644
--- a/spring/src/main/resources/application-dev.yaml
+++ b/spring/src/main/resources/application-dev.yaml
@@ -27,6 +27,9 @@ spring:
authorization-uri: https://dev-1l0ixjw8yohsluoi.us.auth0.com/authorize
token-uri: https://dev-1l0ixjw8yohsluoi.us.auth0.com/oauth/token
user-info-uri: https://dev-1l0ixjw8yohsluoi.us.auth0.com/oauth/userinfo
+ resourceserver:
+ jwt:
+ issuer-uri: https://dev-1l0ixjw8yohsluoi.us.auth0.com/
server:
port: 8087
diff --git a/spring/src/main/resources/application.yaml b/spring/src/main/resources/application.yaml
index cb9b552f..c8d2a21d 100644
--- a/spring/src/main/resources/application.yaml
+++ b/spring/src/main/resources/application.yaml
@@ -19,6 +19,9 @@ spring:
auth0:
# trailing slash is important!
issuer-uri: https://dev-1l0ixjw8yohsluoi.us.auth0.com/
+ resourceserver:
+ jwt:
+ issuer-uri: https://dev-1l0ixjw8yohsluoi.us.auth0.com/
frontend: https://lobby.gaas.waterballsa.tw