From 4b3f79332fb2c3c6fe39cb6643ed674b8bad99fe Mon Sep 17 00:00:00 2001 From: Dreamstar Enterprises <39380005+dreamstar-enterprises@users.noreply.github.com> Date: Sat, 3 Aug 2024 08:25:19 +0100 Subject: [PATCH] Delete Spring BFF/auth directory --- Spring BFF/auth/AuthServerConfig.kt | 68 ---------- Spring BFF/auth/DefaultSecurityConfig.kt | 120 ----------------- .../auth/converters/BasicJSONConverter.kt | 42 ------ Spring BFF/auth/cookies/CookiesConfig.kt | 32 ----- Spring BFF/auth/cors/CORSConfig.kt | 73 ---------- .../auth/filters/DocDbAuthenticationFilter.kt | 127 ------------------ .../auth/filters/PostAuthenticationFilter.kt | 71 ---------- .../auth/handlers/AccessDeniedHandler.kt | 45 ------- ...equestAwareAuthenticationSuccessHandler.kt | 24 ---- .../auth/handlers/DocDbFailureHandler.kt | 50 ------- .../auth/handlers/DocDbSuccessHandler.kt | 80 ----------- .../handlers/SocialLoginSuccessHandler.kt | 82 ----------- .../handlers/UserServiceOidcUserHandler.kt | 54 -------- .../AuthorizationEndPointSuccessHandler.kt | 87 ------------ .../manager/ServletAuthenticationManager.kt | 32 ----- .../authentication/DocDbUserAuthentication.kt | 66 --------- Spring BFF/auth/objects/user/DocDbUser.kt | 56 -------- Spring BFF/auth/objects/user/OidcUser.kt | 106 --------------- .../providers/DocDbAuthenticationProvider.kt | 56 -------- .../ClientRegistrationRepository.kt | 86 ------------ .../repositories/OAuth2ServiceRepository.kt | 33 ----- .../RegisteredClientRepository.kt | 84 ------------ .../repositories/SecurityContextRepository.kt | 24 ---- .../repositories/SessionRegistryConfig.kt | 31 ----- .../auth/requestcache/CustomRequestCache.kt | 52 ------- .../sessions/CustomInvalidSessionStrategy.kt | 51 ------- .../CustomSessionAuthenticationStrategy.kt | 89 ------------ .../OAuth2TokenCustomiserJwtEncoding.kt | 107 --------------- .../OAuth2TokenCustomiserOAuth2Claims.kt | 43 ------ .../auth/tokens/TokenCustomiserConfig.kt | 85 ------------ .../userservice/DocDbUserDetailsManager.kt | 21 --- .../DocDbUserDetailsManagerImpl.kt | 119 ---------------- .../userservice/OidcUserDetailsService.kt | 57 -------- .../oidcmappers/GoogleOidcUserMapper.kt | 73 ---------- .../userservice/oidcmappers/OidcMapper.kt | 22 --- .../virtualthreads/VirtualThreadsManager.kt | 66 --------- 36 files changed, 2314 deletions(-) delete mode 100644 Spring BFF/auth/AuthServerConfig.kt delete mode 100644 Spring BFF/auth/DefaultSecurityConfig.kt delete mode 100644 Spring BFF/auth/converters/BasicJSONConverter.kt delete mode 100644 Spring BFF/auth/cookies/CookiesConfig.kt delete mode 100644 Spring BFF/auth/cors/CORSConfig.kt delete mode 100644 Spring BFF/auth/filters/DocDbAuthenticationFilter.kt delete mode 100644 Spring BFF/auth/filters/PostAuthenticationFilter.kt delete mode 100644 Spring BFF/auth/handlers/AccessDeniedHandler.kt delete mode 100644 Spring BFF/auth/handlers/CustomSavedRequestAwareAuthenticationSuccessHandler.kt delete mode 100644 Spring BFF/auth/handlers/DocDbFailureHandler.kt delete mode 100644 Spring BFF/auth/handlers/DocDbSuccessHandler.kt delete mode 100644 Spring BFF/auth/handlers/SocialLoginSuccessHandler.kt delete mode 100644 Spring BFF/auth/handlers/UserServiceOidcUserHandler.kt delete mode 100644 Spring BFF/auth/handlers/not_used/AuthorizationEndPointSuccessHandler.kt delete mode 100644 Spring BFF/auth/manager/ServletAuthenticationManager.kt delete mode 100644 Spring BFF/auth/objects/authentication/DocDbUserAuthentication.kt delete mode 100644 Spring BFF/auth/objects/user/DocDbUser.kt delete mode 100644 Spring BFF/auth/objects/user/OidcUser.kt delete mode 100644 Spring BFF/auth/providers/DocDbAuthenticationProvider.kt delete mode 100644 Spring BFF/auth/repositories/ClientRegistrationRepository.kt delete mode 100644 Spring BFF/auth/repositories/OAuth2ServiceRepository.kt delete mode 100644 Spring BFF/auth/repositories/RegisteredClientRepository.kt delete mode 100644 Spring BFF/auth/repositories/SecurityContextRepository.kt delete mode 100644 Spring BFF/auth/repositories/SessionRegistryConfig.kt delete mode 100644 Spring BFF/auth/requestcache/CustomRequestCache.kt delete mode 100644 Spring BFF/auth/sessions/CustomInvalidSessionStrategy.kt delete mode 100644 Spring BFF/auth/sessions/CustomSessionAuthenticationStrategy.kt delete mode 100644 Spring BFF/auth/tokens/OAuth2TokenCustomiserJwtEncoding.kt delete mode 100644 Spring BFF/auth/tokens/OAuth2TokenCustomiserOAuth2Claims.kt delete mode 100644 Spring BFF/auth/tokens/TokenCustomiserConfig.kt delete mode 100644 Spring BFF/auth/userservice/DocDbUserDetailsManager.kt delete mode 100644 Spring BFF/auth/userservice/DocDbUserDetailsManagerImpl.kt delete mode 100644 Spring BFF/auth/userservice/OidcUserDetailsService.kt delete mode 100644 Spring BFF/auth/userservice/oidcmappers/GoogleOidcUserMapper.kt delete mode 100644 Spring BFF/auth/userservice/oidcmappers/OidcMapper.kt delete mode 100644 Spring BFF/auth/virtualthreads/VirtualThreadsManager.kt diff --git a/Spring BFF/auth/AuthServerConfig.kt b/Spring BFF/auth/AuthServerConfig.kt deleted file mode 100644 index d01d6d4..0000000 --- a/Spring BFF/auth/AuthServerConfig.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.example.authorizationserver.auth.security - -import org.springframework.beans.factory.annotation.Value -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.core.annotation.Order -import org.springframework.http.MediaType -import org.springframework.security.config.Customizer.withDefaults -import org.springframework.security.config.annotation.web.builders.HttpSecurity -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity -import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration -import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer -import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings -import org.springframework.security.oauth2.server.authorization.token.* -import org.springframework.security.web.SecurityFilterChain -import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint -import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher -import java.util.* - -/**********************************************************************************************************************/ -/********************************************* AUTHORIZATION SERVER CONFIGURATION *************************************/ -/**********************************************************************************************************************/ - -@Configuration -@EnableWebSecurity -internal class AuthServerConfig () { - - @Value("\${in-house-issuer-uri}") - private lateinit var inHouseIssuerUri: String - - @Bean - @Order(1) - @Throws(Exception::class) - /* security filter chain for protocol endpoints */ - fun authorizationServerSecurityFilterChain(http: HttpSecurity): SecurityFilterChain { - - // apply default http security settings to oauth 2.0 (e.g. default endpoints) - OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http) - - // enable OpenID Connect 1.0 - val authorizationServerConfigurer = http.getConfigurer(OAuth2AuthorizationServerConfigurer::class.java) - authorizationServerConfigurer.oidc(withDefaults()) - - // redirect to the login page when not authenticated - http - // handlers for any exceptions not handled elsewhere - .exceptionHandling { - it.defaultAuthenticationEntryPointFor( - LoginUrlAuthenticationEntryPoint("/login"), - MediaTypeRequestMatcher(MediaType.TEXT_HTML) - ) - } - return http.build() - } - - @Bean - // for configuring Spring Authorization Server (e.g. customising URLs for exposed endpoints) - fun authorizationServerSettings(): AuthorizationServerSettings { - return AuthorizationServerSettings.builder() - .issuer(inHouseIssuerUri) - .build() - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/DefaultSecurityConfig.kt b/Spring BFF/auth/DefaultSecurityConfig.kt deleted file mode 100644 index abef5e2..0000000 --- a/Spring BFF/auth/DefaultSecurityConfig.kt +++ /dev/null @@ -1,120 +0,0 @@ -package com.example.authorizationserver.auth.security - -import com.example.authorizationserver.auth.security.filters.DocDbAuthenticationFilter -import com.example.authorizationserver.auth.security.filters.PostAuthenticationFilter -import com.example.authorizationserver.auth.security.handlers.DefaultAccessDeniedHandler -import com.example.authorizationserver.auth.security.handlers.SocialLoginSuccessHandler -import com.example.authorizationserver.auth.security.requestcache.CustomRequestCache -import com.example.authorizationserver.auth.security.sessions.CustomInvalidSessionStrategy -import com.example.authorizationserver.auth.security.sessions.CustomSessionAuthenticationStrategy -import com.example.authorizationserver.auth.security.userservice.DocDbUserDetailsManagerImpl -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.core.annotation.Order -import org.springframework.security.config.annotation.web.builders.HttpSecurity -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity -import org.springframework.security.config.http.SessionCreationPolicy -import org.springframework.security.oauth2.client.* -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository -import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository -import org.springframework.security.web.SecurityFilterChain -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter -import org.springframework.security.web.context.SecurityContextRepository - -/**********************************************************************************************************************/ -/*********************************************** DEFAULT SECURITY CONFIGURATION ***************************************/ -/**********************************************************************************************************************/ - -@Configuration -@EnableWebSecurity -internal class DefaultSecurityConfig () { - - @Autowired - private lateinit var servletClientRegistrationRepository: ClientRegistrationRepository - - @Autowired - private lateinit var servletAuthorizedClientRepository: OAuth2AuthorizedClientRepository - - @Autowired - private lateinit var servletAuthorizedClientService: OAuth2AuthorizedClientService - - @Bean - @Order(2) - @Throws(Exception::class) - /* security filter chain for authentication & authorization */ - fun defaultSecurityFilterChain( - http: HttpSecurity, - socialLoginSuccessHandler: SocialLoginSuccessHandler, - docDbAuthenticationFilter: DocDbAuthenticationFilter, - customRequestCache: CustomRequestCache, - customSecurityContextRepository: SecurityContextRepository, - customInvalidSessionStrategy: CustomInvalidSessionStrategy, - customSessionAuthenticationStrategy: CustomSessionAuthenticationStrategy, - accessDeniedHandler: DefaultAccessDeniedHandler, - ): SecurityFilterChain { - - http - // disable csrf - .csrf { csrf -> csrf.disable() } - // setup session management - use stateless, and set other configurations - .sessionManagement { session -> - // not truly stateless since HttpSessionSecurityContextRepository is used - session.sessionCreationPolicy(SessionCreationPolicy.STATELESS) - session.enableSessionUrlRewriting(false) - session.invalidSessionStrategy(customInvalidSessionStrategy) - session.sessionAuthenticationStrategy(customSessionAuthenticationStrategy) - } - // apply security context repository - .securityContext { context -> - context.securityContextRepository(customSecurityContextRepository) - } - // configure request cache - .requestCache { requestCache -> - requestCache.requestCache(customRequestCache) - } - // form login handles the redirect to the login page from earlier filter chain - .formLogin { formLogin -> - formLogin - .permitAll() - } - // oauth2.0 client login (google) - .oauth2Login { oauth -> - oauth - .clientRegistrationRepository(servletClientRegistrationRepository) - .authorizedClientRepository(servletAuthorizedClientRepository) - .authorizedClientService(servletAuthorizedClientService) - .successHandler(socialLoginSuccessHandler) - } - // perform cleanup operations on logout (invalidate session, remove cookies & authentication object) - // (note: this does not invalidate access or refresh tokens - they expire whenever they expire) - .logout { logout -> - logout.logoutUrl("/logout") - logout.deleteCookies("AUTH-SESSIONID") - logout.clearAuthentication(true) - logout.invalidateHttpSession(true) - logout.permitAll() - } - // apply DocDb authentication filter - .addFilterBefore( - docDbAuthenticationFilter, - UsernamePasswordAuthenticationFilter::class.java - ) - // authorizations (all end points, apart from login and logout not permitted, unless authenticated) - .authorizeHttpRequests { authorize -> - authorize - .anyRequest().authenticated() - } - // handlers for any exceptions not handled elsewhere - .exceptionHandling { exceptionHandling -> - exceptionHandling.accessDeniedHandler(accessDeniedHandler) - } - - return http.build() - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/converters/BasicJSONConverter.kt b/Spring BFF/auth/converters/BasicJSONConverter.kt deleted file mode 100644 index 95c5d22..0000000 --- a/Spring BFF/auth/converters/BasicJSONConverter.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.example.authorizationserver.auth.security.converters - -import com.example.authorizationserver.auth.security.objects.authentication.DocDbUserAuthentication -import com.example.authorizationserver.auth.security.objects.user.DocDbUser -import jakarta.servlet.http.HttpServletRequest -import org.springframework.security.core.Authentication -import org.springframework.security.core.GrantedAuthority -import org.springframework.security.web.authentication.AuthenticationConverter - -/**********************************************************************************************************************/ -/********************************************* AUTHENTICATION CONVERTER ***********************************************/ -/**********************************************************************************************************************/ - -/* Authentication Converter (when credentials are passed in as plain JSON) */ -internal class BasicJSONConverter : AuthenticationConverter { - - override fun convert(request: HttpServletRequest): Authentication? { - val username = request.getParameter("username") - val password = request.getParameter("password") - - if (username.isNullOrBlank() || password.isNullOrBlank()) { - return null - } - - // return authentication object (un-authenticated) - return DocDbUserAuthentication.unauthenticated( - DocDbUser( - null, - username, - password, - emptyList(), - false, - false, - false, - false - ), password) - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/cookies/CookiesConfig.kt b/Spring BFF/auth/cookies/CookiesConfig.kt deleted file mode 100644 index 8b09077..0000000 --- a/Spring BFF/auth/cookies/CookiesConfig.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.example.authorizationserver.auth.security.cookies - -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.session.web.http.CookieSerializer -import org.springframework.session.web.http.DefaultCookieSerializer - -/**********************************************************************************************************************/ -/******************************************************* CONFIGURATION ************************************************/ -/**********************************************************************************************************************/ - -@Configuration -internal class CookiesConfig { - - @Bean - fun cookieSerializer(): CookieSerializer { - val serializer = DefaultCookieSerializer() - serializer.setCookieName("AUTH-SESSIONID") - serializer.setCookiePath("/") - serializer.setUseHttpOnlyCookie(true) - serializer.setUseSecureCookie(true) - serializer.setSameSite("Strict") - serializer.setCookieMaxAge(5) - serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$") - return serializer - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/cors/CORSConfig.kt b/Spring BFF/auth/cors/CORSConfig.kt deleted file mode 100644 index 6939948..0000000 --- a/Spring BFF/auth/cors/CORSConfig.kt +++ /dev/null @@ -1,73 +0,0 @@ -package com.example.authorizationserver.auth.security.cors - -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod -import org.springframework.web.servlet.config.annotation.CorsRegistry -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer - -/**********************************************************************************************************************/ -/**************************************************** CORS CONFIGURATION ***********************************************/ -/**********************************************************************************************************************/ - -//@Configuration -//// applies to web browser clients only - not server-to-server -//class CORSConfig { -// -// @Bean -// fun corsConfigurer(): WebMvcConfigurer { -// return object : WebMvcConfigurer { -// override fun addCorsMappings(registry: CorsRegistry) { -// // apply CORS settings to the specific endpoint -// registry.addMapping("/oauth2/authorize") -// .allowedOrigins("http://localhost:4200") -// .allowedMethods( -// HttpMethod.GET.name(), -// HttpMethod.POST.name(), -// HttpMethod.PUT.name(), -// HttpMethod.PATCH.name(), -// HttpMethod.DELETE.name(), -// HttpMethod.OPTIONS.name(), -// ) -// .allowedHeaders( -// HttpHeaders.CONTENT_TYPE, -// HttpHeaders.AUTHORIZATION -// ) -// .exposedHeaders( -// HttpHeaders.CONTENT_TYPE, -// HttpHeaders.AUTHORIZATION -// ) -// .allowCredentials(true) -// -// // apply restrictive CORS settings to other endpoints -// registry.addMapping("/**") -// .allowedOrigins() // No origins allowed -// .allowedMethods( -// HttpMethod.GET.name(), -// HttpMethod.POST.name(), -// HttpMethod.PUT.name(), -// HttpMethod.PATCH.name(), -// HttpMethod.DELETE.name(), -// HttpMethod.OPTIONS.name(), -// ) -// .allowedHeaders( -// HttpHeaders.CONTENT_TYPE, -// HttpHeaders.AUTHORIZATION, -// "X-XSRF-TOKEN" -// ) -// .exposedHeaders( -// HttpHeaders.CONTENT_TYPE, -// HttpHeaders.AUTHORIZATION, -// "X-XSRF-TOKEN" -// ) -// .allowCredentials(true) -// .maxAge(0) // disallow pre-flight requests -// } -// } -// } -//} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/filters/DocDbAuthenticationFilter.kt b/Spring BFF/auth/filters/DocDbAuthenticationFilter.kt deleted file mode 100644 index 34478fb..0000000 --- a/Spring BFF/auth/filters/DocDbAuthenticationFilter.kt +++ /dev/null @@ -1,127 +0,0 @@ -package com.example.authorizationserver.auth.security.filters - -import com.example.authorizationserver.auth.security.converters.BasicJSONConverter -import com.example.authorizationserver.auth.security.handlers.CustomSavedRequestAwareAuthenticationSuccessHandler -import com.example.authorizationserver.auth.security.sessions.CustomSessionAuthenticationStrategy -import jakarta.servlet.FilterChain -import jakarta.servlet.ServletRequest -import jakarta.servlet.ServletResponse -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse -import org.springframework.http.HttpMethod -import org.springframework.security.authentication.AuthenticationManager -import org.springframework.security.authentication.InternalAuthenticationServiceException -import org.springframework.security.core.Authentication -import org.springframework.security.core.AuthenticationException -import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter -import org.springframework.security.web.context.SecurityContextRepository -import org.springframework.security.web.util.matcher.RequestMatcher -import org.springframework.stereotype.Component - -/**********************************************************************************************************************/ -/******************************************************* FILTER *******************************************************/ -/**********************************************************************************************************************/ - -@Component -internal class DocDbAuthenticationFilter( - private val servletAuthenticationManager: AuthenticationManager, - private val postAuthenticationFilter: PostAuthenticationFilter, - private val customSessionAuthenticationStrategy: CustomSessionAuthenticationStrategy, - customSavedRequestAwareAuthenticationSuccessHandler: CustomSavedRequestAwareAuthenticationSuccessHandler, - customSecurityContextRepository: SecurityContextRepository, -) : AbstractAuthenticationProcessingFilter(RequestMatcher { request -> - // specify authentication path and other custom conditions here - val loginUrl = "/login" - request.servletPath == loginUrl && request.method == HttpMethod.POST.name() - } - ){ - - private val authenticationConverter = BasicJSONConverter() - private val continueChainBeforeSuccessfulAuthentication = false - - init{ - // initialise class variables - this.setAuthenticationManager(servletAuthenticationManager) - this.setSecurityContextRepository(customSecurityContextRepository) - this.setAuthenticationSuccessHandler(customSavedRequestAwareAuthenticationSuccessHandler) - } - - - // main filter logic (don't user 'super' for this!) - override fun doFilter( - request: ServletRequest, - response: ServletResponse, - chain: FilterChain - ) { - val httpRequest = request as HttpServletRequest - val httpResponse = response as HttpServletResponse - - if (!requiresAuthentication(httpRequest, httpResponse)) { - chain.doFilter(httpRequest, response) - return - } - try { - val authenticationResult = attemptAuthentication(httpRequest, httpResponse) - ?: // return immediately as subclass has indicated that it hasn't completed - return - customSessionAuthenticationStrategy.onAuthentication(authenticationResult, httpRequest, httpResponse) - // Authentication success - if (this.continueChainBeforeSuccessfulAuthentication) { - chain.doFilter(httpRequest, httpResponse) - } - successfulAuthentication(httpRequest, httpResponse, chain, authenticationResult) - } catch (failed: InternalAuthenticationServiceException) { - logger.error("An internal error occurred while trying to authenticate the user.", failed) - unsuccessfulAuthentication(httpRequest, httpResponse, failed) - } catch (ex: AuthenticationException) { - // Authentication failed - unsuccessfulAuthentication(httpRequest, httpResponse, ex) - } - } - - - // attempt authentication (convert request, and then authenticate) - override fun attemptAuthentication( - request: HttpServletRequest, - response: HttpServletResponse - ): Authentication? { - val authenticationRequest = authenticationConverter.convert(request) - return authenticationRequest?.let { - servletAuthenticationManager.authenticate(it) - } - } - - - // perform on successful authentication - override fun successfulAuthentication( - request: HttpServletRequest, - response: HttpServletResponse, - chain: FilterChain, - authResult: Authentication - ) { - - // call the parent class method to perform default actions - super.successfulAuthentication(request, response, chain, authResult) - - // manually invoke PostAuthenticationFilter - postAuthenticationFilter.doFilter(request, response, chain) - } - - - // perform on failed authentication - override fun unsuccessfulAuthentication( - request: HttpServletRequest, - response: HttpServletResponse, - failed: AuthenticationException - ) { - - // call the parent class method to perform default actions - super.unsuccessfulAuthentication(request, response, failed) - - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/filters/PostAuthenticationFilter.kt b/Spring BFF/auth/filters/PostAuthenticationFilter.kt deleted file mode 100644 index 1f3732a..0000000 --- a/Spring BFF/auth/filters/PostAuthenticationFilter.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.example.authorizationserver.auth.security.filters - -import jakarta.servlet.FilterChain -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse -import jakarta.servlet.http.HttpSession -import org.springframework.stereotype.Component -import org.springframework.web.filter.OncePerRequestFilter -import java.time.Duration -import java.time.Instant - -/**********************************************************************************************************************/ -/******************************************************* FILTER *******************************************************/ -/**********************************************************************************************************************/ - -@Component -internal class PostAuthenticationFilter() : OncePerRequestFilter() { - - // main filter logic (don't user 'super' for this!) - override fun doFilterInternal( - request: HttpServletRequest, - response: HttpServletResponse, - filterChain: FilterChain - ) { - - /* session management */ - this.manageSession(request) - - // won't continue filter chain! - - } - - - /** - * Manages the HTTP session, including setting the timeout and logging session properties, - * that cannot be set in SessionAuthenticationStrategy, (e.g. session time out) - * @param request The HttpServletRequest containing the session to manage. - */ - private fun manageSession(request: HttpServletRequest?) { - // retrieve the existing session or return if it doesn't exist - val session: HttpSession? = request?.getSession(false) - - // only proceed if there is a session - session?.let { - // set session timeout to 5 seconds - request.getSession()?.setMaxInactiveInterval(5) - - println("SESSION TIME OUT") - - // retrieve session properties - val creationTime = session.creationTime.let { Instant.ofEpochMilli(it) } - val lastAccessedTime = session.lastAccessedTime.let { Instant.ofEpochMilli(it) } - val timeout = session.maxInactiveInterval - - // calculate expiration time - val expirationTime = lastAccessedTime?.plus(timeout.let { Duration.ofSeconds(it.toLong()) }) - - // log for debugging purposes - println("Session ID: ${session.id}") - println("Session Creation Time: $creationTime") - println("Session Last Accessed Time: $lastAccessedTime") - println("Session Timeout (seconds): $timeout") - println("Session Expiration Time: $expirationTime") - } - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/handlers/AccessDeniedHandler.kt b/Spring BFF/auth/handlers/AccessDeniedHandler.kt deleted file mode 100644 index 7b1099b..0000000 --- a/Spring BFF/auth/handlers/AccessDeniedHandler.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.example.authorizationserver.auth.security.handlers - -import com.fasterxml.jackson.databind.ObjectMapper -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse -import org.springframework.http.HttpStatus -import org.springframework.http.MediaType -import org.springframework.security.access.AccessDeniedException -import org.springframework.security.web.access.AccessDeniedHandler -import org.springframework.stereotype.Component -import java.io.IOException - -/**********************************************************************************************************************/ -/****************************************************** HANDLER *******************************************************/ -/**********************************************************************************************************************/ - -//* FOR AUTHORIZAION FAILURES *// - -@Component -internal class DefaultAccessDeniedHandler : AccessDeniedHandler { - private val objectMapper = ObjectMapper() - - @Throws(IOException::class) - override fun handle( - request: HttpServletRequest?, - response: HttpServletResponse, - accessDeniedException: AccessDeniedException - ) { - response.status = HttpStatus.FORBIDDEN.value() - response.contentType = MediaType.APPLICATION_JSON_VALUE - response.setHeader("Authorization-Status", "Forbidden") - - val errorMessage = accessDeniedException.message ?: "Access Denied" - val errorResponse = mapOf("Authorization Failed" to errorMessage) - val jsonResponse = objectMapper.writeValueAsString(errorResponse) - - response.writer.write(jsonResponse) - response.writer.flush() - response.writer.close() - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/handlers/CustomSavedRequestAwareAuthenticationSuccessHandler.kt b/Spring BFF/auth/handlers/CustomSavedRequestAwareAuthenticationSuccessHandler.kt deleted file mode 100644 index 2549a2b..0000000 --- a/Spring BFF/auth/handlers/CustomSavedRequestAwareAuthenticationSuccessHandler.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.example.authorizationserver.auth.security.handlers - -import com.example.authorizationserver.auth.security.requestcache.CustomRequestCache -import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler -import org.springframework.stereotype.Component - -/**********************************************************************************************************************/ -/****************************************************** HANDLER *******************************************************/ -/**********************************************************************************************************************/ - -@Component -internal class CustomSavedRequestAwareAuthenticationSuccessHandler( - customRequestCache: CustomRequestCache -) : SavedRequestAwareAuthenticationSuccessHandler() { - - init { - // set the custom request cache here - super.setRequestCache(customRequestCache) - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/handlers/DocDbFailureHandler.kt b/Spring BFF/auth/handlers/DocDbFailureHandler.kt deleted file mode 100644 index 286ae2d..0000000 --- a/Spring BFF/auth/handlers/DocDbFailureHandler.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.example.authorizationserver.auth.security.handlers - -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse -import org.springframework.context.annotation.Bean -import org.springframework.security.core.AuthenticationException -import org.springframework.security.core.context.SecurityContextHolder -import org.springframework.security.core.context.SecurityContextHolderStrategy -import org.springframework.security.web.authentication.NullRememberMeServices -import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler -import org.springframework.stereotype.Component - -/**********************************************************************************************************************/ -/****************************************************** HANDLER *******************************************************/ -/**********************************************************************************************************************/ - -@Component -internal class DocDbFailureHandler(): SimpleUrlAuthenticationFailureHandler() { - - private val rememberMeServices = NullRememberMeServices() - - override fun onAuthenticationFailure( - request: HttpServletRequest?, - response: HttpServletResponse?, - exception: AuthenticationException? - ) { - - /* security context */ - // erase security context - val securityContextHolderStrategy : SecurityContextHolderStrategy = SecurityContextHolder.getContextHolderStrategy() - securityContextHolderStrategy.clearContext() - - // log results - logger.trace("Failed to process authentication request", exception) - logger.trace("Cleared SecurityContextHolder") - logger.trace("Handling authentication failure") - - // use rememberMe services - rememberMeServices.loginFail(request, response) - - // carry out final actions - - super.onAuthenticationFailure(request, response, exception) - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/handlers/DocDbSuccessHandler.kt b/Spring BFF/auth/handlers/DocDbSuccessHandler.kt deleted file mode 100644 index dfc8da6..0000000 --- a/Spring BFF/auth/handlers/DocDbSuccessHandler.kt +++ /dev/null @@ -1,80 +0,0 @@ -package com.example.authorizationserver.auth.security.handlers - -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse -import jakarta.servlet.http.HttpSession -import org.springframework.context.ApplicationEventPublisher -import org.springframework.core.log.LogMessage -import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent -import org.springframework.security.core.Authentication -import org.springframework.security.core.context.SecurityContext -import org.springframework.security.core.context.SecurityContextHolder -import org.springframework.security.core.context.SecurityContextHolderStrategy -import org.springframework.security.web.authentication.NullRememberMeServices -import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler -import org.springframework.security.web.context.SecurityContextRepository -import org.springframework.stereotype.Component - -/**********************************************************************************************************************/ -/****************************************************** HANDLER *******************************************************/ -/**********************************************************************************************************************/ - -@Component -internal class DocDbSuccessHandler( - private val customSecurityContextRepository: SecurityContextRepository, - private val eventPublisher: ApplicationEventPublisher, -) : SavedRequestAwareAuthenticationSuccessHandler() { - - private val rememberMeServices = NullRememberMeServices() - - override fun onAuthenticationSuccess( - request: HttpServletRequest, - response: HttpServletResponse, - authResult: Authentication, - ) { - - /* session management */ - // if request has no associated session, do not create a new one - val session: HttpSession? = request.getSession(false) - - session?.let { - // change session id for security reasons (mitigates against session fixation attacks) - request.changeSessionId() - - // set session timeout to 5s! - request.getSession()?.setMaxInactiveInterval(5) - - } - - /* security context */ - // set the authentication into the SecurityContext - val securityContextHolderStrategy : SecurityContextHolderStrategy = SecurityContextHolder.getContextHolderStrategy() - val context: SecurityContext = securityContextHolderStrategy.createEmptyContext() - context.setAuthentication(authResult) - securityContextHolderStrategy.setContext(context) - - // save the security context - customSecurityContextRepository.saveContext(SecurityContextHolder.getContext(), request, response) - - // log results - if (logger.isDebugEnabled) { - logger.debug(LogMessage.format("Set SecurityContextHolder to %s", authResult)) - } - - // use rememberMe services - rememberMeServices.loginSuccess(request, response, authResult) - - // use event publisher - eventPublisher.publishEvent(InteractiveAuthenticationSuccessEvent(authResult, this::class.java)) - - println("REDIRECTING !!!!") - - // carry out final actions - super.onAuthenticationSuccess(request, response, authResult) - - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/handlers/SocialLoginSuccessHandler.kt b/Spring BFF/auth/handlers/SocialLoginSuccessHandler.kt deleted file mode 100644 index 145c99b..0000000 --- a/Spring BFF/auth/handlers/SocialLoginSuccessHandler.kt +++ /dev/null @@ -1,82 +0,0 @@ -package com.example.authorizationserver.auth.security.handlers - -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.security.core.Authentication -import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken -import org.springframework.security.oauth2.core.oidc.user.OidcUser -import org.springframework.security.oauth2.core.user.OAuth2User -import org.springframework.security.web.authentication.AuthenticationSuccessHandler -import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler -import org.springframework.stereotype.Component - -/**********************************************************************************************************************/ -/****************************************************** HANDLER *******************************************************/ -/**********************************************************************************************************************/ - -// more here: -// https://medium.com/@d.snezhinskiy/building-sso-based-on-spring-authorization-server-part-3-of-3-b0b31feb2b6e -// https://docs.spring.io/spring-authorization-server/reference/guides/how-to-social-login.html#advanced-use-cases-capture-users - - -//* FOR SOCIAL LOGINS *// - -@Configuration -internal class SocialLoginSuccessHandlerConfiguration { - - @Bean - internal fun socialLoginAuthenticationSuccessHandler( - handler: UserServiceOidcUserHandler? - ): SocialLoginSuccessHandler { - - val authenticationSuccessHandler = SocialLoginSuccessHandler() - // check if handler is not null before setting it - handler?.let { - authenticationSuccessHandler.setOidcUserHandler { user -> it.accept(user) } - } - return authenticationSuccessHandler - } -} - -@Component -internal class SocialLoginSuccessHandler : AuthenticationSuccessHandler { - - private val delegate: AuthenticationSuccessHandler = SavedRequestAwareAuthenticationSuccessHandler() - - // default behaviour is to do nothing (not invoke it) - private var oauth2UserHandler: (OAuth2User) -> Unit = {} - - // default behaviour is to invoke in this pattern - private var oidcUserHandler: (OidcUser) -> Unit = { user -> oauth2UserHandler.invoke(user) } - - override fun onAuthenticationSuccess( - request: HttpServletRequest, response: HttpServletResponse, authentication: Authentication - ) { - - println("AUTHENTICATION SUCCESS!!!") - - if (authentication is OAuth2AuthenticationToken) { - val principal = authentication.principal - when (principal) { - is OidcUser -> oidcUserHandler.invoke(principal) - is OAuth2User -> oauth2UserHandler.invoke(principal) - } - } - - delegate.onAuthenticationSuccess(request, response, authentication) - } - - fun setOAuth2UserHandler(oauth2UserHandler: (OAuth2User) -> Unit) { - this.oauth2UserHandler = oauth2UserHandler - } - - fun setOidcUserHandler(oidcUserHandler: (OidcUser) -> Unit) { - this.oidcUserHandler = oidcUserHandler - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/handlers/UserServiceOidcUserHandler.kt b/Spring BFF/auth/handlers/UserServiceOidcUserHandler.kt deleted file mode 100644 index 44ac922..0000000 --- a/Spring BFF/auth/handlers/UserServiceOidcUserHandler.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.example.authorizationserver.auth.security.handlers - -import com.example.authorizationserver.api.enums.RoleTypes -import com.example.authorizationserver.auth.security.objects.user.CustomOidcUser -import com.example.authorizationserver.auth.security.roles.RoleAuthConfig -import org.springframework.security.core.GrantedAuthority -import org.springframework.security.oauth2.core.oidc.user.OidcUser -import org.springframework.stereotype.Component -import java.util.function.Consumer - -/**********************************************************************************************************************/ -/****************************************************** HANDLER *******************************************************/ -/**********************************************************************************************************************/ - -// more here: -// https://medium.com/@d.snezhinskiy/building-sso-based-on-spring-authorization-server-part-3-of-3-b0b31feb2b6e - -@Component -internal class UserServiceOidcUserHandler() : Consumer { - - override fun accept(user: OidcUser) { - - // capture user in an external data base on first authentication - val oidcUser = user as CustomOidcUser - - // if oicdUser id is null - attempt to add user to database - if (oidcUser.getUserId() == null) { - val grantedAuthorities = oidcUser.authorities as MutableCollection - - // create userEntity from oidcUserDetails object - val userEntity = oidcUser.toInstantUserEntity() - - // assign default role - val defaultRole = RoleTypes.ROLE_USER - userEntity.securityInformation.roles = listOf(defaultRole) - - // save userEntity to database - // userService.save(localUser) - - // get authorities - if (userEntity.securityInformation.roles.isNotEmpty()) { - val authorities = userEntity.securityInformation.let { RoleAuthConfig().getAuthorities(it.roles) } - grantedAuthorities.addAll(authorities) - } - - // assign newly created userEntity id back to oidcUserDetails object - oidcUser.setUserId(userEntity._id.toString()) - } - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/handlers/not_used/AuthorizationEndPointSuccessHandler.kt b/Spring BFF/auth/handlers/not_used/AuthorizationEndPointSuccessHandler.kt deleted file mode 100644 index dbabb24..0000000 --- a/Spring BFF/auth/handlers/not_used/AuthorizationEndPointSuccessHandler.kt +++ /dev/null @@ -1,87 +0,0 @@ -package com.example.authorizationserver.auth.security.handlers.not_used - -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse -import org.springframework.security.core.Authentication -import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames -import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationToken -import org.springframework.security.web.DefaultRedirectStrategy -import org.springframework.security.web.authentication.AuthenticationSuccessHandler -import org.springframework.stereotype.Component -import org.springframework.util.StringUtils -import org.springframework.web.util.UriComponentsBuilder -import java.net.URI -import java.net.URISyntaxException - - -/**********************************************************************************************************************/ -/****************************************************** HANDLER *******************************************************/ -/**********************************************************************************************************************/ - -@Component -internal class AuthorizationEndPointSuccessHandler - : AuthenticationSuccessHandler { - - private val redirectStrategy = DefaultRedirectStrategy() - private val allowedHosts = setOf("www.manning.com", "another-trusted-site.com") - - override fun onAuthenticationSuccess( - request: HttpServletRequest?, - response: HttpServletResponse?, - authentication: Authentication - ) { - val result = authentication as OAuth2AuthorizationCodeRequestAuthenticationToken - val code = result.authorizationCode!!.tokenValue - - val redirectUri = buildSecureRedirectUri(result.redirectUri, code, result.state) - - println(redirectUri) - println("END POINT HANDLING") - - if (redirectUri != null) { - // invalidate the session if required - request?.session?.invalidate() - - // redirect to the secure URI - redirectStrategy.sendRedirect(request, response, redirectUri) - } else { - // Handle invalid redirect URI scenario - response?.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid redirect URI") - } - } - - private fun buildSecureRedirectUri(redirectUri: String?, code: String, state: String?): String? { - if (redirectUri == null || !isValidUri(redirectUri)) { - return null - } - - val builder = UriComponentsBuilder - .fromUriString(redirectUri) - .queryParam(OAuth2ParameterNames.CODE, code) - - if (StringUtils.hasText(state)) { - builder.queryParam(OAuth2ParameterNames.STATE, state) - } - - return builder.build().toUriString() - } - - private fun isValidUri(uri: String): Boolean { - return try { - val parsedUri = URI(uri) - val host = parsedUri.host - val userInfo = parsedUri.userInfo - - // check if the host is in the allowed list and user info is not used - host != null && allowedHosts.contains(host) && userInfo == null && - (parsedUri.scheme == "http" || parsedUri.scheme == "https") - } catch (e: URISyntaxException) { - false - } - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/manager/ServletAuthenticationManager.kt b/Spring BFF/auth/manager/ServletAuthenticationManager.kt deleted file mode 100644 index 375b159..0000000 --- a/Spring BFF/auth/manager/ServletAuthenticationManager.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.example.authorizationserver.auth.security.manager - -import com.example.authorizationserver.auth.security.providers.DocDbAuthenticationProvider -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.security.authentication.AuthenticationManager -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder -import org.springframework.security.config.annotation.web.builders.HttpSecurity - -/**********************************************************************************************************************/ -/********************************************** AUTHENTICATION PROVIDER ***********************************************/ -/**********************************************************************************************************************/ - -@Configuration -internal class ServletAuthenticationManagerConfig { - - @Bean - // authentication manager (adds providers to the manager) - fun servletAuthenticationManager( - http: HttpSecurity, - docDbAuthenticationProvider: DocDbAuthenticationProvider, - ): AuthenticationManager { - val authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder::class.java) - authenticationManagerBuilder.authenticationProvider(docDbAuthenticationProvider) - return authenticationManagerBuilder.build() - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/objects/authentication/DocDbUserAuthentication.kt b/Spring BFF/auth/objects/authentication/DocDbUserAuthentication.kt deleted file mode 100644 index 7635790..0000000 --- a/Spring BFF/auth/objects/authentication/DocDbUserAuthentication.kt +++ /dev/null @@ -1,66 +0,0 @@ -package com.example.authorizationserver.auth.security.objects.authentication - -import com.example.authorizationserver.auth.security.objects.user.DocDbUser -import org.springframework.security.authentication.AbstractAuthenticationToken -import org.springframework.security.core.userdetails.UserDetails - -/**********************************************************************************************************************/ -/*********************************************** AUTHENTICATION OBJECT ************************************************/ -/**********************************************************************************************************************/ - -internal class DocDbUserAuthentication : AbstractAuthenticationToken { - private val docDBUser: DocDbUser? - private val password: String? - - // constructor for User - authenticated - private constructor( - docDBUser: DocDbUser - ) : super(docDBUser.authorities) { - this.docDBUser = docDBUser.copy(password = null) // password is null - this.password = null // password is null - super.eraseCredentials() // erase credentials - super.setAuthenticated(true) - } - - // constructor for User - un-authenticated - private constructor( - docDBUser: DocDbUser, - password: String - ) : super(docDBUser.authorities) { - this.docDBUser = docDBUser - this.password = password - super.setAuthenticated(false) - } - - override fun getCredentials(): String? { - return this.password - } - - override fun getPrincipal(): UserDetails? { - return this.docDBUser - } - - override fun setAuthenticated(authenticated: Boolean) { - throw RuntimeException("THE AUTHENTICATION STATUS CANNOT BE CHANGED") - } - - // factory methods for creating different instances of the Authentication object - companion object { - fun authenticated(docDBUser: DocDbUser): DocDbUserAuthentication { - return DocDbUserAuthentication( - docDBUser, - ) - } - - fun unauthenticated(docDBUser: DocDbUser, password: String): DocDbUserAuthentication { - return DocDbUserAuthentication( - docDBUser, - password - ) - } - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/objects/user/DocDbUser.kt b/Spring BFF/auth/objects/user/DocDbUser.kt deleted file mode 100644 index ff9fcc7..0000000 --- a/Spring BFF/auth/objects/user/DocDbUser.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.example.authorizationserver.auth.security.objects.user - -import org.springframework.security.core.GrantedAuthority -import org.springframework.security.core.userdetails.UserDetails - -/**********************************************************************************************************************/ -/********************************************** USER / PRINCIPAL OBJECT ************************************************/ -/**********************************************************************************************************************/ - -internal data class DocDbUser( - private val userId: String?, - private val username: String, - private val password: String?, - private val authorities: Collection, - private val isAccountNonExpired: Boolean?, - private val isAccountNonLocked: Boolean?, - private val isCredentialsNonExpired: Boolean?, - private val isEnabled: Boolean? -) : UserDetails { - - fun getUserId(): String? { - return userId - } - - override fun getUsername(): String { - return username - } - - override fun getPassword(): String? { - return password - } - - override fun getAuthorities(): Collection { - return authorities - } - - override fun isAccountNonExpired(): Boolean { - return isAccountNonExpired ?: false - } - - override fun isAccountNonLocked(): Boolean { - return isAccountNonLocked ?: false - } - - override fun isCredentialsNonExpired(): Boolean { - return isCredentialsNonExpired ?: false - } - - override fun isEnabled(): Boolean { - return isEnabled ?: false - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/objects/user/OidcUser.kt b/Spring BFF/auth/objects/user/OidcUser.kt deleted file mode 100644 index f41e50a..0000000 --- a/Spring BFF/auth/objects/user/OidcUser.kt +++ /dev/null @@ -1,106 +0,0 @@ -package com.example.authorizationserver.auth.security.objects.user - -import com.example.authorizationserver.api.entities.user.UserEntity -import org.springframework.security.core.GrantedAuthority -import org.springframework.security.core.authority.AuthorityUtils -import org.springframework.security.core.userdetails.UserDetails -import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames -import org.springframework.security.oauth2.core.oidc.OidcIdToken -import org.springframework.security.oauth2.core.oidc.OidcUserInfo -import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser - -/**********************************************************************************************************************/ -/********************************************** USER / PRINCIPAL OBJECT ************************************************/ -/**********************************************************************************************************************/ - -internal open class CustomOidcUser : DefaultOidcUser, UserDetails { - @JvmField - var userId: String? = null - @JvmField - var username: String = "" - private var authorities: Collection = HashSet() - @JvmField - var isAccountNonExpired: Boolean = false - @JvmField - var isAccountNonLocked: Boolean = false - @JvmField - var isCredentialsNonExpired: Boolean = false - @JvmField - var isEnabled: Boolean = false - - /** custom constructors **/ - constructor(authorities: Collection, idToken: OidcIdToken) - : super(authorities.ifEmpty { AuthorityUtils.NO_AUTHORITIES }, idToken, null, IdTokenClaimNames.SUB) - - constructor(authorities: Collection, idToken: OidcIdToken, nameAttributeKey: String) - : super(authorities.ifEmpty { AuthorityUtils.NO_AUTHORITIES }, idToken, null, nameAttributeKey) - - constructor(authorities: Collection, idToken: OidcIdToken, userInfo: OidcUserInfo?) - : this(authorities, idToken, userInfo, IdTokenClaimNames.SUB) - - constructor(authorities: Collection, idToken: OidcIdToken, userInfo: OidcUserInfo?, nameAttributeKey: String) - : super(authorities.ifEmpty { AuthorityUtils.NO_AUTHORITIES }, idToken, userInfo, nameAttributeKey) { - /** keep the authorities mutable **/ - this.authorities = authorities.ifEmpty { AuthorityUtils.NO_AUTHORITIES } - } - - constructor(idToken: OidcIdToken, userInfo: OidcUserInfo?) - : super(AuthorityUtils.NO_AUTHORITIES, idToken, userInfo) - - //* normal functions *// - open fun getUserId(): String? { - return userId - } - - fun setUserId(userId: String?) { - this.userId = userId - } - - //* overridden functions with backing fields *// - override fun getUsername(): String { - return username - } - - override fun getPassword(): String? { - return null - } - - override fun getAuthorities(): Collection { - return authorities - } - - override fun isAccountNonExpired(): Boolean { - return isAccountNonExpired - } - - override fun isAccountNonLocked(): Boolean { - return isAccountNonLocked - } - - - override fun isCredentialsNonExpired(): Boolean { - return isCredentialsNonExpired - } - - override fun isEnabled(): Boolean { - return isEnabled - } - - fun toInstantUserEntity(): UserEntity { - val userEntity = UserEntity() - userEntity.personalInformation.firstName = givenName - userEntity.personalInformation.middleName = middleName - userEntity.personalInformation.lastName = familyName - userEntity.contactInformation.email = email - userEntity.securityInformation.isAccountNonExpired = true - userEntity.securityInformation.isAccountNonLocked = true - userEntity.securityInformation.isCredentialsNonExpired = true - userEntity.securityInformation.isEnabled = true - return userEntity - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/providers/DocDbAuthenticationProvider.kt b/Spring BFF/auth/providers/DocDbAuthenticationProvider.kt deleted file mode 100644 index a60fb52..0000000 --- a/Spring BFF/auth/providers/DocDbAuthenticationProvider.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.example.authorizationserver.auth.security.providers - -import com.example.authorizationserver.auth.security.objects.authentication.DocDbUserAuthentication -import com.example.authorizationserver.auth.security.objects.user.DocDbUser -import com.example.authorizationserver.auth.security.userservice.DocDbUserDetailsManager -import org.springframework.security.authentication.AuthenticationProvider -import org.springframework.security.authentication.BadCredentialsException -import org.springframework.security.core.Authentication -import org.springframework.security.core.userdetails.UsernameNotFoundException -import org.springframework.security.crypto.password.PasswordEncoder -import org.springframework.stereotype.Component -import java.security.GeneralSecurityException - -/**********************************************************************************************************************/ -/********************************************** AUTHENTICATION PROVIDER ***********************************************/ -/**********************************************************************************************************************/ - -@Component -internal class DocDbAuthenticationProvider( - private val docDbUserDetailsManager: DocDbUserDetailsManager, - private val passwordEncoder: PasswordEncoder -) : AuthenticationProvider { - - override fun authenticate(authentication: Authentication): Authentication { - val username = authentication.name - val password = authentication.credentials.toString() - - val user = try { - docDbUserDetailsManager.loadUserByUsername(username) - } catch (ex: UsernameNotFoundException) { - throw UsernameNotFoundException("User not found: $username", ex) - } catch (ex: Exception) { - throw GeneralSecurityException("Unknown error", ex) - } - - // check password validity - if (!passwordEncoder.matches(password, user.password)) { - throw BadCredentialsException("Invalid username or password") - } - - // return authentication object (authenticated) - return DocDbUserAuthentication.authenticated(user as DocDbUser) - - } - - - // this authentication provider works on AuthenticationObjects of type: UserAuthentication - override fun supports(authentication: Class<*>): Boolean { - return DocDbUserAuthentication::class.java.isAssignableFrom(authentication) - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/repositories/ClientRegistrationRepository.kt b/Spring BFF/auth/repositories/ClientRegistrationRepository.kt deleted file mode 100644 index 3813f09..0000000 --- a/Spring BFF/auth/repositories/ClientRegistrationRepository.kt +++ /dev/null @@ -1,86 +0,0 @@ -package com.example.authorizationserver.auth.security.repositories - -import org.springframework.beans.factory.annotation.Value -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.security.config.oauth2.client.CommonOAuth2Provider -import org.springframework.security.oauth2.client.* -import org.springframework.security.oauth2.client.registration.ClientRegistration -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository -import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository -import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager -import org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizedClientRepository -import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository - -/**********************************************************************************************************************/ -/***************************************************** REPOSITORY *****************************************************/ -/**********************************************************************************************************************/ - -@Configuration -internal class ClientRegistrationRepository { - - // google client id - @Value("\${oauth2.client.registration.google.client-id}") - lateinit var googleClientId: String - - // google client secret - @Value("\${oauth2.client.registration.google.client-secret}") - lateinit var googleClientSecret: String - - @Bean - fun servletClientRegistrationRepository(): ClientRegistrationRepository { - return InMemoryClientRegistrationRepository(googleClientRegistration()) - } - - private fun googleClientRegistration(): ClientRegistration { - return CommonOAuth2Provider.GOOGLE.getBuilder("google") - .clientId(googleClientId) - .clientSecret(googleClientSecret) - .build() - } - - @Bean - fun servletAuthorizedClientRepository(): OAuth2AuthorizedClientRepository { - return HttpSessionOAuth2AuthorizedClientRepository() - } - - @Bean - fun servletAuthorizedClientService( - servletClientRegistrationRepository: ClientRegistrationRepository - ): OAuth2AuthorizedClientService { - return InMemoryOAuth2AuthorizedClientService( - servletClientRegistrationRepository - ) - } - - @Bean - fun servletAuthorizedClientManager( - servletClientRegistrationRepository: ClientRegistrationRepository, - servletAuthorizedClientRepository: OAuth2AuthorizedClientRepository - ): OAuth2AuthorizedClientManager { - - // create a builder for the authorized client provider with different grant types - val servletAuthorizedClientProvider: OAuth2AuthorizedClientProvider - = OAuth2AuthorizedClientProviderBuilder.builder() - .authorizationCode() // For the Authorization Code Grant flow - .refreshToken() // For the Refresh Token Grant flow - .clientCredentials() // For the Client Credentials Grant flow - .build() - - // create the DefaultOAuth2AuthorizedClientManager instance - val servletAuthorizedClientManager = DefaultOAuth2AuthorizedClientManager( - servletClientRegistrationRepository, // Repository for client registrations - servletAuthorizedClientRepository // Repository for authorized clients - ) - - // set the authorized client provider to the manager - servletAuthorizedClientManager.setAuthorizedClientProvider(servletAuthorizedClientProvider) - - return servletAuthorizedClientManager - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/repositories/OAuth2ServiceRepository.kt b/Spring BFF/auth/repositories/OAuth2ServiceRepository.kt deleted file mode 100644 index 5c1dce8..0000000 --- a/Spring BFF/auth/repositories/OAuth2ServiceRepository.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.example.authorizationserver.auth.security.repositories - -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationConsentService -import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationService -import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService -import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService - -/**********************************************************************************************************************/ -/***************************************************** REPOSITORY *****************************************************/ -/**********************************************************************************************************************/ - -@Configuration -internal class OAuth2ServiceConfig() { - - @Bean - // where new authorizations / tokens are stored and existing authorizations are queried - fun authorizationService(): OAuth2AuthorizationService { - return InMemoryOAuth2AuthorizationService() - } - - @Bean - // where new authorization consents are stored and existing authorization consents are queried - fun authorizationServiceConsent(): OAuth2AuthorizationConsentService { - return InMemoryOAuth2AuthorizationConsentService() - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/repositories/RegisteredClientRepository.kt b/Spring BFF/auth/repositories/RegisteredClientRepository.kt deleted file mode 100644 index 32625c5..0000000 --- a/Spring BFF/auth/repositories/RegisteredClientRepository.kt +++ /dev/null @@ -1,84 +0,0 @@ -package com.example.authorizationserver.auth.security.repositories - -import org.springframework.beans.factory.annotation.Value -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.security.crypto.password.PasswordEncoder -import org.springframework.security.oauth2.core.AuthorizationGrantType -import org.springframework.security.oauth2.core.ClientAuthenticationMethod -import org.springframework.security.oauth2.core.oidc.OidcScopes -import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository -import org.springframework.security.oauth2.server.authorization.client.RegisteredClient -import org.springframework.security.oauth2.server.authorization.settings.ClientSettings -import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat -import org.springframework.security.oauth2.server.authorization.settings.TokenSettings -import java.time.Duration -import java.util.* - -/**********************************************************************************************************************/ -/***************************************************** REPOSITORY *****************************************************/ -/**********************************************************************************************************************/ - -@Configuration -internal class RegisteredClientConfig() { - - @Value("\${oauth2.client.registration.api-gateway.client-id}") - private lateinit var gatewayClientId: String - - @Value("\${oauth2.client.registration.api-gateway.client-secret}") - private lateinit var gatewayClientSecret: String - - @Value("\${in-house-auth-registration-id}") - private lateinit var inHouseAuthRegistrationId: String - - @Value("\${reverse-proxy-uri}") - private lateinit var reverseProxyUri: String - - @Value("\${bff-prefix}") - private lateinit var bffPrefix: String - - @Bean - /* registeredClientRepository (defines: authorization grants, OIDC scopes, etc.) */ - fun registeredClientRepository(passwordEncoder: PasswordEncoder): InMemoryRegisteredClientRepository { - - // api-gateway client (gateway client!) - val apiGatewayClient = RegisteredClient - .withId(UUID.randomUUID().toString()) - .clientId(gatewayClientId) - .clientSecret(gatewayClientSecret) - .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC) - .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) - .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN) - .redirectUri("$reverseProxyUri$bffPrefix/login/oauth2/code/$inHouseAuthRegistrationId") - .postLogoutRedirectUri("https://www.manning.com/authorized") - .tokenSettings( - TokenSettings.builder() - .accessTokenFormat(OAuth2TokenFormat.SELF_CONTAINED) - .accessTokenTimeToLive(Duration.ofMinutes(5)) - .refreshTokenTimeToLive(Duration.ofMinutes(30)) - .authorizationCodeTimeToLive(Duration.ofMinutes(1)) - .reuseRefreshTokens(false) - .build()) - .scope(OidcScopes.OPENID) // requests an ID token, which is necessary for any OpenID Connect request. - .scope(OidcScopes.PROFILE) // requests access to the user's profile information (e.g., name, date of birth) - .clientSettings(ClientSettings - .builder().requireAuthorizationConsent(true) - .requireProofKey(true) - .build()) - .build() - - // back-end client (resource server!) - val resourceServer = RegisteredClient.withId(UUID.randomUUID().toString()) - .clientId("resource_server") - .clientSecret(passwordEncoder.encode("resource_server_secret")) - .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC) - .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS) - .build() - - return InMemoryRegisteredClientRepository(apiGatewayClient, resourceServer) - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/repositories/SecurityContextRepository.kt b/Spring BFF/auth/repositories/SecurityContextRepository.kt deleted file mode 100644 index 72a1f28..0000000 --- a/Spring BFF/auth/repositories/SecurityContextRepository.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.example.authorizationserver.auth.security.repositories - -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.security.web.context.HttpSessionSecurityContextRepository -import org.springframework.security.web.context.SecurityContextRepository - -/**********************************************************************************************************************/ -/***************************************************** REPOSITORY *****************************************************/ -/**********************************************************************************************************************/ - -@Configuration -internal class SecurityContextConfig() { - - @Bean - fun customSecurityContextRepository(): SecurityContextRepository { - return HttpSessionSecurityContextRepository() - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/repositories/SessionRegistryConfig.kt b/Spring BFF/auth/repositories/SessionRegistryConfig.kt deleted file mode 100644 index 0af262b..0000000 --- a/Spring BFF/auth/repositories/SessionRegistryConfig.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.example.authorizationserver.auth.security.repositories - -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.security.core.session.SessionRegistry -import org.springframework.security.core.session.SessionRegistryImpl -import org.springframework.security.web.session.HttpSessionEventPublisher - -/**********************************************************************************************************************/ -/***************************************************** REPOSITORY *****************************************************/ -/**********************************************************************************************************************/ - -@Configuration -internal class SessionRegistryConfig { - - @Bean - // for tracking and managing active sessions, needed for the various session strategies - fun sessionRegistry(): SessionRegistry { - return SessionRegistryImpl() - } - - @Bean - // for publishing session lifecycle events, to enable application to respond to session creation & destruction - fun httpSessionEventPublisher(): HttpSessionEventPublisher { - return HttpSessionEventPublisher() - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/requestcache/CustomRequestCache.kt b/Spring BFF/auth/requestcache/CustomRequestCache.kt deleted file mode 100644 index 2719245..0000000 --- a/Spring BFF/auth/requestcache/CustomRequestCache.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.example.authorizationserver.auth.security.requestcache - -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse -import org.springframework.security.web.PortResolver -import org.springframework.security.web.PortResolverImpl -import org.springframework.security.web.savedrequest.DefaultSavedRequest -import org.springframework.security.web.savedrequest.HttpSessionRequestCache -import org.springframework.security.web.savedrequest.SavedRequest -import org.springframework.security.web.util.UrlUtils -import org.springframework.stereotype.Component -import org.springframework.util.StringUtils - -/**********************************************************************************************************************/ -/******************************************************* REQUEST CACHE ************************************************/ -/**********************************************************************************************************************/ - -@Component -internal class CustomRequestCache : HttpSessionRequestCache() { - - init { - // allows selective use of save request so that only those with 'redirect_uri' parameter are cached - this.setRequestMatcher { request -> - StringUtils.hasText(request.getParameter("redirect_uri")) - } - } - - override fun saveRequest(request: HttpServletRequest, response: HttpServletResponse) { - println("Saving request to ${request.requestURI}") - super.saveRequest(request, response) - } - - override fun getMatchingRequest(request: HttpServletRequest, response: HttpServletResponse): HttpServletRequest? { - println("Getting matching request for ${request.requestURI}") - return super.getMatchingRequest(request, response) - } - - override fun removeRequest(request: HttpServletRequest, response: HttpServletResponse) { - println("Removing request for ${request.requestURI}") - super.removeRequest(request, response) - } - - override fun getRequest(request: HttpServletRequest, response: HttpServletResponse): SavedRequest? { - println("Getting request for ${request.requestURI}") - return super.getRequest(request, response) - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/sessions/CustomInvalidSessionStrategy.kt b/Spring BFF/auth/sessions/CustomInvalidSessionStrategy.kt deleted file mode 100644 index 3e6ec5d..0000000 --- a/Spring BFF/auth/sessions/CustomInvalidSessionStrategy.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.example.authorizationserver.auth.security.sessions - -import jakarta.servlet.http.Cookie -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse -import org.springframework.security.core.context.SecurityContextHolder -import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler -import org.springframework.security.web.session.InvalidSessionStrategy -import org.springframework.stereotype.Component - -/**********************************************************************************************************************/ -/****************************************************** SESSION STRATEGY **********************************************/ -/**********************************************************************************************************************/ - -@Component -internal class CustomInvalidSessionStrategy : InvalidSessionStrategy { - - override fun onInvalidSessionDetected(request: HttpServletRequest, response: HttpServletResponse) { - // handle session expiry - handleSessionExpiry(request, response) - } - - private fun handleSessionExpiry(request: HttpServletRequest, response: HttpServletResponse) { - - // delete cookies - val cookies = request.cookies - if (cookies != null) { - for (cookie in cookies) { - if (cookie.name == "AUTH-SESSIONID") { - val deleteCookie = Cookie(cookie.name, null) - deleteCookie.path = "/" - deleteCookie.maxAge = 0 - response.addCookie(deleteCookie) - } - } - } - - // clear authentication object - val auth = SecurityContextHolder.getContext().authentication - if (auth != null) { - SecurityContextLogoutHandler().logout(request, response, auth) - } - - // redirect to session expired URL - response.sendRedirect("/session-expired") - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/sessions/CustomSessionAuthenticationStrategy.kt b/Spring BFF/auth/sessions/CustomSessionAuthenticationStrategy.kt deleted file mode 100644 index a5b3f65..0000000 --- a/Spring BFF/auth/sessions/CustomSessionAuthenticationStrategy.kt +++ /dev/null @@ -1,89 +0,0 @@ -package com.example.authorizationserver.auth.security.sessions - -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse -import org.apache.commons.logging.Log -import org.apache.commons.logging.LogFactory -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.security.core.Authentication -import org.springframework.security.core.session.SessionRegistry -import org.springframework.security.web.authentication.session.* -import org.springframework.util.Assert - -/**********************************************************************************************************************/ -/****************************************************** SESSION STRATEGY **********************************************/ -/**********************************************************************************************************************/ - -@Configuration -internal class CustomSessionAuthenticationStrategy( - private val sessionRegistry: SessionRegistry -) : SessionAuthenticationStrategy { - - private val logger: Log = LogFactory.getLog(javaClass) - - private val delegateStrategies: List by lazy { - val strategies = listOf( - concurrentSessionControlAuthenticationStrategy(), - sessionFixationProtectionStrategy(), - registerSessionAuthenticationStrategy(), - changeSessionIdAuthenticationStrategy() - ) - Assert.notEmpty(strategies, "delegateStrategies cannot be null or empty") - for (strategy in strategies) { - Assert.notNull(strategy) { "delegateStrategies cannot contain null entries. Got $strategies" } - } - strategies - } - - @Bean - fun concurrentSessionControlAuthenticationStrategy(): ConcurrentSessionControlAuthenticationStrategy { - val strategy = ConcurrentSessionControlAuthenticationStrategy(sessionRegistry) - strategy.setMaximumSessions(1) // set maximum sessions per user - strategy.setExceptionIfMaximumExceeded(true) // prevents login if maximum sessions are exceeded - return strategy - } - - @Bean - fun sessionFixationProtectionStrategy(): SessionFixationProtectionStrategy { - val strategy = SessionFixationProtectionStrategy() - strategy.setMigrateSessionAttributes(true) // migrates session attributes - strategy.setAlwaysCreateSession(true) // always create a new session - return strategy - } - - @Bean - fun registerSessionAuthenticationStrategy(): RegisterSessionAuthenticationStrategy { - val strategy = RegisterSessionAuthenticationStrategy(sessionRegistry) - return strategy - } - - @Bean - fun changeSessionIdAuthenticationStrategy(): ChangeSessionIdAuthenticationStrategy { - val strategy = ChangeSessionIdAuthenticationStrategy() - strategy.setAlwaysCreateSession(true) - return strategy - } - - @Bean - fun compositeSessionAuthenticationStrategy(): CompositeSessionAuthenticationStrategy { - return CompositeSessionAuthenticationStrategy(delegateStrategies) - } - - override fun onAuthentication(authentication: Authentication?, request: HttpServletRequest?, response: HttpServletResponse?) { - var currentPosition = 0 - val size: Int = this.delegateStrategies.size - for (delegate in this.delegateStrategies) { - if (this.logger.isTraceEnabled) { - this.logger.trace( - "Preparing session with ${delegate.javaClass.simpleName} (${++currentPosition}/$size)" - ) - } - delegate.onAuthentication(authentication, request, response) - } - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/tokens/OAuth2TokenCustomiserJwtEncoding.kt b/Spring BFF/auth/tokens/OAuth2TokenCustomiserJwtEncoding.kt deleted file mode 100644 index c53d25f..0000000 --- a/Spring BFF/auth/tokens/OAuth2TokenCustomiserJwtEncoding.kt +++ /dev/null @@ -1,107 +0,0 @@ -package com.example.authorizationserver.auth.security.tokens - -import com.example.authorizationserver.auth.security.tokens.TokenCustomiserConfig.ClaimsBuilder -import com.nimbusds.jose.jwk.JWKSet -import com.nimbusds.jose.jwk.RSAKey -import com.nimbusds.jose.jwk.source.ImmutableJWKSet -import com.nimbusds.jose.jwk.source.JWKSource -import com.nimbusds.jose.proc.SecurityContext -import org.slf4j.LoggerFactory -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.security.oauth2.jwt.JwtClaimsSet -import org.springframework.security.oauth2.jwt.JwtDecoder -import org.springframework.security.oauth2.server.authorization.OAuth2TokenType -import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration -import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext -import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer -import java.security.KeyPair -import java.security.KeyPairGenerator -import java.security.NoSuchAlgorithmException -import java.security.interfaces.RSAPrivateKey -import java.security.interfaces.RSAPublicKey -import java.util.* - -/**********************************************************************************************************************/ -/******************************************************* CONFIGURATION ************************************************/ -/**********************************************************************************************************************/ - -@Configuration -internal class OAuth2TokenCustomiserJwtEncoding( - private val tokenCustomiserConfig: TokenCustomiserConfig -) { - - @Bean - internal fun jwtTokenCustomizer(): OAuth2TokenCustomizer { - return OAuth2TokenCustomizer { context -> - if (OAuth2TokenType.ACCESS_TOKEN.equals(context.tokenType)) { - val userDetails = tokenCustomiserConfig.getUserDetails(context) - tokenCustomiserConfig.addClaims(context.claims.toClaimsBuilder(), userDetails) - - // Print all claims - printAllClaims(context.claims) - } - } - } - - - private val logger = LoggerFactory.getLogger(TokenCustomiserConfig::class.java) - - // Print all claims method - private fun printAllClaims(claims: JwtClaimsSet.Builder) { - // You will need to call build() to get the final claims set - val claimsSet = claims.build() - claimsSet.claims.forEach { (key, value) -> - logger.info("Claim Key: $key, Claim Value: $value") - println("Claim Key: $key, Claim Value: $value") - } - } - - - // jwtClaimsSet.Builder extension - internal fun JwtClaimsSet.Builder.toClaimsBuilder(): ClaimsBuilder { - return object : ClaimsBuilder { - override fun claim(name: String, value: Any?) { - this@toClaimsBuilder.claim(name, value) - } - } - } - - - @Bean - // for signing JWT access tokens (from Nimbus) - internal fun jwkSource(): JWKSource { - val keyPair = generateRsaKey() - val publicKey = keyPair.public as RSAPublicKey - val privateKey = keyPair.private as RSAPrivateKey - val rsaKey = RSAKey.Builder(publicKey) - .privateKey(privateKey) - .keyID(UUID.randomUUID().toString()) - .build() - val jwkSet = JWKSet(rsaKey) - return ImmutableJWKSet(jwkSet) - } - - // for generating the RSA key, for JWT tokens (asymmetric encryption: private + public key) - private fun generateRsaKey(): KeyPair { - val keyPair: KeyPair - try { - val keyPairGenerator = KeyPairGenerator.getInstance("RSA") - keyPairGenerator.initialize(2048) - keyPair = keyPairGenerator.generateKeyPair() - } catch (ex: NoSuchAlgorithmException) { - throw IllegalStateException("RSA KeyPairGenerator not available", ex) - } - return keyPair - } - - @Bean - // for decoding signed access tokens - internal fun jwtDecoder(jwkSource: JWKSource): JwtDecoder { - return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource) - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ diff --git a/Spring BFF/auth/tokens/OAuth2TokenCustomiserOAuth2Claims.kt b/Spring BFF/auth/tokens/OAuth2TokenCustomiserOAuth2Claims.kt deleted file mode 100644 index 17080bc..0000000 --- a/Spring BFF/auth/tokens/OAuth2TokenCustomiserOAuth2Claims.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.example.authorizationserver.auth.security.tokens - -import com.example.authorizationserver.auth.security.tokens.TokenCustomiserConfig.ClaimsBuilder -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.security.oauth2.server.authorization.OAuth2TokenType -import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimsContext -import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimsSet -import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer - -/**********************************************************************************************************************/ -/******************************************************* CONFIGURATION ************************************************/ -/**********************************************************************************************************************/ - -@Configuration -internal class OpaqueTokenCustomizerConfig( - private val tokenCustomiserConfig: TokenCustomiserConfig -) { - - @Bean - internal fun opaqueTokenCustomizer(): OAuth2TokenCustomizer { - return OAuth2TokenCustomizer { context -> - if (OAuth2TokenType.ACCESS_TOKEN.equals(context.tokenType)) { - val userDetails = tokenCustomiserConfig.getUserDetails(context) - tokenCustomiserConfig.addClaims(context.claims.toClaimsBuilder(), userDetails) - } - } - } - - // OAuth2TokenClaimsSet.Builder extension - internal fun OAuth2TokenClaimsSet.Builder.toClaimsBuilder(): ClaimsBuilder { - return object : ClaimsBuilder { - override fun claim(name: String, value: Any?) { - this@toClaimsBuilder.claim(name, value) - } - } - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/tokens/TokenCustomiserConfig.kt b/Spring BFF/auth/tokens/TokenCustomiserConfig.kt deleted file mode 100644 index 1509cff..0000000 --- a/Spring BFF/auth/tokens/TokenCustomiserConfig.kt +++ /dev/null @@ -1,85 +0,0 @@ -package com.example.authorizationserver.auth.security.tokens - -import com.example.authorizationserver.auth.security.objects.user.CustomOidcUser -import com.example.authorizationserver.auth.security.objects.user.DocDbUser -import com.nimbusds.jose.jwk.source.JWKSource -import com.nimbusds.jose.proc.SecurityContext -import org.slf4j.LoggerFactory -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.security.core.Authentication -import org.springframework.security.core.userdetails.UserDetails -import org.springframework.security.oauth2.core.OAuth2Token -import org.springframework.security.oauth2.jwt.NimbusJwtEncoder -import org.springframework.security.oauth2.server.authorization.token.* - -/**********************************************************************************************************************/ -/******************************************************* CONFIGURATION ************************************************/ -/**********************************************************************************************************************/ - -@Configuration -internal class TokenCustomiserConfig { - - interface ClaimsBuilder { - fun claim(name: String, value: Any?) - } - - @Bean - // used for generating either opaque or jwt tokens - internal fun tokenGenerator( - jwkSource: JWKSource, - jwtTokenCustomizer: OAuth2TokenCustomizer, - opaqueTokenCustomizer: OAuth2TokenCustomizer - ): OAuth2TokenGenerator { - val jwtEncoder = NimbusJwtEncoder(jwkSource) - val jwtGenerator = JwtGenerator(jwtEncoder) - jwtGenerator.setJwtCustomizer(jwtTokenCustomizer) - - val accessTokenGenerator = OAuth2AccessTokenGenerator() - accessTokenGenerator.setAccessTokenCustomizer(opaqueTokenCustomizer) - - val refreshTokenGenerator = OAuth2RefreshTokenGenerator() - return DelegatingOAuth2TokenGenerator(jwtGenerator, accessTokenGenerator, refreshTokenGenerator) - } - - // utility method (generic type) for getting user details / principal object - internal fun getUserDetails(context: T): UserDetails where T : OAuth2TokenContext { - return when (val principal = context.getPrincipal().principal) { - is CustomOidcUser -> principal - is DocDbUser -> principal - is UserDetails -> principal - else -> throw IllegalStateException("Unsupported principal type: ${principal::class}") - } - } - - // utility method for adding custom claims - internal fun addClaims(claimsBuilder: ClaimsBuilder, userDetails: UserDetails) { - if (userDetails.username.isNotEmpty()) { - claimsBuilder.apply { - claim("userId", extractUserId(userDetails)) - claim("username", userDetails.username) - claim("authorities", userDetails.authorities.map { it.authority }.toSet()) - claim("isAccountNonExpired", userDetails.isAccountNonExpired) - claim("isAccountNonLocked", userDetails.isAccountNonLocked) - claim("isCredentialsNonExpired", userDetails.isCredentialsNonExpired) - claim("isEnabled", userDetails.isEnabled) - - } - } else { - throw IllegalStateException("Bad UserDetails, username is empty") - } - } - - // utility method for getting user id (since getter does not exist on type UserDetails) - private fun extractUserId(userDetails: UserDetails): String? { - return when (userDetails) { - is CustomOidcUser -> userDetails.getUserId() - is DocDbUser -> userDetails.getUserId() - else -> throw IllegalStateException("Unsupported UserDetails type: ${userDetails::class}") - } - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/userservice/DocDbUserDetailsManager.kt b/Spring BFF/auth/userservice/DocDbUserDetailsManager.kt deleted file mode 100644 index 6aa872c..0000000 --- a/Spring BFF/auth/userservice/DocDbUserDetailsManager.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.example.authorizationserver.auth.security.userservice - -import org.springframework.security.core.userdetails.UserDetailsService - -/**********************************************************************************************************************/ -/************************************************* SERVICE INTERFACE **************************************************/ -/**********************************************************************************************************************/ - -internal interface DocDbUserDetailsManager : UserDetailsService { - - // fun createUser(user: UserDetails): Mono - // fun updateUser(user: UserDetails): Mono - // fun deleteUser(username: String): Mono - // fun changePassword(oldPassword: String, newPassword: String): Mono - // fun userExists(username: String): Mono - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/userservice/DocDbUserDetailsManagerImpl.kt b/Spring BFF/auth/userservice/DocDbUserDetailsManagerImpl.kt deleted file mode 100644 index 79aaf29..0000000 --- a/Spring BFF/auth/userservice/DocDbUserDetailsManagerImpl.kt +++ /dev/null @@ -1,119 +0,0 @@ -package com.example.authorizationserver.auth.security.userservice - -import com.example.authorizationserver.api.entities.user.UserEntity -import com.example.authorizationserver.auth.security.objects.user.DocDbUser -import com.example.authorizationserver.auth.security.roles.RoleAuthConfig -import com.example.authorizationserver.auth.security.virtualthreads.VirtualThreadManager -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.security.core.userdetails.UsernameNotFoundException -import org.springframework.security.crypto.password.PasswordEncoder -import org.springframework.stereotype.Service - -/**********************************************************************************************************************/ -/********************************************** SERVICE IMPLEMENTATION ************************************************/ -/**********************************************************************************************************************/ - -/**********************************************************************************************************************/ -/* USER DETAILS - MANAGER (extends USER SERVICE) */ -/**********************************************************************************************************************/ - - @Service - internal class DocDbUserDetailsManagerImpl( - @Autowired - private val passwordEncoder: PasswordEncoder, - private val virtualThreadManager: VirtualThreadManager, - ) : DocDbUserDetailsManager { - - // find username in database, and get other security details, from User's Profile - override fun loadUserByUsername(userEmail: String): DocDbUser { - val userEntity = virtualThreadManager.fetchUserEntity(userEmail) - if (userEntity == null) { - throw UsernameNotFoundException("User not found: $userEmail") - } else { - return createDocDBUserDetails(userEntity) - } - } - - // create DocDBUserDetails object - private fun createDocDBUserDetails(userEntity: UserEntity): DocDbUser { - - // get authorities - val authorities = RoleAuthConfig().getAuthorities(userEntity.securityInformation.roles) - - // return DocDBuserDetails object - return DocDbUser( - userEntity._id.toString(), - userEntity.contactInformation.email, - passwordEncoder.encode(userEntity.securityInformation.password), - authorities, - userEntity.securityInformation.isAccountNonExpired, - userEntity.securityInformation.isAccountNonLocked, - userEntity.securityInformation.isCredentialsNonExpired, - userEntity.securityInformation.isEnabled, - ) - } - -// override fun createUser(user: UserDetails): Mono { -// return mono { -// val encodedUser = User.builder() -// .username(user.username) -// .password(passwordEncoder.encode(user.password)) -// .authorities(user.authorities) -// .build() -// userRepo.save(encodedUser) -// }.then() -// } -// -// override fun updateUser(user: UserDetails): Mono { -// return mono { -// val existingUser = userRepo.getUserByEmail(user.username) -// existingUser?.let { -// val updatedUser = it.copy( -// securityInformation = it.securityInformation.copy( -// password = passwordEncoder.encode(user.password) -// ), -// contactInformation = it.contactInformation.copy( -// email = user.username -// ), -// roles = user.authorities.map { it.authority } -// ) -// userRepo.save(updatedUser) -// } ?: throw UsernameNotFoundException("User not found: ${user.username}") -// }.then() -// } -// -// override fun deleteUser(username: String): Mono { -// return mono { -// userRepo.deleteByUsername(username) -// }.then() -// } -// -// override fun changePassword(oldPassword: String, newPassword: String): Mono { -// return mono { -// val username = // Retrieve current username from security context -// val user = userRepo.getUserByEmail(username) -// user?.let { -// if (passwordEncoder.matches(oldPassword, it.securityInformation.password)) { -// val updatedUser = it.copy( -// securityInformation = it.securityInformation.copy( -// password = passwordEncoder.encode(newPassword) -// ) -// ) -// userRepo.save(updatedUser) -// } else { -// throw BadCredentialsException("Invalid old password") -// } -// } ?: throw UsernameNotFoundException("User not found: $username") -// }.then() -// } -// -// override fun userExists(username: String): Mono { -// return mono { -// userRepo.getUserByEmail(username) != null -// } -// } - } - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/userservice/OidcUserDetailsService.kt b/Spring BFF/auth/userservice/OidcUserDetailsService.kt deleted file mode 100644 index e806ba3..0000000 --- a/Spring BFF/auth/userservice/OidcUserDetailsService.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.example.authorizationserver.auth.security.userservice - -import com.example.authorizationserver.api.entities.user.UserEntity -import com.example.authorizationserver.auth.security.userservice.oidcmappers.OidcUserMapper -import com.example.authorizationserver.auth.security.virtualthreads.VirtualThreadManager -import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest -import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService -import org.springframework.security.oauth2.core.oidc.user.OidcUser -import org.springframework.stereotype.Service - -/**********************************************************************************************************************/ -/********************************************** SERVICE IMPLEMENTATION ************************************************/ -/**********************************************************************************************************************/ - -// more here: -// https://medium.com/@d.snezhinskiy/building-sso-based-on-spring-authorization-server-part-3-of-3-b0b31feb2b6e - - -/**********************************************************************************************************************/ -/* O.I.D.C. USER DETAILS - SERVICE */ -/**********************************************************************************************************************/ - -@Service -internal class CustomOidcUserDetailsService( - private val mappers: Map, - private val virtualThreadManager: VirtualThreadManager, -) : OidcUserService() { - - override fun loadUser(userRequest: OidcUserRequest): OidcUser { - - // get oidc request - val oidcUserRequest: OidcUser = super.loadUser(userRequest) as OidcUser - - // get registration id from oidc request - val registrationId: String = userRequest.clientRegistration.registrationId - - // check mapper exists, otherwise throw error - require(mappers.containsKey(registrationId)) { "No mapper defined for such registrationId" } - - // get appropriate mapper - val mapper: OidcUserMapper = mappers.getValue(registrationId) - - // get userEntity (optional) by email - val email: String = userRequest.idToken.email - val userEntity: UserEntity? = virtualThreadManager.fetchUserEntity(email) - - // return appropriate OidcUserDetails object - return userEntity?.let { - mapper.map(oidcUserRequest.idToken, oidcUserRequest.userInfo, userEntity) - } ?: mapper.map(oidcUserRequest) - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/userservice/oidcmappers/GoogleOidcUserMapper.kt b/Spring BFF/auth/userservice/oidcmappers/GoogleOidcUserMapper.kt deleted file mode 100644 index 4715491..0000000 --- a/Spring BFF/auth/userservice/oidcmappers/GoogleOidcUserMapper.kt +++ /dev/null @@ -1,73 +0,0 @@ -package com.example.authorizationserver.auth.security.userservice.oidcmappers - -import com.example.authorizationserver.api.entities.user.UserEntity -import com.example.authorizationserver.auth.security.objects.user.CustomOidcUser -import com.example.authorizationserver.auth.security.roles.RoleAuthConfig -import org.springframework.security.oauth2.core.oidc.OidcIdToken -import org.springframework.security.oauth2.core.oidc.OidcUserInfo -import org.springframework.security.oauth2.core.oidc.StandardClaimNames -import org.springframework.security.oauth2.core.oidc.user.OidcUser -import org.springframework.stereotype.Component - -/**********************************************************************************************************************/ -/*************************************************** USER MAPPER ******************************************************/ -/**********************************************************************************************************************/ - -// more here: -// https://medium.com/@d.snezhinskiy/building-sso-based-on-spring-authorization-server-part-3-of-3-b0b31feb2b6e - - -@Component("google") -internal class GoogleOidcUserMapper : OidcUserMapper { - - // if userEntity does not already exist - override fun map(oidcUserRequest: OidcUser): CustomOidcUser { - val oidcUser = CustomOidcUser(oidcUserRequest.authorities, oidcUserRequest.idToken, oidcUserRequest.userInfo) - oidcUser.setUserId(null) - oidcUser.username = oidcUser.email - oidcUser.isAccountNonExpired = true - oidcUser.isAccountNonLocked = true - oidcUser.isCredentialsNonExpired = true - oidcUser.isEnabled = true - return oidcUser - } - - // if userEntity already exists - override fun map(idToken: OidcIdToken, userInfo: OidcUserInfo?, userEntity: UserEntity?): CustomOidcUser { - - // get authorities - val authorities = userEntity?.securityInformation?.let { RoleAuthConfig().getAuthorities(it.roles) } ?: HashSet() - - // create custom claims - val claims = mutableMapOf() - - // these get added as attributes to the OAuth2AuthenticationToken - claims.putAll(idToken.claims) - if (userEntity != null) { - claims[StandardClaimNames.GIVEN_NAME] = userEntity.personalInformation.firstName - claims[StandardClaimNames.MIDDLE_NAME] = userEntity.personalInformation.middleName ?: "" - claims[StandardClaimNames.FAMILY_NAME] = userEntity.personalInformation.lastName - } - - // create token - val customIdToken = OidcIdToken( - idToken.tokenValue, idToken.issuedAt, idToken.expiresAt, claims - ) - - // create oidcUserDetails object - val oidcUser = CustomOidcUser(authorities, customIdToken, userInfo) - oidcUser.setUserId( userEntity?._id.toString()) - oidcUser.username = userEntity?.contactInformation?.email ?: "" - oidcUser.isAccountNonExpired = userEntity?.securityInformation?.isAccountNonExpired == true - oidcUser.isAccountNonLocked = userEntity?.securityInformation?.isAccountNonLocked == true - oidcUser.isCredentialsNonExpired = userEntity?.securityInformation?.isCredentialsNonExpired == true - oidcUser.isEnabled = userEntity?.securityInformation?.isEnabled == true - - // return oidcUserDetails object - return oidcUser - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/userservice/oidcmappers/OidcMapper.kt b/Spring BFF/auth/userservice/oidcmappers/OidcMapper.kt deleted file mode 100644 index eecd0e9..0000000 --- a/Spring BFF/auth/userservice/oidcmappers/OidcMapper.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.example.authorizationserver.auth.security.userservice.oidcmappers - -import com.example.authorizationserver.api.entities.user.UserEntity -import com.example.authorizationserver.auth.security.objects.user.CustomOidcUser -import org.springframework.security.oauth2.core.oidc.OidcIdToken -import org.springframework.security.oauth2.core.oidc.OidcUserInfo -import org.springframework.security.oauth2.core.oidc.user.OidcUser - -/**********************************************************************************************************************/ -/************************************************** MAPPER INTERFACE **************************************************/ -/**********************************************************************************************************************/ - -internal interface OidcUserMapper { - - fun map(oidcUserRequest: OidcUser): CustomOidcUser - fun map(idToken: OidcIdToken, userInfo: OidcUserInfo?, userEntity: UserEntity?): CustomOidcUser - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/virtualthreads/VirtualThreadsManager.kt b/Spring BFF/auth/virtualthreads/VirtualThreadsManager.kt deleted file mode 100644 index c5f4c99..0000000 --- a/Spring BFF/auth/virtualthreads/VirtualThreadsManager.kt +++ /dev/null @@ -1,66 +0,0 @@ -package com.example.authorizationserver.auth.security.virtualthreads - -import com.example.authorizationserver.api.entities.user.UserEntity -import com.example.authorizationserver.api.repositories.users.UserRepositoryImpl -import kotlinx.coroutines.asCoroutineDispatcher -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.withContext -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.stereotype.Service -import java.util.concurrent.Executors -import java.util.concurrent.RejectedExecutionException -import javax.annotation.PreDestroy -import kotlin.coroutines.CoroutineContext - -// using Java Virtual Threads (Project Loom), since Spring does not yet support reactive Auth Servers -// https://github.com/spring-projects/spring-authorization-server/issues/152 -// https://kt.academy/article/dispatcher-loom - -@Configuration -class ExecutorConfig { - - private val executor = Executors.newVirtualThreadPerTaskExecutor() - - @Bean - fun coroutineDispatcher(): CoroutineContext = executor.asCoroutineDispatcher() - - @PreDestroy - fun cleanUp() { - executor.close() - } -} - -@Service -internal class VirtualThreadManager( - @Autowired - private val userRepo: UserRepositoryImpl, - private val dispatcher: CoroutineContext -) { - - internal fun fetchUserEntity(userEmail: String): UserEntity? { - - return try { - // run the coroutine blocking the current thread until it completes - runBlocking { - // switch to the custom dispatcher created from the executor - withContext(dispatcher) { - getUserEntity(userEmail) - } - } - } catch (ex: RejectedExecutionException) { - throw RuntimeException("Executor was shut down, unable to execute task", ex) - } - } - - // get userEntity from DocDatabase - private suspend fun getUserEntity(userEmail: String): UserEntity? { - val userEntity = userRepo.getUserByEmail(userEmail) - return userEntity - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file