I’m passing form Angular to Spring Security (an OAuthClient) some header parameters.
They are saved as attributes to the session, but when I try to read them from the session, it gives null (which makes me think the session is not being persisted)
(I use an Authorization Grant Flow (with PKCE) between the OAuthClient and an Auth Server.)
Here is are the server logs:
SESSION SUCCESS ATTRIBUTE SET: http://localhost:7080/angular-ui/login
SESSION FAILURE ATTRIBUTE SET: http://localhost:7080/angular-ui/login-error
RUNNING REDIRECT STRATEGY: 302 FOUND
SESSION FAILURE ATTRIBUTE SET: null
ON FAILURE REDIRECT URI: /
RUNNING REDIRECT STRATEGY: 302 FOUND
GitHub repository
I have 49 configuration files that can be found here:
Github – BFF Server Repository
Security chain
Here is my security chain
@Configuration
@EnableWebSecurity
//@EnableRedisHttpSession( )
internal class DefaultSecurityConfig () {
@Autowired
private lateinit var servletClientRegistrationRepository: ClientRegistrationRepository
@Autowired
private lateinit var servletAuthorizedClientRepository: OAuth2AuthorizedClientRepository
@Autowired
private lateinit var servletAuthorizedClientService: OAuth2AuthorizedClientService
@Bean
@Order(2)
@Throws(Exception::class)
/* security filter chain for authentication & authorization */
fun defaultSecurityFilterChain(
http: HttpSecurity,
customServletCsrfTokenRepository : CustomServletCsrfTokenRepository,
customCsrfAuthenticationStrategy: CustomCsrfAuthenticationStrategy,
csrfProtectionMatcher: CsrfProtectionMatcher,
// sessionRememberMeServices: SpringSessionRememberMeServices,
socialLoginSuccessHandler: SocialLoginSuccessHandler,
docDbAuthenticationFilter: DocDbAuthenticationFilter,
servletRequestCache: ServletRequestCache,
customSecurityContextRepository: SecurityContextRepository,
sessionProperties: SessionProperties,
customInvalidSessionStrategy: CustomInvalidSessionStrategy,
customSessionAuthenticationStrategy: CustomSessionAuthenticationStrategy,
// redisRememberMeTokenRepository: RedisRememberMeTokenRepository,
logoutProperties: LogoutProperties,
accessDeniedHandler: DefaultAccessDeniedHandler,
): SecurityFilterChain {
// enable csrf
http.csrf { csrf ->
csrf.csrfTokenRepository(customServletCsrfTokenRepository)
csrf.sessionAuthenticationStrategy(customCsrfAuthenticationStrategy)
csrf.requireCsrfProtectionMatcher(csrfProtectionMatcher)
}
// 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(securityProperties.rememberMeKey)
// 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(servletRequestCache)
}
// 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)
oauth.authorizedClientRepository(servletAuthorizedClientRepository)
oauth.authorizedClientService(servletAuthorizedClientService)
oauth.successHandler(socialLoginSuccessHandler)
}
// apply DocDb authentication filter
http.addFilterBefore(
docDbAuthenticationFilter,
UsernamePasswordAuthenticationFilter::class.java
)
// authorizations (lock all endpoints apart from)
http.authorizeHttpRequests { authorize ->
// login endpoint
authorize.requestMatchers("/login/**").permitAll()
// logout endpoint
authorize.requestMatchers("/logout/**").permitAll()
// authorization endpoints
authorize.requestMatchers("/oauth2/**").permitAll()
// userinfo endpoint
authorize.requestMatchers("/userinfo").permitAll()
// logout endpoint
authorize.requestMatchers("/connect/logout").permitAll()
// all other endpoints
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(logoutProperties.LOGOUT_URL)
logout.invalidateHttpSession(logoutProperties.INVALIDATE_HTTP_SESSION)
logout.clearAuthentication(logoutProperties.CLEAR_AUTHENTICATION)
logout.deleteCookies(sessionProperties.SESSION_COOKIE_NAME)
logout.addLogoutHandler(HeaderWriterLogoutHandler(ClearSiteDataHeaderWriter(COOKIES)))
logout.permitAll()
}
// unauthorized exception handler
http.exceptionHandling { exceptionHandling ->
exceptionHandling.accessDeniedHandler(accessDeniedHandler)
}
return http.build()
}
}
Relevant files:
The relevant files, I believe, from the repository, are probably:
-
Session Registry
-
The OAuth2 Request Resolver
-
OAuth2 Failure Handler
-
OAuth2 Success Handler
-
I’ve turned the Redis Repository off RedisSessionRepository, so am assuming the default one is used?
I can’t think of anything else related to session. Spring session is not enabled, so it should just use the default…
… Can someone help?