From 0b12ab08f195d1c19c31b17805c74be4e92dfa5a Mon Sep 17 00:00:00 2001 From: Dreamstar Enterprises <39380005+dreamstar-enterprises@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:24:14 +0100 Subject: [PATCH] Delete Spring BFF/auth directory --- Spring BFF/auth/AuthServerConfig.kt | 71 ------- Spring BFF/auth/DefaultSecurityConfig.kt | 164 ---------------- Spring BFF/auth/TomCatServerConfig.kt | 36 ---- Spring BFF/auth/application.yaml | 111 ----------- .../auth/converters/BasicJSONConverter.kt | 42 ---- Spring BFF/auth/cookies/CookiesConfig.kt | 48 ----- .../auth/encoders/PasswordEncoderConfig.kt | 52 ----- .../auth/filters/DocDbAuthenticationFilter.kt | 133 ------------- .../auth/handlers/AccessDeniedHandler.kt | 45 ----- ...equestAwareAuthenticationSuccessHandler.kt | 96 ---------- ...omSimpleUrlAuthenticationFailureHandler.kt | 90 --------- .../handlers/SocialLoginSuccessHandler.kt | 80 -------- .../handlers/UserServiceOidcUserHandler.kt | 54 ------ .../manager/ServletAuthenticationManager.kt | 32 ---- .../authentication/DocDbUserAuthentication.kt | 62 ------ Spring BFF/auth/objects/user/DocDbUser.kt | 56 ------ Spring BFF/auth/objects/user/OidcUser.kt | 106 ---------- .../providers/DocDbAuthenticationProvider.kt | 56 ------ .../redis/RedisConnectionFactoryConfig.kt | 101 ---------- Spring BFF/auth/redis/RedisSerialiser.kt | 181 ------------------ Spring BFF/auth/redis/RedisTemplateConfig.kt | 70 ------- .../ClientRegistrationRepository.kt | 86 --------- .../auth/repositories/CsrfTokenRespository.kt | 61 ------ .../repositories/OAuth2ServiceRepository.kt | 33 ---- .../RedisIndexedSessionRepositoryConfig.kt | 97 ---------- .../RedisRememberMeTokenRepository.kt | 107 ----------- .../RegisteredClientRepository.kt | 84 -------- .../repositories/SecurityContextRepository.kt | 24 --- .../repositories/SessionRegistryConfig.kt | 31 --- .../auth/requestcache/CustomRequestCache.kt | 52 ----- Spring BFF/auth/roles/RoleAuthConfig.kt | 72 ------- .../CustomCsrfAuthenticationStrategy.kt | 36 ---- .../sessions/CustomInvalidSessionStrategy.kt | 56 ------ .../auth/sessions/CustomRedisSessionMapper.kt | 39 ---- .../CustomSessionAuthenticationStrategy.kt | 92 --------- .../auth/sessions/CustomSessionIdGenerator.kt | 23 --- .../sessions/SessionApplicationInitialiser.kt | 21 -- .../SessionEventHttpSessionListenerAdapter.kt | 113 ----------- .../auth/sessions/SessionManagementService.kt | 45 ----- Spring BFF/auth/sessions/SessionRememberMe.kt | 30 --- .../OAuth2TokenCustomiserJwtEncoding.kt | 99 ---------- .../OAuth2TokenCustomiserOAuth2Claims.kt | 43 ----- .../auth/tokens/TokenCustomiserConfig.kt | 85 -------- .../docdb/DocDbUserDetailsManager.kt | 21 -- .../docdb/DocDbUserDetailsManagerImpl.kt | 119 ------------ .../oidc/OidcUserDetailsService.kt | 57 ------ .../oidc/oidcmappers/GoogleOidcUserMapper.kt | 73 ------- .../oidc/oidcmappers/OidcMapper.kt | 22 --- .../virtualthreads/VirtualThreadsManager.kt | 66 ------- 49 files changed, 3373 deletions(-) delete mode 100644 Spring BFF/auth/AuthServerConfig.kt delete mode 100644 Spring BFF/auth/DefaultSecurityConfig.kt delete mode 100644 Spring BFF/auth/TomCatServerConfig.kt delete mode 100644 Spring BFF/auth/application.yaml delete mode 100644 Spring BFF/auth/converters/BasicJSONConverter.kt delete mode 100644 Spring BFF/auth/cookies/CookiesConfig.kt delete mode 100644 Spring BFF/auth/encoders/PasswordEncoderConfig.kt delete mode 100644 Spring BFF/auth/filters/DocDbAuthenticationFilter.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/CustomSimpleUrlAuthenticationFailureHandler.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/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/redis/RedisConnectionFactoryConfig.kt delete mode 100644 Spring BFF/auth/redis/RedisSerialiser.kt delete mode 100644 Spring BFF/auth/redis/RedisTemplateConfig.kt delete mode 100644 Spring BFF/auth/repositories/ClientRegistrationRepository.kt delete mode 100644 Spring BFF/auth/repositories/CsrfTokenRespository.kt delete mode 100644 Spring BFF/auth/repositories/OAuth2ServiceRepository.kt delete mode 100644 Spring BFF/auth/repositories/RedisIndexedSessionRepositoryConfig.kt delete mode 100644 Spring BFF/auth/repositories/RedisRememberMeTokenRepository.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/roles/RoleAuthConfig.kt delete mode 100644 Spring BFF/auth/sessions/CustomCsrfAuthenticationStrategy.kt delete mode 100644 Spring BFF/auth/sessions/CustomInvalidSessionStrategy.kt delete mode 100644 Spring BFF/auth/sessions/CustomRedisSessionMapper.kt delete mode 100644 Spring BFF/auth/sessions/CustomSessionAuthenticationStrategy.kt delete mode 100644 Spring BFF/auth/sessions/CustomSessionIdGenerator.kt delete mode 100644 Spring BFF/auth/sessions/SessionApplicationInitialiser.kt delete mode 100644 Spring BFF/auth/sessions/SessionEventHttpSessionListenerAdapter.kt delete mode 100644 Spring BFF/auth/sessions/SessionManagementService.kt delete mode 100644 Spring BFF/auth/sessions/SessionRememberMe.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/docdb/DocDbUserDetailsManager.kt delete mode 100644 Spring BFF/auth/userservice/docdb/DocDbUserDetailsManagerImpl.kt delete mode 100644 Spring BFF/auth/userservice/oidc/OidcUserDetailsService.kt delete mode 100644 Spring BFF/auth/userservice/oidc/oidcmappers/GoogleOidcUserMapper.kt delete mode 100644 Spring BFF/auth/userservice/oidc/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 8d253ef..0000000 --- a/Spring BFF/auth/AuthServerConfig.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.example.authorizationserver.auth - -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 { - - // disable csrf - http.csrf { csrf -> csrf.disable() } - - // apply default http security settings to oauth 2.0 (e.g. default endpoints) - OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http) - - // enable OpenID Connect 1.0 - http.getConfigurer(OAuth2AuthorizationServerConfigurer::class.java) - .oidc(withDefaults()) - - // redirect to the login page when not authenticated - // handlers for any exceptions not handled elsewhere - http.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 263d3e9..0000000 --- a/Spring BFF/auth/DefaultSecurityConfig.kt +++ /dev/null @@ -1,164 +0,0 @@ -package com.example.authorizationserver.auth - -import com.example.authorizationserver.auth.filters.DocDbAuthenticationFilter -import com.example.authorizationserver.auth.handlers.DefaultAccessDeniedHandler -import com.example.authorizationserver.auth.handlers.SocialLoginSuccessHandler -import com.example.authorizationserver.auth.repositories.CustomServletCsrfTokenRepository -import com.example.authorizationserver.auth.repositories.RedisRememberMeTokenRepository -import com.example.authorizationserver.auth.requestcache.CustomRequestCache -import com.example.authorizationserver.auth.sessions.CustomCsrfAuthenticationStrategy -import com.example.authorizationserver.auth.sessions.CustomInvalidSessionStrategy -import com.example.authorizationserver.auth.sessions.CustomSessionAuthenticationStrategy -import org.springframework.beans.factory.annotation.Autowired -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.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.authentication.logout.HeaderWriterLogoutHandler -import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy -import org.springframework.security.web.context.SecurityContextRepository -import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter -import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.COOKIES -import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession -import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices - - -/**********************************************************************************************************************/ -/*********************************************** DEFAULT SECURITY CONFIGURATION ***************************************/ -/**********************************************************************************************************************/ - -@Configuration -@EnableWebSecurity -@EnableRedisHttpSession( ) -internal class DefaultSecurityConfig () { - - // rememberMe Key - @Value("\${security.remember-me.key}") - private lateinit var rememberMeTokenKey: String - - @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, - customServletCsrfTokenRepository : CustomServletCsrfTokenRepository, - customCsrfAuthenticationStrategy: CustomCsrfAuthenticationStrategy, - sessionRememberMeServices: SpringSessionRememberMeServices, - socialLoginSuccessHandler: SocialLoginSuccessHandler, - docDbAuthenticationFilter: DocDbAuthenticationFilter, - customRequestCache: CustomRequestCache, - customSecurityContextRepository: SecurityContextRepository, - customInvalidSessionStrategy: CustomInvalidSessionStrategy, - customSessionAuthenticationStrategy: CustomSessionAuthenticationStrategy, - redisRememberMeTokenRepository: RedisRememberMeTokenRepository, - accessDeniedHandler: DefaultAccessDeniedHandler, - ): SecurityFilterChain { - - // enable csrf - http.csrf { csrf -> - csrf.csrfTokenRepository(customServletCsrfTokenRepository) - csrf.sessionAuthenticationStrategy(customCsrfAuthenticationStrategy) - csrf.requireCsrfProtectionMatcher { request -> - !request.method.equals("GET", ignoreCase = true) - } - } - - // setup session management - use stateless, and set other configurations - http.sessionManagement { session -> - // not truly stateless since HttpSessionSecurityContextRepository is used - session.sessionCreationPolicy(SessionCreationPolicy.STATELESS) - session.enableSessionUrlRewriting(false) - session.invalidSessionStrategy(customInvalidSessionStrategy) - session.sessionAuthenticationStrategy(customSessionAuthenticationStrategy) - } - - // creates a more persistent rememberMe token, that isn't lost when browser closes - // (unlike a session cookie, that will be lost) -// http.rememberMe { rememberMe -> -// rememberMe.rememberMeServices(sessionRememberMeServices) -// rememberMe.useSecureCookie(false) // scope is not just on secure connections -// rememberMe.key(rememberMeTokenKey) -// rememberMe.rememberMeCookieName("REMEMBER-ME-SESSIONID") -// rememberMe.tokenRepository(redisRememberMeTokenRepository) -// // rememberMe.userDetailsService() - NEED TO IMPLEMENT -// } - - // apply security context repository - http.securityContext { context -> - context.securityContextRepository(customSecurityContextRepository) - } - - // configure request cache - http.requestCache { requestCache -> - requestCache.requestCache(customRequestCache) - } - - // form login handles the redirect to the login page from earlier filter chain - http.formLogin { formLogin -> - formLogin - .permitAll() - } - - // oauth2.0 client login (google) - http.oauth2Login { oauth -> - oauth - .clientRegistrationRepository(servletClientRegistrationRepository) - .authorizedClientRepository(servletAuthorizedClientRepository) - .authorizedClientService(servletAuthorizedClientService) - .successHandler(socialLoginSuccessHandler) - } - - // apply DocDb authentication filter - http.addFilterBefore( - docDbAuthenticationFilter, - UsernamePasswordAuthenticationFilter::class.java - ) - - // authorizations (all end points, apart from login and logout not permitted, unless authenticated) - http.authorizeHttpRequests { authorize -> - authorize - .anyRequest().authenticated() - } - - // 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) - http.logout { logout -> - logout.logoutUrl("/logout") - logout.invalidateHttpSession(true) - logout.clearAuthentication(true) - logout.deleteCookies("AUTH-SESSIONID") - logout.addLogoutHandler(HeaderWriterLogoutHandler(ClearSiteDataHeaderWriter(COOKIES))) - logout.permitAll() - } - - // handlers for any exceptions not handled elsewhere - http.exceptionHandling { exceptionHandling -> - exceptionHandling.accessDeniedHandler(accessDeniedHandler) - } - - return http.build() - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/TomCatServerConfig.kt b/Spring BFF/auth/TomCatServerConfig.kt deleted file mode 100644 index 8cd439a..0000000 --- a/Spring BFF/auth/TomCatServerConfig.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.example.authorizationserver.auth - -import org.apache.catalina.Context -import org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer -import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.context.annotation.Profile - -/**********************************************************************************************************************/ -/*********************************************** SERVLET CONFIGURATION ************************************************/ -/**********************************************************************************************************************/ - -@Configuration -@Profile("ssl") // only active when 'ssl' profile is active -internal class TomcatConfig { - @Bean - fun tomcatCustomizer(): TomcatServletWebServerFactory { - val factory = TomcatServletWebServerFactory() - - // disable SSL - factory.ssl = null - - // customize session timeout - factory.addContextCustomizers(TomcatContextCustomizer { context: Context -> - context.sessionTimeout = 5 - }) - - return factory - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/application.yaml b/Spring BFF/auth/application.yaml deleted file mode 100644 index bed0764..0000000 --- a/Spring BFF/auth/application.yaml +++ /dev/null @@ -1,111 +0,0 @@ -# Custom properties to ease configuration overrides -# on command-line or IDE launch configurations - -#**********************************************************************************************************************# -#***************************************************** VARIABLES ******************************************************# -#**********************************************************************************************************************# - -# server settings -scheme: http -hostname: localhost - -# reverse proxy -reverse-proxy-port: 7080 -reverse-proxy-uri: ${scheme}://${hostname}:${reverse-proxy-port} - -# bff server -bff-prefix: /bff - -# authorization server -authorization-server-port: 6060 -authorization-server-prefix: /auth -in-house-auth-registration-id: in-house-auth-server -in-house-issuer-uri: ${reverse-proxy-uri}${authorization-server-prefix} - -#**********************************************************************************************************************# -#************************************************** SPRING SETTINGS ***************************************************# -#**********************************************************************************************************************# - -# spring settings -spring: - # profile settings - profiles: - active: ssl - # session redis configurations - session: - redis: - namespace: spring:session:in-house-auth-server - repository-type: indexed - flush-mode: on-save - timeout: 30 - -#**********************************************************************************************************************# -#************************************************** SERVER SETTINGS ***************************************************# -#**********************************************************************************************************************# - -# current server settings -server: - port: ${authorization-server-port} - ssl: - enabled: false - -#**********************************************************************************************************************# -#************************************************** SPRING SETTINGS ***************************************************# -#**********************************************************************************************************************# - -security: - remember-me: - key: S/MqST4}8Weo)OLyL$N|9RY-.|.46zpVtb'{wVf~IdgWk#r>D[9DzUCL|DTv_Hb - -#**********************************************************************************************************************# -#************************************************* PROFILE SETTINGS ***************************************************# -#**********************************************************************************************************************# - -# spring profile settings ---- -spring: - config: - activate: - on-profile: ssl -server: - ssl: - # This has been disabled! - enabled: false - -#**********************************************************************************************************************# -#*********************************************** MANAGEMENT SETTINGS **************************************************# -#**********************************************************************************************************************# - -# endpoint settings -management: - endpoint: - health: - probes: - enabled: true - endpoints: - web: - exposure: - include: health,info - health: - livenessstate: - enabled: true - readinessstate: - enabled: true - -#**********************************************************************************************************************# -#************************************************ LOGGING SETTINGS ****************************************************# -#**********************************************************************************************************************# - -# logging configurations -logging: - level: - root: INFO - org: - springframework: - boot: INFO - security: TRACE - web: INFO - -#**********************************************************************************************************************# -#************************************************** END OF YAML *******************************************************# -#**********************************************************************************************************************# \ 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 076c512..0000000 --- a/Spring BFF/auth/converters/BasicJSONConverter.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.example.authorizationserver.auth.converters - -import com.example.authorizationserver.auth.objects.authentication.DocDbUserAuthentication -import com.example.authorizationserver.auth.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 5ea154b..0000000 --- a/Spring BFF/auth/cookies/CookiesConfig.kt +++ /dev/null @@ -1,48 +0,0 @@ -package com.example.authorizationserver.auth.cookies - -import org.springframework.boot.web.servlet.ServletContextInitializer -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 ************************************************/ -/**********************************************************************************************************************/ - -// more here: -// https://docs.spring.io/spring-session/reference/configuration/common.html#customizing-session-cookie - -@Configuration -internal class CookiesConfig { - - @Bean - fun cookieSerializer(): CookieSerializer { - val serializer = DefaultCookieSerializer() - serializer.setCookieName("AUTH-SESSIONID-VIA-BEAN") - serializer.setUseHttpOnlyCookie(true) - serializer.setUseSecureCookie(false) // scope is not just on secure connections - serializer.setSameSite("Strict") - serializer.setCookieMaxAge(5) - serializer.setCookiePath("/") - return serializer - } - - @Bean - fun sessionCookieConfig(): ServletContextInitializer { - return ServletContextInitializer { servletContext -> - val sessionCookieConfig = servletContext.sessionCookieConfig - sessionCookieConfig.name = "AUTH-SESSIONID" - sessionCookieConfig.isHttpOnly = true - sessionCookieConfig.isSecure = false // scope is not just on secure connections - sessionCookieConfig.maxAge = 5 - sessionCookieConfig.path = "/" - } - } - -} - - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/encoders/PasswordEncoderConfig.kt b/Spring BFF/auth/encoders/PasswordEncoderConfig.kt deleted file mode 100644 index 8cd37e8..0000000 --- a/Spring BFF/auth/encoders/PasswordEncoderConfig.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.example.authorizationserver.auth.encoders - -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder -import org.springframework.security.crypto.password.DelegatingPasswordEncoder -import org.springframework.security.crypto.password.PasswordEncoder -import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder -import java.security.SecureRandom - -/**********************************************************************************************************************/ -/******************************************************* CONFIGURATION ************************************************/ -/**********************************************************************************************************************/ - -@Configuration -internal class PasswordEncoderConfig() { - - @Bean - fun passwordEncoder(): PasswordEncoder { - - // BCrypt parameters - val bcryptParams = BCryptPasswordEncoder( - 10, - SecureRandom.getInstanceStrong() - ) - - // SCrypt parameters - val scryptParams = SCryptPasswordEncoder( - 16384, // CPU cost parameter - 8, // Memory cost parameter - 1, // Parallelization parameter - 32, // Key length parameter - 16 // Salt length parameter - ) - - // map of password encoders - val encoders: Map = mapOf( - "bcrypt" to bcryptParams, - "scrypt" to scryptParams - // optionally, add a "noop" encoder for testing or migration purposes - // "noop" to NoOpPasswordEncoder.getInstance() - ) - - // default encoder used - return DelegatingPasswordEncoder("bcrypt", encoders) - } - -} - -/**********************************************************************************************************************/ -/**************************************************** 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 7ca11d9..0000000 --- a/Spring BFF/auth/filters/DocDbAuthenticationFilter.kt +++ /dev/null @@ -1,133 +0,0 @@ -package com.example.authorizationserver.auth.filters - -import com.example.authorizationserver.auth.converters.BasicJSONConverter -import com.example.authorizationserver.auth.handlers.CustomSavedRequestAwareAuthenticationSuccessHandler -import com.example.authorizationserver.auth.handlers.CustomSimpleUrlAuthenticationFailureHandler -import com.example.authorizationserver.auth.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 customSessionAuthenticationStrategy: CustomSessionAuthenticationStrategy, - customSavedRequestAwareAuthenticationSuccessHandler: CustomSavedRequestAwareAuthenticationSuccessHandler, - customSimpleUrlAuthenticationFailureHandler: CustomSimpleUrlAuthenticationFailureHandler, - 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) - - // success handler - val successHandler = customSavedRequestAwareAuthenticationSuccessHandler - this.setAuthenticationSuccessHandler(successHandler) - - // failure handler - val failureHandler = customSimpleUrlAuthenticationFailureHandler - this.setAuthenticationFailureHandler(failureHandler) - } - - - // 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) - - } - - - // 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/handlers/AccessDeniedHandler.kt b/Spring BFF/auth/handlers/AccessDeniedHandler.kt deleted file mode 100644 index 4140ecd..0000000 --- a/Spring BFF/auth/handlers/AccessDeniedHandler.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.example.authorizationserver.auth.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 3499d86..0000000 --- a/Spring BFF/auth/handlers/CustomSavedRequestAwareAuthenticationSuccessHandler.kt +++ /dev/null @@ -1,96 +0,0 @@ -package com.example.authorizationserver.auth.handlers - -import com.example.authorizationserver.auth.requestcache.CustomRequestCache -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse -import jakarta.servlet.http.HttpSession -import org.springframework.security.core.Authentication -import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler -import org.springframework.stereotype.Component -import java.time.Duration -import java.time.Instant - -/**********************************************************************************************************************/ -/****************************************************** HANDLER *******************************************************/ -/**********************************************************************************************************************/ - -@Component -internal class CustomSavedRequestAwareAuthenticationSuccessHandler( - customRequestCache: CustomRequestCache -) : SavedRequestAwareAuthenticationSuccessHandler() { - - init { - // set the custom request cache here - super.setRequestCache(customRequestCache) - } - - override fun onAuthenticationSuccess( - request: HttpServletRequest, - response: HttpServletResponse, - authentication: Authentication - ) { - - // handle authentication success - super.onAuthenticationSuccess(request, response, authentication) - - // manage the session - this.manageSession(request, response) - } - - - /** - * 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?, - response: HttpServletResponse? - ) { - // 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 (for testing purposes) - request.getSession()?.setMaxInactiveInterval(5) - - // 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 session details - println("SESSION INFORMATION - AFTER SUCCESSFUL AUTHENTICATION") - 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") - - // log session cookie details - val sessionCookie = session.servletContext.sessionCookieConfig - println("SESSION COOKIE INFORMATION") - println("Cookie Name: ${sessionCookie.name}") - println("Cookie Path: ${sessionCookie.path}") - println("Cookie Domain: ${sessionCookie.domain}") - println("Cookie Max Age: ${sessionCookie.maxAge}") - println("Cookie Secure: ${sessionCookie.isSecure}") - println("Cookie HttpOnly: ${sessionCookie.isHttpOnly}") - println("Cookie Attributes: ${sessionCookie.attributes}") - println("-----------") - - } ?: run { - println("No session available.") - } - } -} - - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/handlers/CustomSimpleUrlAuthenticationFailureHandler.kt b/Spring BFF/auth/handlers/CustomSimpleUrlAuthenticationFailureHandler.kt deleted file mode 100644 index 5ebb97b..0000000 --- a/Spring BFF/auth/handlers/CustomSimpleUrlAuthenticationFailureHandler.kt +++ /dev/null @@ -1,90 +0,0 @@ -package com.example.authorizationserver.auth.handlers - -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse -import jakarta.servlet.http.HttpSession -import org.springframework.security.core.AuthenticationException -import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler -import org.springframework.stereotype.Component -import java.time.Duration -import java.time.Instant - -/**********************************************************************************************************************/ -/****************************************************** HANDLER *******************************************************/ -/**********************************************************************************************************************/ - -@Component -internal class CustomSimpleUrlAuthenticationFailureHandler( - -) : SimpleUrlAuthenticationFailureHandler() { - - override fun onAuthenticationFailure( - request: HttpServletRequest?, - response: HttpServletResponse?, - exception: AuthenticationException? - ) { - - // handle authentication failure - super.onAuthenticationFailure(request, response, exception) - - // manage the session - this.manageSession(request, response) - } - - /** - * 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?, - response: HttpServletResponse? - ) { - // 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 (for testing purposes) - session.setMaxInactiveInterval(5) - - // 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 session details - println("SESSION INFORMATION - AFTER FAILED AUTHENTICATION") - 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") - println("-----------") - - // log session cookie details - val sessionCookie = session.servletContext.sessionCookieConfig - println("SESSION COOKIE INFORMATION") - println("Cookie Name: ${sessionCookie.name}") - println("Cookie Path: ${sessionCookie.path}") - println("Cookie Domain: ${sessionCookie.domain}") - println("Cookie Max Age: ${sessionCookie.maxAge}") - println("Cookie Secure: ${sessionCookie.isSecure}") - println("Cookie HttpOnly: ${sessionCookie.isHttpOnly}") - println("Cookie Attributes: ${sessionCookie.attributes}") - println("-----------") - - } ?: run { - println("No session available.") - } - } - -} - -/**********************************************************************************************************************/ -/**************************************************** 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 fddbd2b..0000000 --- a/Spring BFF/auth/handlers/SocialLoginSuccessHandler.kt +++ /dev/null @@ -1,80 +0,0 @@ -package com.example.authorizationserver.auth.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 - ) { - - 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 93b8cef..0000000 --- a/Spring BFF/auth/handlers/UserServiceOidcUserHandler.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.example.authorizationserver.auth.handlers - -import com.example.authorizationserver.api.enums.RoleTypes -import com.example.authorizationserver.auth.objects.user.CustomOidcUser -import com.example.authorizationserver.auth.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 database 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/manager/ServletAuthenticationManager.kt b/Spring BFF/auth/manager/ServletAuthenticationManager.kt deleted file mode 100644 index d86ab11..0000000 --- a/Spring BFF/auth/manager/ServletAuthenticationManager.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.example.authorizationserver.auth.manager - -import com.example.authorizationserver.auth.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 a8038b6..0000000 --- a/Spring BFF/auth/objects/authentication/DocDbUserAuthentication.kt +++ /dev/null @@ -1,62 +0,0 @@ -package com.example.authorizationserver.auth.objects.authentication - -import com.example.authorizationserver.auth.objects.user.DocDbUser -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import org.springframework.security.core.GrantedAuthority -import org.springframework.security.authentication.AbstractAuthenticationToken -import org.springframework.security.core.userdetails.UserDetails - -/**********************************************************************************************************************/ -/*********************************************** AUTHENTICATION OBJECT ************************************************/ -/**********************************************************************************************************************/ - -class DocDbUserAuthentication @JsonCreator constructor( - @JsonProperty("docDBUser") private val docDBUser: DocDbUser?, - @JsonProperty("password") private val password: String?, - @JsonProperty("authorities") authorities: Collection, - @JsonProperty("isAuthenticated") isAuthenticated: Boolean -) : AbstractAuthenticationToken(authorities) { - - init { - // set the authentication status based on the input - super.setAuthenticated(isAuthenticated) - } - - 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, - null, - docDBUser.authorities, - true - ) - } - - fun unauthenticated(docDBUser: DocDbUser, password: String): DocDbUserAuthentication { - return DocDbUserAuthentication( - docDBUser, - password, - docDBUser.authorities, - false - ) - } - } -} - -/**********************************************************************************************************************/ -/**************************************************** 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 e0c0ed3..0000000 --- a/Spring BFF/auth/objects/user/DocDbUser.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.example.authorizationserver.auth.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 5cfc17e..0000000 --- a/Spring BFF/auth/objects/user/OidcUser.kt +++ /dev/null @@ -1,106 +0,0 @@ -package com.example.authorizationserver.auth.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 7228a8a..0000000 --- a/Spring BFF/auth/providers/DocDbAuthenticationProvider.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.example.authorizationserver.auth.providers - -import com.example.authorizationserver.auth.objects.authentication.DocDbUserAuthentication -import com.example.authorizationserver.auth.objects.user.DocDbUser -import com.example.authorizationserver.auth.userservice.docdb.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/redis/RedisConnectionFactoryConfig.kt b/Spring BFF/auth/redis/RedisConnectionFactoryConfig.kt deleted file mode 100644 index e484fb9..0000000 --- a/Spring BFF/auth/redis/RedisConnectionFactoryConfig.kt +++ /dev/null @@ -1,101 +0,0 @@ -package com.example.authorizationserver.auth.redis - -import io.lettuce.core.ClientOptions -import io.lettuce.core.SocketOptions -import io.lettuce.core.resource.DefaultClientResources -import org.apache.commons.pool2.impl.GenericObjectPoolConfig -import org.springframework.beans.factory.annotation.Value -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.context.annotation.Primary -import org.springframework.data.redis.connection.RedisPassword -import org.springframework.data.redis.connection.RedisConnectionFactory -import org.springframework.data.redis.connection.RedisStandaloneConfiguration -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory -import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration -import java.time.Duration - -/**********************************************************************************************************************/ -/************************************************ REDIS CONFIGURATION *************************************************/ -/**********************************************************************************************************************/ - -// see here for more: -// https://docs.spring.io/spring-session/reference/web-session.html#websession-redis -// https://docs.spring.io/spring-session/reference/configuration/redis.html - -@Configuration -class RedisConnectionFactoryConfig { - - @Value("\${spring.data.redis.host}") - private lateinit var redisHostName: String - - @Value("\${spring.data.redis.password}") - private lateinit var redisPassword: String - - @Value("\${spring.data.redis.port}") - private var redisPort: Int = 6380 - - @Bean - @Primary - fun redisConnectionFactory(): RedisConnectionFactory { - - // configure Redis standalone configuration - val config = RedisStandaloneConfiguration() - config.hostName = redisHostName - config.port = redisPort - config.setPassword(RedisPassword.of(redisPassword)) - - // create socket options - val socketOptions = SocketOptions.builder() - .keepAlive(true) - .connectTimeout(Duration.ofSeconds(60)) - .build() - - // create client options - val clientOptions = ClientOptions.builder() - .autoReconnect(true) - .pingBeforeActivateConnection(true) - .socketOptions(socketOptions) - .build() - - // customize thread pool size - val clientResources = DefaultClientResources.builder() - .ioThreadPoolSize(4) - .computationThreadPoolSize(4) - .build() - - // create Lettuce client configuration with authentication details - val clientConfig = LettucePoolingClientConfiguration.builder() - .commandTimeout(Duration.ofSeconds(60)) - .clientResources(clientResources) - .clientOptions(clientOptions) - .poolConfig(buildLettucePoolConfig()) - .useSsl() - .build() - - // create Lettuce connection factory - return LettuceConnectionFactory(config, clientConfig).apply { - afterPropertiesSet() - } - } - - // configure connection pool settings - protected fun buildLettucePoolConfig(): GenericObjectPoolConfig { - val poolConfig = GenericObjectPoolConfig() - poolConfig.maxTotal = 100 - poolConfig.maxIdle = 50 - poolConfig.minIdle = 10 - poolConfig.setMaxWait(Duration.ofSeconds(60)) - poolConfig.timeBetweenEvictionRuns = Duration.ofSeconds(60) - poolConfig.minEvictableIdleTime = Duration.ofMinutes(5) - poolConfig.testOnBorrow = true - poolConfig.testWhileIdle = true - poolConfig.testOnReturn = true - return poolConfig - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/redis/RedisSerialiser.kt b/Spring BFF/auth/redis/RedisSerialiser.kt deleted file mode 100644 index 1716c78..0000000 --- a/Spring BFF/auth/redis/RedisSerialiser.kt +++ /dev/null @@ -1,181 +0,0 @@ -package com.example.authorizationserver.auth.redis - -import com.example.authorizationserver.api.enums.RoleTypes -import com.example.authorizationserver.auth.objects.authentication.DocDbUserAuthentication -import com.example.authorizationserver.auth.objects.user.DocDbUser -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.annotation.JsonTypeInfo -import com.fasterxml.jackson.annotation.JsonTypeInfo.As -import com.fasterxml.jackson.annotation.JsonTypeInfo.Id -import com.fasterxml.jackson.core.JsonParser -import com.fasterxml.jackson.core.JsonProcessingException -import com.fasterxml.jackson.databind.DeserializationContext -import com.fasterxml.jackson.databind.JsonDeserializer -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.module.SimpleModule -import org.apache.logging.log4j.LogManager -import org.apache.logging.log4j.Logger -import org.springframework.beans.factory.BeanClassLoaderAware -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer -import org.springframework.data.redis.serializer.RedisSerializer -import org.springframework.security.core.GrantedAuthority -import org.springframework.security.core.authority.SimpleGrantedAuthority -import org.springframework.security.jackson2.SecurityJackson2Modules -import java.io.IOException - -/**********************************************************************************************************************/ -/************************************************ REDIS CONFIGURATION *************************************************/ -/**********************************************************************************************************************/ - -// more here: -// https://docs.spring.io/spring-session/reference/configuration/redis.html#serializing-session-using-json - -@Configuration -internal class RedisSerialiser : BeanClassLoaderAware { - - private var loader: ClassLoader? = null - - /** - * Note that the bean name for this bean is intentionally - * {@code springSessionDefaultRedisSerializer}. It must be named this way to override - * the default {@link RedisSerializer} used by Spring Session. - */ - @Bean - // setting a custom session serialiser for Redis - fun springSessionDefaultRedisSerializer(): RedisSerializer { - return object : GenericJackson2JsonRedisSerializer(objectMapper()) { - override fun serialize(value: Any?): ByteArray { - println("Serializing: $value") - return super.serialize(value) - } - - override fun deserialize(bytes: ByteArray?): Any { - if (bytes !== null && bytes.isNotEmpty()) { - val result = super.deserialize(bytes) - return result - } - println("Deserialization: Received null or empty byte array") - return Any() - } - } - } - - /** - * Customized {@link ObjectMapper} to add mix-in for class that doesn't have default - * constructors. - * @return the {@link ObjectMapper} to use - */ - private fun objectMapper(): ObjectMapper { - val mapper = ObjectMapper() - - // register mixin for DocDbUserAuthentication - mapper.addMixIn(DocDbUserAuthentication::class.java, DocDbUserAuthenticationMixin::class.java) - - // register modules for security if needed - mapper.registerModules(SecurityJackson2Modules.getModules(loader)) - - // register custom deserializer for DocDbUserAuthentication - mapper.registerModule( - SimpleModule().addDeserializer(DocDbUserAuthentication::class.java, DocDbUserAuthenticationDeserializer()) - ) - - return mapper - } - - /* - * @see - * org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(java.lang.ClassLoader) - */ - override fun setBeanClassLoader(classLoader: ClassLoader) { - this.loader = classLoader - } -} - -// custom mixin for DocDbUserAuthentication object -@JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY, property = "@class") -abstract class DocDbUserAuthenticationMixin { - @JsonProperty("docDBUser") - abstract fun getDocDBUser(): DocDbUser? - - @JsonProperty("password") - abstract fun getPassword(): String? - - @JsonProperty("authorities") - abstract fun getAuthorities(): Collection - - @JsonProperty("isAuthenticated") - abstract fun isAuthenticated(): Boolean -} - -// custom de-serialiser for DocDbUserAuthentication object -private class DocDbUserAuthenticationDeserializer : JsonDeserializer() { - - val logger: Logger = LogManager.getLogger( - DocDbUserAuthenticationDeserializer::class.java - ) - - @Throws(IOException::class, JsonProcessingException::class) - override fun deserialize( - p: JsonParser, - ctxt: DeserializationContext, - ): DocDbUserAuthentication? { - - val node: JsonNode = p.codec.readTree(p) - - // deserialize DocDbUser - val docDBUserNode = node.get("docDBUser") - val docDBUser = docDBUserNode?.let { userNode -> - val userId = userNode.get("userId")?.asText() - val username = userNode.get("username")?.asText() ?: "" - val password = userNode.get("password")?.asText() - val isAccountNonExpired = userNode.get("isAccountNonExpired")?.asBoolean() - val isAccountNonLocked = userNode.get("isAccountNonLocked")?.asBoolean() - val isCredentialsNonExpired = userNode.get("isCredentialsNonExpired")?.asBoolean() - val isEnabled = userNode.get("isEnabled")?.asBoolean() - - // deserialize GrantedAuthority list - val authorities = userNode.get("authorities")?.mapNotNull { authorityNode -> - if (authorityNode.isTextual) { - authorityNode.asText()?.let { auth -> SimpleGrantedAuthority(auth) } - } else { - // Handle unexpected format (optional) - logger.warn("Unexpected format for authority: {}", authorityNode) - null - } - }?.takeIf { it.isNotEmpty() } ?: listOf(SimpleGrantedAuthority(RoleTypes.EMPTY.name)) - - // create DocDbUser instance - DocDbUser( - userId, - username, - password, - authorities, - isAccountNonExpired, - isAccountNonLocked, - isCredentialsNonExpired, - isEnabled - ) - } - - // deserialize other fields - val isAuthenticated = node.get("isAuthenticated")?.asBoolean() ?: false - - // create DocDbUserAuthentication instance - return docDBUser?.let { - docDBUser.authorities.let { auths -> - DocDbUserAuthentication( - it, - docDBUser.password, - auths, - isAuthenticated) - } - } - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/redis/RedisTemplateConfig.kt b/Spring BFF/auth/redis/RedisTemplateConfig.kt deleted file mode 100644 index 8a63e3b..0000000 --- a/Spring BFF/auth/redis/RedisTemplateConfig.kt +++ /dev/null @@ -1,70 +0,0 @@ -package com.example.authorizationserver.auth.redis - -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.context.annotation.Primary -import org.springframework.data.redis.connection.RedisConnectionFactory -import org.springframework.data.redis.core.RedisOperations -import org.springframework.data.redis.core.RedisTemplate -import org.springframework.data.redis.serializer.RedisSerializer -import org.springframework.data.redis.serializer.StringRedisSerializer -import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest - -/**********************************************************************************************************************/ -/************************************************ REDIS CONFIGURATION *************************************************/ -/**********************************************************************************************************************/ - -@Configuration -internal class RedisTemplateConfig { - - @Bean - @Primary - // redis Template for sessions - fun reactiveRedisTemplate( - connectionFactory: RedisConnectionFactory, - springSessionDefaultRedisSerializer: RedisSerializer - ): RedisTemplate { - return RedisTemplate().apply { - setConnectionFactory(connectionFactory) - keySerializer = StringRedisSerializer() - valueSerializer = springSessionDefaultRedisSerializer - hashKeySerializer = StringRedisSerializer() - hashValueSerializer = springSessionDefaultRedisSerializer - } - } - - @Bean - // redis Operations for sessions - fun reactiveRedisOperations( - connectionFactory: RedisConnectionFactory, - springSessionDefaultRedisSerializer: RedisSerializer - ): RedisOperations { - return RedisTemplate().apply { - setConnectionFactory(connectionFactory) - keySerializer = StringRedisSerializer() - valueSerializer = springSessionDefaultRedisSerializer - hashKeySerializer = StringRedisSerializer() - hashValueSerializer = springSessionDefaultRedisSerializer - } - } - - @Bean - // redis Template for oauth2AuthorizationRequests - fun oauth2AuthorizationRequestRedisTemplate( - connectionFactory: RedisConnectionFactory, - oauth2AuthorizationRequestRedisSerializer: RedisSerializer - ): RedisTemplate { - return RedisTemplate().apply { - setConnectionFactory(connectionFactory) - keySerializer = StringRedisSerializer() - valueSerializer = oauth2AuthorizationRequestRedisSerializer - hashKeySerializer = StringRedisSerializer() - hashValueSerializer = oauth2AuthorizationRequestRedisSerializer - } - } - -} - -/**********************************************************************************************************************/ -/**************************************************** 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 fa28971..0000000 --- a/Spring BFF/auth/repositories/ClientRegistrationRepository.kt +++ /dev/null @@ -1,86 +0,0 @@ -package com.example.authorizationserver.auth.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}") - private lateinit var googleClientId: String - - // google client secret - @Value("\${oauth2.client.registration.google.client-secret}") - private 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/CsrfTokenRespository.kt b/Spring BFF/auth/repositories/CsrfTokenRespository.kt deleted file mode 100644 index 3874af3..0000000 --- a/Spring BFF/auth/repositories/CsrfTokenRespository.kt +++ /dev/null @@ -1,61 +0,0 @@ -package com.example.authorizationserver.auth.repositories - -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse -import org.springframework.security.web.csrf.CookieCsrfTokenRepository -import org.springframework.security.web.csrf.CsrfToken -import org.springframework.security.web.csrf.CsrfTokenRepository -import org.springframework.stereotype.Repository - -/**********************************************************************************************************************/ -/***************************************************** REPOSITORY *****************************************************/ -/**********************************************************************************************************************/ - -@Repository -internal class CustomServletCsrfTokenRepository : CsrfTokenRepository { - - companion object { - private const val CSRF_COOKIE_NAME = "XSRF-AUTH-TOKEN" - private const val CSRF_HEADER_NAME = "X-XSRF-AUTH-TOKEN" - private const val CSRF_PARAMETER_NAME = "_csrf" - private const val COOKIE_PATH = "/" - private const val COOKIE_SAME_SITE = "Strict" - } - private val cookieCsrfTokenRepository = CookieCsrfTokenRepository() - - init { - cookieCsrfTokenRepository.setCookieName(CSRF_COOKIE_NAME) - cookieCsrfTokenRepository.setHeaderName(CSRF_HEADER_NAME) - cookieCsrfTokenRepository.setParameterName(CSRF_PARAMETER_NAME) - cookieCsrfTokenRepository.setCookieCustomizer { cookie -> - cookie.httpOnly(true) - cookie.secure(false) // scope is not just on secure connections - cookie.sameSite(COOKIE_SAME_SITE) - cookie.maxAge(-1) - cookie.path(COOKIE_PATH) - } - } - - override fun generateToken(request: HttpServletRequest): CsrfToken { - println("Generating CSRF Token") - return cookieCsrfTokenRepository.generateToken(request) - } - - override fun saveToken( - token: CsrfToken?, - request: HttpServletRequest, - response: HttpServletResponse? - ) { - println("Saving CSRF Token: ${token?.token}") - cookieCsrfTokenRepository.saveToken(token, request, response) - } - - override fun loadToken(request: HttpServletRequest): CsrfToken? { - println("Loaded CSRF Token: ${cookieCsrfTokenRepository.loadToken(request)?.token}") - return cookieCsrfTokenRepository.loadToken(request) - } -} - -/**********************************************************************************************************************/ -/**************************************************** 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 8b83a1d..0000000 --- a/Spring BFF/auth/repositories/OAuth2ServiceRepository.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.example.authorizationserver.auth.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/RedisIndexedSessionRepositoryConfig.kt b/Spring BFF/auth/repositories/RedisIndexedSessionRepositoryConfig.kt deleted file mode 100644 index 2cc97d0..0000000 --- a/Spring BFF/auth/repositories/RedisIndexedSessionRepositoryConfig.kt +++ /dev/null @@ -1,97 +0,0 @@ -package com.example.authorizationserver.auth.repositories - -import com.example.authorizationserver.auth.sessions.CustomRedisSessionMapper -import com.example.authorizationserver.auth.sessions.CustomSessionIdGenerator -import org.springframework.beans.factory.annotation.Value -import org.springframework.context.ApplicationEventPublisher -import org.springframework.context.annotation.Bean -import org.springframework.data.redis.core.RedisOperations -import org.springframework.data.redis.core.RedisTemplate -import org.springframework.session.FindByIndexNameSessionRepository -import org.springframework.session.SaveMode -import org.springframework.session.Session -import org.springframework.session.config.SessionRepositoryCustomizer -import org.springframework.session.data.redis.ReactiveRedisIndexedSessionRepository -import org.springframework.session.data.redis.ReactiveRedisIndexedSessionRepository.RedisSession -import org.springframework.session.data.redis.RedisIndexedSessionRepository -import org.springframework.stereotype.Repository -import java.time.Duration - -// WARNING!!! -// When using RedisIndexedSessionRepository with Redis Cluster you must be aware that it only subscribe -// to events from one random redis node in the cluster, which can cause some session indexes not -// being cleaned up if the event happened in a different node. - -/**********************************************************************************************************************/ -/***************************************************** REPOSITORY *****************************************************/ -/**********************************************************************************************************************/ - -// more here: -// https://docs.spring.io/spring-session/reference/configuration/redis.html#configuring-redis-session-mapper -// https://docs.spring.io/spring-session/reference/configuration/redis.html#choosing-between-regular-and-indexed - -@Repository -internal class RedisIndexedSessionRepositoryConfig () { - - @Value("\${spring.session.redis.namespace}") - private lateinit var redisNamespace: String - - @Value("\${spring.session.timeout}") - private var sessionTimeout: Int = 30 - - /** - * Customizes the RedisIndexedSessionRepository to use the CustomRedisSessionMapper. - */ - @Bean - fun redisIndexedSessionRepositoryCustomizer( - redisIndexedSessionRepository: RedisIndexedSessionRepository - ): SessionRepositoryCustomizer { - return SessionRepositoryCustomizer { repository -> - repository.setRedisSessionMapper(CustomRedisSessionMapper(repository)) - } - } - - /** - * Session repository configuration for Redis. - **/ - @Bean - fun redisIndexedSessionRepository( - redisOperations: RedisOperations, - redisTemplate: RedisTemplate, - eventPublisher: ApplicationEventPublisher - ): FindByIndexNameSessionRepository { - val repository = RedisIndexedSessionRepository(redisOperations).apply { - setDefaultMaxInactiveInterval(Duration.ofMinutes(sessionTimeout.toLong())) - setRedisKeyNamespace(redisNamespace) - setSaveMode(SaveMode.ON_SET_ATTRIBUTE) - setSessionIdGenerator(CustomSessionIdGenerator()) - setApplicationEventPublisher(eventPublisher) - } - - repository.setIndexResolver { session -> - val indexes = mutableMapOf() - - // safely handle potential null values - val principalName = session.getAttribute("principalName") - val role = session.getAttribute("role") - - // use safe calls or provide default values if necessary - if (principalName != null) { - indexes["PRINCIPAL_NAME_INDEX_NAME"] = principalName - } - if (role != null) { - indexes["ROLE_INDEX_NAME"] = role - } - - indexes - } - - return repository as FindByIndexNameSessionRepository - } - - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/repositories/RedisRememberMeTokenRepository.kt b/Spring BFF/auth/repositories/RedisRememberMeTokenRepository.kt deleted file mode 100644 index 2adcb08..0000000 --- a/Spring BFF/auth/repositories/RedisRememberMeTokenRepository.kt +++ /dev/null @@ -1,107 +0,0 @@ -package com.example.authorizationserver.auth.repositories - -import org.springframework.context.annotation.Configuration -import org.springframework.data.redis.core.RedisTemplate -import org.springframework.data.redis.core.ScanOptions -import org.springframework.data.redis.serializer.StringRedisSerializer -import org.springframework.security.web.authentication.rememberme.PersistentRememberMeToken -import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository -import java.util.* -import java.util.concurrent.TimeUnit - -@Configuration -internal class RedisRememberMeTokenRepository( - private val redisTemplate: RedisTemplate -) : PersistentTokenRepository { - - /** - * Creates a new token and stores it in Redis with an expiration time of 14 days. - */ - companion object { - private const val TOKEN_VALID_DAYS = 14 - private val stringRedisSerializer = StringRedisSerializer() - private const val USERNAME = "username" - private const val TOKEN = "token" - private const val LAST_USED_DATE = "last_used_date" - private const val NAME_SPACE = "spring:session:in-house-auth-server:rememberMe:token:" - } - - /** - * Creates a new token and stores it in Redis with an expiration time of 14 days. - */ - override fun createNewToken(token: PersistentRememberMeToken) { - val key = generateKey(token.series) - val data = mapOf( - USERNAME to token.username, - TOKEN to token.tokenValue, - LAST_USED_DATE to token.date.time.toString() - ) - redisTemplate.opsForHash().putAll(key, data) - redisTemplate.expire(key, TOKEN_VALID_DAYS.toLong(), TimeUnit.DAYS) - } - - /** - * Updates an existing token in Redis with new values and resets its expiration time. - */ - override fun updateToken(series: String, tokenValue: String, lastUsed: Date) { - val key = generateKey(series) - val data = mapOf( - TOKEN to tokenValue, - LAST_USED_DATE to lastUsed.time.toString() - ) - redisTemplate.opsForHash().putAll(key, data) - redisTemplate.expire(key, TOKEN_VALID_DAYS.toLong(), TimeUnit.DAYS) - } - - - /** - * Retrieves a token from Redis using the series ID. - * Returns a PersistentRememberMeToken if the token exists; otherwise, returns null. - */ - override fun getTokenForSeries(seriesId: String): PersistentRememberMeToken? { - val key = generateKey(seriesId) - val hashValues = redisTemplate.opsForHash() - .multiGet(key, listOf(USERNAME, TOKEN, LAST_USED_DATE)) - - val username = hashValues.get(0) - val tokenValue = hashValues.get(1) - val date = hashValues.get(2)?.toLongOrNull() - - if (username == null || tokenValue == null || date == null) { - return null - } - - val time = Date(date) - return PersistentRememberMeToken(username, seriesId, tokenValue, time) - } - - /** - * Removes all tokens associated with the given username from Redis. - */ - override fun removeUserTokens(username: String) { - val hashKey = stringRedisSerializer.serialize(USERNAME) - val redisConnection = redisTemplate.connectionFactory?.connection - ?: throw IllegalStateException("Redis connection factory is not available") - - redisConnection.use { connection -> - val cursor = connection.scan( - ScanOptions.scanOptions() - .match(generateKey("*")) - .count(1024).build() - ) - cursor.use { scanCursor -> - while (scanCursor.hasNext()) { - val key = scanCursor.next() - val hashValue = connection.hGet(key, hashKey) - val storedUsername = stringRedisSerializer.deserialize(hashValue) - if (username == storedUsername) { - connection.expire(key, 0L) - return - } - } - } - } - } - - private fun generateKey(series: String) = NAME_SPACE + series -} \ 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 9737cb9..0000000 --- a/Spring BFF/auth/repositories/RegisteredClientRepository.kt +++ /dev/null @@ -1,84 +0,0 @@ -package com.example.authorizationserver.auth.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 415b4df..0000000 --- a/Spring BFF/auth/repositories/SecurityContextRepository.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.example.authorizationserver.auth.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 2e0c432..0000000 --- a/Spring BFF/auth/repositories/SessionRegistryConfig.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.example.authorizationserver.auth.repositories - -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.session.FindByIndexNameSessionRepository -import org.springframework.session.Session -import org.springframework.session.data.redis.ReactiveRedisIndexedSessionRepository.RedisSession -import org.springframework.session.security.SpringSessionBackedSessionRegistry - -/**********************************************************************************************************************/ -/***************************************************** REPOSITORY *****************************************************/ -/**********************************************************************************************************************/ - -// more here: -// https://docs.spring.io/spring-session/reference/spring-security.html#spring-security-concurrent-sessions - -@Configuration -internal class SessionRegistryConfig( - private val sessionRepository: FindByIndexNameSessionRepository -) { - - @Bean - fun sessionRegistry(): SpringSessionBackedSessionRegistry { - return SpringSessionBackedSessionRegistry(sessionRepository) - } - -} - -/**********************************************************************************************************************/ -/**************************************************** 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 6160be8..0000000 --- a/Spring BFF/auth/requestcache/CustomRequestCache.kt +++ /dev/null @@ -1,52 +0,0 @@ -package com.example.authorizationserver.auth.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/roles/RoleAuthConfig.kt b/Spring BFF/auth/roles/RoleAuthConfig.kt deleted file mode 100644 index 97b537a..0000000 --- a/Spring BFF/auth/roles/RoleAuthConfig.kt +++ /dev/null @@ -1,72 +0,0 @@ -package com.example.authorizationserver.auth.roles - -import com.example.authorizationserver.api.enums.AuthTypes -import com.example.authorizationserver.api.enums.RoleTypes -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.security.core.GrantedAuthority -import org.springframework.security.core.authority.SimpleGrantedAuthority - -/**********************************************************************************************************************/ -/******************************************************* CONFIGURATION ************************************************/ -/**********************************************************************************************************************/ - -@Configuration -internal class RoleAuthConfig { - - // data class - authorities - data class Auth(val name: AuthTypes) - - // data class - roles - data class Role( - val name: RoleTypes, - val auths: Collection - ) - - // authorities - final val postAuth = Auth(AuthTypes.AUTH_POST) - final val getAuth = Auth(AuthTypes.AUTH_GET) - final val putAuth = Auth(AuthTypes.AUTH_PUT) - final val patchAuth = Auth(AuthTypes.AUTH_PATCH) - final val deleteAuth = Auth(AuthTypes.AUTH_DELETE) - - // define a role-authority mapping - val roleAuthorityMapping = mapOf( - RoleTypes.ROLE_USER to listOf(postAuth, getAuth, putAuth, patchAuth, deleteAuth), - RoleTypes.ROLE_ADMIN to listOf(postAuth, getAuth, putAuth, patchAuth, deleteAuth) - ) - - @Bean - // generate authorities from roles - fun getAuthorities(roles: List): Collection { - val authorities = mutableSetOf() - for (role in roles) { - // add the role itself as a GrantedAuthority - if (role?.name != null && role.name.isNotEmpty()) { - authorities.add(SimpleGrantedAuthority(role.name)) - } else { - // handle cases where role name is null or empty - println("Warning: Role name is null or empty for role $role") - } - - // add all the auths associated with the role as GrantedAuthorities - roleAuthorityMapping.get(role)?.let { auths -> - for (auth in auths) { - val authorityName = auth.name.toDisplayName() - if (authorityName.isNotEmpty()) { - authorities.add(SimpleGrantedAuthority(authorityName)) - } else { - // handle cases where authority name is null or empty - println("Warning: Authority name is null or empty for authority $auth") - } - } - } - } - return authorities - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/sessions/CustomCsrfAuthenticationStrategy.kt b/Spring BFF/auth/sessions/CustomCsrfAuthenticationStrategy.kt deleted file mode 100644 index 682342d..0000000 --- a/Spring BFF/auth/sessions/CustomCsrfAuthenticationStrategy.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.example.authorizationserver.auth.sessions - -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse -import org.springframework.security.core.Authentication -import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy -import org.springframework.security.web.csrf.CsrfAuthenticationStrategy -import org.springframework.security.web.csrf.CsrfTokenRepository -import org.springframework.stereotype.Component - -/**********************************************************************************************************************/ -/****************************************************** SESSION STRATEGY **********************************************/ -/**********************************************************************************************************************/ - -@Component -class CustomCsrfAuthenticationStrategy( - csrfTokenRepository: CsrfTokenRepository -) : SessionAuthenticationStrategy { - - private val delegate = CsrfAuthenticationStrategy(csrfTokenRepository) - - override fun onAuthentication( - authentication: Authentication?, - request: HttpServletRequest?, - response: HttpServletResponse? - ) { - - // delegate to the original CsrfAuthenticationStrategy - delegate.onAuthentication(authentication, 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 4ed7763..0000000 --- a/Spring BFF/auth/sessions/CustomInvalidSessionStrategy.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.example.authorizationserver.auth.sessions - -import jakarta.servlet.http.Cookie -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse -import jakarta.servlet.http.HttpSession -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) { - - // clear authentication object - val auth = SecurityContextHolder.getContext().authentication - if (auth != null) { - SecurityContextLogoutHandler().logout(request, response, auth) - } - - // retrieve the existing session or return if it doesn't exist - val session: HttpSession? = request.getSession(false) - - // delete cookies - val sessionCookieConfig = session?.servletContext?.sessionCookieConfig - - // create a new cookie with the same name as the session cookie but with maxAge set to 0 - val deleteCookie = Cookie(sessionCookieConfig?.name ?: "AUTH-SESSIONID", null).apply { - isHttpOnly = sessionCookieConfig?.isHttpOnly ?: true - maxAge = 0 // session age is 0! - secure = sessionCookieConfig?.isSecure ?: false - path = sessionCookieConfig?.path ?: "/" - } - - // add the cookie to the response to delete it - response.addCookie(deleteCookie) - - // 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/CustomRedisSessionMapper.kt b/Spring BFF/auth/sessions/CustomRedisSessionMapper.kt deleted file mode 100644 index be4df55..0000000 --- a/Spring BFF/auth/sessions/CustomRedisSessionMapper.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.example.authorizationserver.auth.sessions - -import org.springframework.context.annotation.Configuration -import org.springframework.session.MapSession -import org.springframework.session.data.redis.RedisIndexedSessionRepository -import org.springframework.session.data.redis.RedisSessionMapper -import java.util.function.BiFunction - -/**********************************************************************************************************************/ -/************************************************ REDIS CONFIGURATION *************************************************/ -/**********************************************************************************************************************/ - -// more here: -// https://docs.spring.io/spring-session/reference/configuration/redis.html#configuring-redis-session-mapper - -@Configuration -internal class CustomRedisSessionMapper( - private val sessionRepository: RedisIndexedSessionRepository -): BiFunction, MapSession?>{ - - private val delegate = RedisSessionMapper() - - /** - * Custom session mapper that delegates to the default RedisSessionMapper. - * If an exception occurs, the session is deleted from Redis. - */ - override fun apply(sessionId: String, map: Map): MapSession? { - return try { - delegate.apply(sessionId, map) - } catch (ex: IllegalStateException) { - sessionRepository.deleteById(sessionId) - null - } - } -} - -/**********************************************************************************************************************/ -/**************************************************** 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 bfa8dbe..0000000 --- a/Spring BFF/auth/sessions/CustomSessionAuthenticationStrategy.kt +++ /dev/null @@ -1,92 +0,0 @@ -package com.example.authorizationserver.auth.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.session.Session -import org.springframework.session.data.redis.ReactiveRedisIndexedSessionRepository.RedisSession -import org.springframework.session.security.SpringSessionBackedSessionRegistry -import org.springframework.util.Assert - -/**********************************************************************************************************************/ -/****************************************************** SESSION STRATEGY **********************************************/ -/**********************************************************************************************************************/ - -@Configuration -internal class CustomSessionAuthenticationStrategy( - private val sessionRegistry: SpringSessionBackedSessionRegistry -) : 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/sessions/CustomSessionIdGenerator.kt b/Spring BFF/auth/sessions/CustomSessionIdGenerator.kt deleted file mode 100644 index b20695c..0000000 --- a/Spring BFF/auth/sessions/CustomSessionIdGenerator.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.example.authorizationserver.auth.sessions - -import org.springframework.session.SessionIdGenerator - -/**********************************************************************************************************************/ -/************************************************ SESSION ID GENERATOR ************************************************/ -/**********************************************************************************************************************/ - -// more here: -// https://docs.spring.io/spring-session/reference/configuration/common.html#changing-how-session-ids-are-generated - -internal class CustomSessionIdGenerator : SessionIdGenerator { - - override fun generate(): String { - // use a UUID with a custom prefix or other unique generation logic - return "IN-HOUSE-AUTH-SERVER-${java.util.UUID.randomUUID()}" - } - -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/sessions/SessionApplicationInitialiser.kt b/Spring BFF/auth/sessions/SessionApplicationInitialiser.kt deleted file mode 100644 index 7045609..0000000 --- a/Spring BFF/auth/sessions/SessionApplicationInitialiser.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.example.authorizationserver.auth.sessions - -import com.example.authorizationserver.auth.redis.RedisConnectionFactoryConfig -import org.springframework.context.annotation.Configuration -import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer - -/**********************************************************************************************************************/ -/************************************************ REDIS CONFIGURATION *************************************************/ -/**********************************************************************************************************************/ - -// more here: -// https://docs.spring.io/spring-session/reference/http-session.html#httpsession-redis-jc -// https://docs.spring.io/spring-session/reference/http-session.html#_servlet_container_initialization_2 - -@Configuration -internal class SessionApplicationInitialiser - : AbstractHttpSessionApplicationInitializer(RedisConnectionFactoryConfig::class.java) - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/sessions/SessionEventHttpSessionListenerAdapter.kt b/Spring BFF/auth/sessions/SessionEventHttpSessionListenerAdapter.kt deleted file mode 100644 index 2b0a7bb..0000000 --- a/Spring BFF/auth/sessions/SessionEventHttpSessionListenerAdapter.kt +++ /dev/null @@ -1,113 +0,0 @@ -package com.example.authorizationserver.auth.sessions - -import jakarta.servlet.http.HttpSessionEvent -import jakarta.servlet.http.HttpSessionListener -import org.springframework.context.event.EventListener -import org.springframework.security.web.session.HttpSessionEventPublisher -import org.springframework.session.events.SessionCreatedEvent -import org.springframework.session.events.SessionDeletedEvent -import org.springframework.session.events.SessionDestroyedEvent -import org.springframework.session.events.SessionExpiredEvent -import org.springframework.session.web.http.SessionEventHttpSessionListenerAdapter -import org.springframework.context.annotation.Bean -import org.springframework.stereotype.Component - -/**********************************************************************************************************************/ -/************************************************ SESSION CONFIGURATION ***********************************************/ -/**********************************************************************************************************************/ - -// more here: -// https://docs.spring.io/spring-session/reference/configuration/redis.html#listening-session-events -// https://docs.spring.io/spring-session/reference/http-session.html#httpsession-httpsessionlistener - -@Component -// session event listener -internal class SessionListenerConfig() { - - @Bean - // for publishing session lifecycle events, to enable application to respond to such events - fun httpSessionEventPublisher(): HttpSessionEventPublisher { - return HttpSessionEventPublisher() - } - - // define individual HttpSessionListener beans - @Bean - fun sessionCreatedListener(): HttpSessionListener { - return object : HttpSessionListener { - override fun sessionCreated(event: HttpSessionEvent) { - println("Session created: ${event.session.id}") - } - - override fun sessionDestroyed(event: HttpSessionEvent) { - println("Session destroyed: ${event.session.id}") - } - } - } - - @Bean - fun sessionDeletedListener(): HttpSessionListener { - return object : HttpSessionListener { - override fun sessionCreated(event: HttpSessionEvent) { - println("Session deleted event - Session created: ${event.session.id}") - } - - override fun sessionDestroyed(event: HttpSessionEvent) { - println("Session deleted event - Session destroyed: ${event.session.id}") - } - } - } - - @Bean - fun sessionDestroyedListener(): HttpSessionListener { - return object : HttpSessionListener { - override fun sessionCreated(event: HttpSessionEvent) { - println("Session destroyed event - Session created: ${event.session.id}") - } - - override fun sessionDestroyed(event: HttpSessionEvent) { - println("Session destroyed event - Session destroyed: ${event.session.id}") - } - } - } - - @Bean - fun sessionExpiredListener(): HttpSessionListener { - return object : HttpSessionListener { - override fun sessionCreated(event: HttpSessionEvent) { - println("Session expired event - Session created: ${event.session.id}") - } - - override fun sessionDestroyed(event: HttpSessionEvent) { - println("Session expired event - Session destroyed: ${event.session.id}") - } - } - } - - // Create a list of all listeners and inject it into the SessionEventHttpSessionListenerAdapter - @Bean - fun httpSessionListeners( - sessionCreatedListener: HttpSessionListener, - sessionDeletedListener: HttpSessionListener, - sessionDestroyedListener: HttpSessionListener, - sessionExpiredListener: HttpSessionListener - ): List { - return listOf( - sessionCreatedListener, - sessionDeletedListener, - sessionDestroyedListener, - sessionExpiredListener - ) - } - - // configure SessionEventHttpSessionListenerAdapter with the list of listeners - @Bean - fun sessionEventHttpSessionListenerAdapter( - httpSessionListeners: List - ): SessionEventHttpSessionListenerAdapter { - return SessionEventHttpSessionListenerAdapter(httpSessionListeners) - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/sessions/SessionManagementService.kt b/Spring BFF/auth/sessions/SessionManagementService.kt deleted file mode 100644 index 0f21b7a..0000000 --- a/Spring BFF/auth/sessions/SessionManagementService.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.example.authorizationserver.auth.sessions - -import org.springframework.data.redis.connection.RedisConnectionFactory -import org.springframework.data.redis.core.RedisTemplate -import org.springframework.session.FindByIndexNameSessionRepository -import org.springframework.session.Session -import org.springframework.context.annotation.Bean -import org.springframework.data.redis.core.RedisOperations -import org.springframework.session.data.redis.ReactiveRedisIndexedSessionRepository -import org.springframework.session.data.redis.ReactiveRedisIndexedSessionRepository.RedisSession -import org.springframework.session.data.redis.RedisIndexedSessionRepository -import org.springframework.stereotype.Service -import java.security.Principal - -/**********************************************************************************************************************/ -/************************************************ SESSION CONFIGURATION ***********************************************/ -/**********************************************************************************************************************/ - -// more here: -// https://docs.spring.io/spring-session/reference/configuration/redis.html#finding-all-user-sessions - -@Service -internal class SessionManagementService( - private val sessions: FindByIndexNameSessionRepository -) { - - fun getSessions(principal: Principal): Collection { - // Retrieve all sessions for a specific user - val userSessions = sessions.findByPrincipalName(principal.name).values - return userSessions - } - - fun removeSession(principal: Principal, sessionIdToDelete: String) { - // Retrieve all session IDs for a specific user - val userSessionIds = sessions.findByPrincipalName(principal.name).keys - if (userSessionIds.contains(sessionIdToDelete)) { - // Remove the specific session - sessions.deleteById(sessionIdToDelete) - } - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ \ No newline at end of file diff --git a/Spring BFF/auth/sessions/SessionRememberMe.kt b/Spring BFF/auth/sessions/SessionRememberMe.kt deleted file mode 100644 index c919c84..0000000 --- a/Spring BFF/auth/sessions/SessionRememberMe.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.example.authorizationserver.auth.sessions - -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices - -/**********************************************************************************************************************/ -/***************************************************** REPOSITORY *****************************************************/ -/**********************************************************************************************************************/ - -@Configuration -internal class SessionRememberMeConfig() { - - @Bean - fun rememberMeServices(): SpringSessionRememberMeServices { - val rememberMeServices = - SpringSessionRememberMeServices() - - // optionally customize - rememberMeServices.setAlwaysRemember(true) - rememberMeServices.setRememberMeParameterName("remember-me") - rememberMeServices.setValiditySeconds(57600) // set to 16 hours - - return rememberMeServices - } -} - -/**********************************************************************************************************************/ -/**************************************************** END OF KOTLIN ***************************************************/ -/**********************************************************************************************************************/ diff --git a/Spring BFF/auth/tokens/OAuth2TokenCustomiserJwtEncoding.kt b/Spring BFF/auth/tokens/OAuth2TokenCustomiserJwtEncoding.kt deleted file mode 100644 index 1497f3c..0000000 --- a/Spring BFF/auth/tokens/OAuth2TokenCustomiserJwtEncoding.kt +++ /dev/null @@ -1,99 +0,0 @@ -package com.example.authorizationserver.auth.tokens - -import com.example.authorizationserver.auth.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) - - // Convert JwtClaimsSet.Builder to JwtClaimsSet to access claims - val claimsSet = context.claims.build() - - // Print each claim to the console - claimsSet.claims.forEach { (key, 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 344926b..0000000 --- a/Spring BFF/auth/tokens/OAuth2TokenCustomiserOAuth2Claims.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.example.authorizationserver.auth.tokens - -import com.example.authorizationserver.auth.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 1ace893..0000000 --- a/Spring BFF/auth/tokens/TokenCustomiserConfig.kt +++ /dev/null @@ -1,85 +0,0 @@ -package com.example.authorizationserver.auth.tokens - -import com.example.authorizationserver.auth.objects.user.CustomOidcUser -import com.example.authorizationserver.auth.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/docdb/DocDbUserDetailsManager.kt b/Spring BFF/auth/userservice/docdb/DocDbUserDetailsManager.kt deleted file mode 100644 index bb4662e..0000000 --- a/Spring BFF/auth/userservice/docdb/DocDbUserDetailsManager.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.example.authorizationserver.auth.userservice.docdb - -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/docdb/DocDbUserDetailsManagerImpl.kt b/Spring BFF/auth/userservice/docdb/DocDbUserDetailsManagerImpl.kt deleted file mode 100644 index dbea52c..0000000 --- a/Spring BFF/auth/userservice/docdb/DocDbUserDetailsManagerImpl.kt +++ /dev/null @@ -1,119 +0,0 @@ -package com.example.authorizationserver.auth.userservice.docdb - -import com.example.authorizationserver.api.entities.user.UserEntity -import com.example.authorizationserver.auth.objects.user.DocDbUser -import com.example.authorizationserver.auth.roles.RoleAuthConfig -import com.example.authorizationserver.auth.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/oidc/OidcUserDetailsService.kt b/Spring BFF/auth/userservice/oidc/OidcUserDetailsService.kt deleted file mode 100644 index 91cf3b3..0000000 --- a/Spring BFF/auth/userservice/oidc/OidcUserDetailsService.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.example.authorizationserver.auth.userservice.oidc - -import com.example.authorizationserver.api.entities.user.UserEntity -import com.example.authorizationserver.auth.userservice.oidc.oidcmappers.OidcUserMapper -import com.example.authorizationserver.auth.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/oidc/oidcmappers/GoogleOidcUserMapper.kt b/Spring BFF/auth/userservice/oidc/oidcmappers/GoogleOidcUserMapper.kt deleted file mode 100644 index f8fe749..0000000 --- a/Spring BFF/auth/userservice/oidc/oidcmappers/GoogleOidcUserMapper.kt +++ /dev/null @@ -1,73 +0,0 @@ -package com.example.authorizationserver.auth.userservice.oidc.oidcmappers - -import com.example.authorizationserver.api.entities.user.UserEntity -import com.example.authorizationserver.auth.objects.user.CustomOidcUser -import com.example.authorizationserver.auth.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/oidc/oidcmappers/OidcMapper.kt b/Spring BFF/auth/userservice/oidc/oidcmappers/OidcMapper.kt deleted file mode 100644 index 8eee6a2..0000000 --- a/Spring BFF/auth/userservice/oidc/oidcmappers/OidcMapper.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.example.authorizationserver.auth.userservice.oidc.oidcmappers - -import com.example.authorizationserver.api.entities.user.UserEntity -import com.example.authorizationserver.auth.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 f48c59b..0000000 --- a/Spring BFF/auth/virtualthreads/VirtualThreadsManager.kt +++ /dev/null @@ -1,66 +0,0 @@ -package com.example.authorizationserver.auth.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