How can I prevent RequestCache from being overriden - spring

I am implementing multi-factor authentication using Spring Authorization Server (OAuth 2.0). Essentially, I have three endpoints:
/login
/verify-otp
/oauth2/authorize?{oauth_params} (default Spring Authorization Server endpoint)
When a user attempts to log in, they are redirected to /oauth2/authorize with the required parameters. Spring Authorization Server checks whether the user has been authenticated. If not, the user is redirected to another endpoint, /login. At this point, the RequestCache caches the requested parameters from the oauth2 endpoint.
Everything works fine unless a user who has been redirected to the login page tries to access the /verify-otp endpoint without being authenticated. In this case, the RequestCache will cache the requested params from /verify-otp and redirect a user to /login endpoint again, which means that the oauth2 cached params will be overridden. As a result, when the user tries to log in with OTP again, they will not be redirected to the OAuth redirect URI.
Is there a way to prevent RequestCache from being overriden or any better solutions.

I have an mfa-sample branch with an mfa-authorizationserver sample that demonstrates a working MFA setup.
Note: It is an older branch and is not up to date with 1.0 (main).
It is based on Spring Security mfa sample.
Currently, Spring Security does not have official MFA support, so it is a bit tricky to get right.
The key elements are setting up a custom TrustResolver and authorization rules that allow access based on the state the user is in while they are going through the login flow.
The state the user is in during the login flow can be changed by setting up a new SecurityContext in the AuthenticationSuccessHandler and each custom #Controller endpoint during each step of the flow.
Take a look at the sample. One thing to watch out for is my branch is based on Spring Security 5.7, which automatically persists a SecurityContext when it is set on the SecurityContextHolder. If you start with Spring Boot 3, you'll be using Spring Security 6, which requires the SecurityContext to be saved explicitly (e.g. securityContextRepository.save(securityContext);).
(I'd like to add more links to important files in my sample branch and the official Spring Security sample, but as I type this GitHub is down on a Friday night... so I'm gonna go do something fun instead of repeatedly refresh waiting for the 500s to stop. Cheers!)

Related

SpringBoot command-line application with OAuth2

I'm working on a SpringBootApplication that implements CommandLineRunner. We are usign keycloak as our OAuth2 provider with a public client.
We would like to trigger SSO when someone uses the build from a CLI.
ie.
$ sampleclitool dosomething
... Redirecting to SSO... waiting for access token... etc..
... SOME_USER_NAME is logged in.
... Doing something!
Ive been using Spring Security in other microservices and am trying to figure out how to follow the same "flow".
Use the CLI (any command).
Check if user is authenticated.
If user is not authenticated, open SSO authentication in default browser.
If user is authenticated, continue.
CLI makes requests to other services (microservices, hosted by me).
Authorization header (JWT) is attached to those requests.
The exact trigger for auth isn't important to me, but the end result is that who ever is using the CLI can login to it from the browser, then make request to protected services.
I cannot for the life of me, without some selenium integration, think of a way to achieve this flow. I'm not sure if there are some clever mechanisms in Spring Security that I can hook into.
Using SpringBoot 3.0.1 and WebFlux.

Add additional inner user validation after successful OAuth2 Resource Server JWT check at Keycloak

There is a Spring boot app with endpoints protected with JWT. Token validation is performed by Spring boot OAuth2 Resource Server that checks tokens at Keycloak Authorization Server.
How can additional inner user validation be added to the app after it successfully passes authorization at Keycloak?
So I'd like to build some kind of a chain - if token passes validation at Auth Server then I check the username taken from JWT at local database.
Checking access-token claims against local database for access-control on a resource-server is an easy task inside authentication converters (http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(...) or http.oauth2ResourceServer().opaqueToken().authenticationConverter(...), but this is very inefficient: it is much better to have this DB access once when the token is created on authorization-server, rather than each time it is evaluated during resource-server authorization process (which happens for each request).
All the data required for access-control decisions should be included in the token already. If you need more than standard claims plus the default private claims from your authorization-server, then configure this authorization-server to add the data you need about the user when issuing access-tokens. For Keycloak, this is done with so called "OIDC protocol mappers". Those can issue DB requests, web-service calls and about anything. I have a sample of a mapper adding a private claim with a value from a web-service call in this project.
Once all the data you need is in the token, you just use it as normal in Spring security expressions of your resource-server. Here is a working sample taken from my set of tutorials:
#PreAuthorize("is(#username) or isNice() or onBehalfOf(#username).can('greet')")
In this expression, it is checked that the user either:
is greeting himself (username #PathVariable is equal to preferred_username claim in access-token)
has one of "nice" roles
has permission to greet on behalf of user with preferred_username equal to username #PathVariable (the route is /greet/{username} and this permissions delegation is taken from a private claim added by a mapper like the one in the sample linked above)

Spring Security and OneLogin Token Expiration

I am trying to configure an authentication flow in Spring Boot using OneLogin SSO. I can successfully authenticate, create a JWT token, and redirect to my frontend app.
However, I am not certain of the next steps. When my JWT token expires, is the appropriate course to clear my security context and then to redirect to OneLogin again and reconfirm my authentication? Right now, as far as I can tell, Spring's security context represents one moment in time and I can't figure out how to refresh it against my SSO provider to ensure the user is still authenticated.

Can the Spring Boot + Spring Security Keycloak adapters automatically refresh the access token contained in the HttpSession on token expiration?

I am using Keycloak to provide SSO through OIDC for a bunch of applications that belong to the same realm. All of these applications are confidential clients that use the Authorization Code flow. They use JSP for the views, and all necessary redirects are managed by Spring Boot and Spring Security Keycloak adapters.
After successfully logging in I can switch from one application to another correctly (SSO). For each of them, an HttpSession is generated containing a org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken. This class, has a details object (SimpleKeycloakAccount) with a securityContext (RefreshableKeycloakSecurityContext) that contains the access token (tokenString), id token (idTokenString) and refresh token (refreshTokenString):
The contained access token has a 5 minute expiration time. Oddly enough, after this time has passed, although I'm still correctly authenticated in the Spring Boot application, I've checked that the access token is never refreshed.
I need to have a valid access token, since some of these applications invoke REST services, secured with the same adapters with bearer only authentication. The problem is I end up having an expired access token and have to deal (manually?) with its expiration.
Is there a way to make the adapter refresh the access token when it expires or are we expected to do so programmatically?
Can you show how to do it?

Spring Security with SAML Token for REST Service

I'm looking for a simple example of a spring security configuration (Java config preferred) on how I can secure my REST Services with Spring-Security and SAML.
There's an Web Application Firewall in front which will only pass requests which contain a valid SAML Token or otherwise redirects to IDP to get one. So I don't have to look if the user is logged in or redirect the user if not so to the IDP.
The only thing I'll need to do is allow only authenticated requests to all REST Services, read the user from SAML-Token and check that the Token is from Airlock.
Later I'll need to add ACL support for more fine granular rights of the user on specific services but I'm already lost with the first part of the integration work in spring security. Any help would be welcome :)
the magic happens here: https://github.com/spring-projects/spring-security-saml/blob/master/core/src/main/java/org/springframework/security/saml/SAMLProcessingFilter.java
in attemptAuthentication(), it gets the SAML message, parse it and gets the token (SAMLAuthenticationToken). Then it tries to authenticate the user: authenticate(token);

Resources