I want to force the client to reauthenticate if the login_hint or acr_values parameters changes. So far we have configured Spring Authorization Server as a "proxy" for other IdPs, i.e. if login_hint points to one specific IdP, this is the one that the auth server redirects to. This is all managed in our custom AuthenticationEntryPoint class.
This model works great, but not if the authenticated client changes login_hint to point to another IdP. What we want to happen then, is that the authorization server forces reauthentication.
I tried to do this in a custom validator, which implements Consumer<OAuth2AuthorizationCodeRequestAuthenticationContext>
. I'm able to fetch the loginHint value this way:
authorizationCodeRequestAuthentication.getAdditionalParameters().get("login_hint");
I'm also able to check which IdP the client used during last authentication, because this is stored as a parameter in the OidcUser object. So this is what I tried, which does not work. I'm only sent back to the client with the last authentication even though I clear the authentication:
if (!loginHint.equals(oidcUser.getAuthMethod())) {
authentication.setAuthenticated(false);
SecurityContextHolder.clearContext();
SecurityContextHolder.getContext().setAuthentication(null);
}
I also tried to throw an AccessDeniedException in case this invoked our AuthenticationEntryPoint class, but I was only sent back to the client with an error.
I even tried to do similar things in our custom authenticationSuccessHandler where we have access to HttpServletResponse
and HttpServletRequest
. Then I injected our AuthenticationEntryPoint class and called the commence
method. This worked somehow, but I was not sent back to the client after authentication, but to the auth server instead.
I had to create my own authorizationRequestConverter
(pre-processor) by copying the default OAuth2AuthorizationCodeRequestAuthenticationConverter
. Here I have access to HttpServletRequest
to fetch the session. I also created a constructor that takes a SessionRegistry
param.
This is how I detect the changes and invalidate the session. If the user tries to authenticate with a higher security level (changes the acr_value to a higher level), he/she must re-authenticate.
Authentication principal = SecurityContextHolder.getContext().getAuthentication();
if (principal == null) {
principal = ANONYMOUS_AUTHENTICATION;
} else {
var oidcUser = (CustomizedOidcUser) principal.getPrincipal();
String currentAuthProvider = oidcUser.getAuthMethod();
Integer currentSecurityLevel = oidcUser.getSecurityLevel();
if (isNewAuthenticationProvider(loginHint, currentAuthProvider)) {
invalidateSession(request, registry, principal);
}
if (requiresHigherSecurityLevel(acr, loginHint, currentSecurityLevel)) {
invalidateSession(request, registry, principal);
}
}