Swagger-ui Spring Security and OAuth2 project Logout button doesn't clean Session cookies - spring

I am working for microservice (rest API) with Spring boot, security and OAuth2 project with swagger 2.
Although it's a Rest service project but it creates a session cookie when a user login and after logout cookie should be removed and when any user tries to access the APIs need to put an access token again but the cookie remains the same.
So the same users can access API again without login after refreshing.

Solution:
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
add this line on WebSecurityConfigurerAdapter bean It's work for me.
OR
For MVC:
.and()
.logout().clearAuthentication(true)
.logoutSuccessUrl("/")
.deleteCookies("JSESSIONID","remember-me")
.invalidateHttpSession(true)
.and()

Related

Spring Security: how to recognize, in a public page, that a user is authenticated

I have a simple Spring Boot web application consisting of 2 pages:
a Home Page (freely accessible) at the url https://example.com/
a secured page (requires login for being accessed) at the url https://example.com/secure/page.html
In the Home Page I'm printing the First Name of the visiting user (if he/she is already authenticated) or a sentence saying that the page is visited by an anonymous user.
I'm using Keycloak as far as authentication is concerned.
Here the Spring Security configuration:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/secure/**")
.authenticated()
.and()
.csrf().requireCsrfProtectionMatcher(keycloakCsrfRequestMatcher())
.and()
.sessionManagement()
.sessionAuthenticationStrategy(sessionAuthenticationStrategy())
.and()
.addFilterBefore(keycloakPreAuthActionsFilter(), LogoutFilter.class)
.addFilterBefore(keycloakAuthenticationProcessingFilter(), BasicAuthenticationFilter.class)
.addFilterBefore(keycloakAuthenticatedActionsFilter(), BasicAuthenticationFilter.class)
.addFilterAfter(keycloakSecurityContextRequestFilter(), SecurityContextHolderAwareRequestFilter.class)
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
.and()
.logout()
.addLogoutHandler(keycloakLogoutHandler())
.logoutUrl("/sso/logout").permitAll()
.logoutSuccessUrl("/");
}
If the user is already authenticated, the problem is that the Home Page says he is anonymous because the Principal is always null.
But if the user enters the secured page (and Keycloak lets him in because he's already authenticated) when he comes back to the Home, the page contains - correctly - his First Name.
Where is my configuration wrong?
It seems that Spring Security doesn't check the authentication on non secured pages. Is there a way to tell Spring Security to check every page (both secured and non-secured)?
Thanks in advance for your support.
The solution to this problem is to add /** to security context/handling (with permitAll()).
The art is to do it correctly:
Multiple antMatchers in Spring security (First ant matcher wins!!, https://www.google.com/search?q=spring+security+permitall+not+working)
http://blog.florian-hopf.de/2017/08/spring-security.html
So in this case:
http
.authorizeRequests()
.antMatchers("/secure/**").authenticated()
.antMatchers("/**").pernmitAll()
.and()...
...should fill the (anonymous) Principal also in "permitted area" (i.e. /**(!) ...and leave secure/** restricted!;).
To the core/title question (once Principal is filled), i think the answer is already given:
here (verbally): https://stackoverflow.com/a/26117007/592355
and here(with code): https://stackoverflow.com/a/57054816/592355
..if you use Spring Security (JSP) Taglibs isAnonymous() is handy, and otherwise (in default) you just need to check for hasRole('ROLE_ANONYMOUS') (Ref)

Spring SAML SSO with OKTA - InResponseTo when changing web app context

We're having a lot of trouble with OKTA SAML SSO integration with Spring Security. We're using the saml-dsl extension to Spring Security to configure the auth, and everything works fine on HTTP, however when we try to use HTTPS the authentication only works when the app is deployed on root (/) context. When we change the context to anything else, it stops working and starts throwing InResponseTo field errors and sometimes with different configurations it comes to a redirect loop.
Here's the configuration we're using:
http
.csrf()
.disable();
http
.sessionManagement().sessionFixation().none();
http
.logout()
.logoutSuccessUrl("/");
http
.authorizeRequests()
.antMatchers("/saml*").permitAll()
.anyRequest().authenticated()
.and()
.apply(samlConfigurer())
.serviceProvider()
.keyStore()
.storeFilePath(config.getKeystorePath())
.password(config.getKeystorePassword())
.keyname(config.getKeyAlias())
.keyPassword(config.getKeystorePassword())
.and()
.protocol("https")
.hostname(String.format("%s:%s", serverURL, config.getServerPort()))
.basePath("/"+contextRoot)
.and()
.identityProvider()
.metadataFilePath(config.getMetadataUrl());
And we should have our OKTA setup properly as well ( https://localhost:8443/ourappcontext/saml/SSO for testing, all the other stuff too )
We've tried most of the solutions proposed on here and the Spring documentation ( empty factory, spring session management and session fixation and so on ) and nothing seems to work. Are we doing something wrong? We're currently not generation any SP metadata, could it be that this is at fault and the request is somehow redirected to the wrong place or something? Really confused as of right now, first time using SAML and I'm not sure if it's the extension, the OKTA config or the Spring config...
We're deploying on Wildfly and you set the application context on there through a separate jboss-web.xml, if that matters at all.
By default the HttpSessionStorageFactory is used and this provides HttpSessionStorage SAML message store.
--> The HTTP session cookie is the browser side key to the server side SAML message store.
When the HTTP session cookie is not sent by the browser when the SAML response is delivered to Spring Security SAML SP, it can not find the related SAML AuthNRequest and fails to compare 'InResponseTo' value with 'ID' value of matching AuthNRequest.
If you can not assure HTTP session cookie is delivered you may implement your own SAMLMessageStorageFactory and SAMLMessageStorage (as I did).

How to check if user still logged in via azure sso (oAuth2), while using my own webapp?

I'm developing an web application with Spring Boot using Azure AD and OAuth2.0 for authentication to secure up the backend.
If I log-out via for example the Outlook Web App, my web application should register this process and logout as well (at least if I reload or reopen the page). How do i implement that? Now the Web-Application seems as still logged in. Unfortunately I did not find an approach to implement this behavior consistently. Only if I use the self-implemented log-out button, it shows the desired effect and the HttpSession gets invalidated and cookies where deleted.
I have already implemented a login and logout via Azure AD in my web application (see code). As soon as I log-out via the button of my own application, I am automatically logged out of other Azure applications (e.g. Outlook Web App) that require Azure SSO.
I already tried the #PreAuthorize Annotation discribed here Spring MVC - Checking if User is already logged in via Spring Security? but this seems not to be the solution.
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login()
.userInfoEndpoint()
.oidcUserService(oidcUserService);
http.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.clearAuthentication(true)
.logoutSuccessUrl("https://login.microsoftonline.com/common/oauth2/logout");
}
Redirect to main page:
#GetMapping("login/oauth2/code/azure")
public ModelAndView redirectToRoot(ModelMap modelMap) {
return new ModelAndView("redirect:/", modelMap);
}
I have never implemented this myself, but if I remember right, all OAuth2 providers have some kind of a SingleSignOut endpoint, if you call this in your logout method, it will log the user out from every app that is connected to this provider.
After refreshing the page of your webapp, the security should recognize that the user is then no longer logged in and redirect him to the login page.
Hope I could help you a bit. :)
Edit: I found this after a quick search: https://github.com/juanzero000/spring-boot-oauth2-sso .

Using SAML with Spring Boot behind an ELB redirects to http instead of https

I'm trying to use Okta to authenticate users from a SpringBoot application.
I've setup the app following the Okta Tutorial from : https://developer.okta.com/blog/2017/03/16/spring-boot-saml
However my app is behind an ELB, and as such the TLS is being terminated at the LB. So I've modified the configuration from the tutorial to suit my needs.
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/saml*").permitAll()
.anyRequest().authenticated()
.and()
.apply(saml())
.serviceProvider()
.keyStore()
.storeFilePath(this.keyStoreFilePath)
.password(this.password)
.keyname(this.keyAlias)
.keyPassword(this.password)
.and()
.protocol("https")
.hostname(String.format("%s", serverName))
.basePath("/")
.and()
.identityProvider()
.metadataFilePath(this.metadataUrl);
}
This does the trick but there is a problem. After the user is authenticated by Okta, the user is finally redirected to a http URL instead of a https URL. I am thinking the reason for this is that the TLS is being terminated at the LB and my app is actually receiving the request with http which is being sent in the RelayState.
This is something I found : spring-boot-security-saml-config-options.md.
It contains a list of SAML properties for spring boot security. I added the following to the application.properties file
saml.sso.context-provider.lb.enabled = true
saml.sso.context-provider.lb.scheme=https
saml.sso.profile-options.relay-state=<https://my.website.com>
It doesn't change the http redirection. Is there something I am doing wrong?
When a SAML 2.0 IdP like Okta redirects back to you application the endpoint url is either based on the SAML 2.0 metadata you application expose or the configuration in the IdP.
Furthermore, it is optional to add a Destination property in SAML 2.0 AuthnRequest:
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified"
Destination="https://my.website.com" IssueInstant="2018-11-22T09:23:08.844Z" Version="2.0" ID="id-f8ee3ab1-6745-42d5-b00f-7845b97fe953">
<Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion"> ... </Issuer>
...
</samlp:AuthnRequest>

Spring OAuth2 + Http basic redirection with token

I'm using OAuth2 Spring setup from official spring guide - full blown authorization server part.
There are two apps - separate authorization server with user resource server embedded and a client application - using JWT OAuth.
By default if you want to navigate to protected resource of the client app you get redirected to authorization server app where you can choose which authentication provider you'd like to use for the session. The problem is I want to support also local login mechanisms.
I managed to introduce a simple login form which just gets from /user resource with Basic authentication which works fine except there is no redirection back to the resource which initiated the process in the first place and no JWT token is being issued.
Normally I would get redirected with JWT token but I guess basic authentication doesn't even have authentication success handlers not to mention SavedRequestAwareAuthenticationSuccessHandler which OAuth2ClientAuthenticationProcessingFilter seems to be using after successfully logged in.
Here's my initial idea:
#Throws(Exception::class)
override fun configure(http: HttpSecurity) {
// .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
http.antMatcher("/**")
.httpBasic()
.authenticationEntryPoint(LoginUrlAuthenticationEntryPoint("/"))
.and()
.authorizeRequests()
.antMatchers("/", "/login**", "/webjars/**").permitAll()
.antMatchers("/registration/**").permitAll()
.antMatchers(HttpMethod.POST, "/auth/account/password/reset*/**").permitAll()
.anyRequest()
.authenticated()
.and()
.exceptionHandling()
.and().logout()
.logoutSuccessUrl("/").permitAll()
// .and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and().csrf().disable() // todo consider how to enable this only for parts of the service which is exposed to the web browser
.addFilterBefore(createClientFilter(), BasicAuthenticationFilter::class.java)
}
And somewhere at the end of the chain
val oldRedirectUrl = HttpSessionRequestCache().getRequest(request, response).redirectUrl
DefaultRedirectStrategy().sendRedirect(request, response, oldRedirectUrl) // all those should be in authentication success handler for basic auth
The only problem is that once the user is authenticated at auth server (port 9998) and gets redirected to initial application (port 9999) he gets the following error:
The second time he does it (when he is already authenticated) it works fine. Read somewhere that the issue might be with apps stealing each others cookies so I renamed the cookies using
server:
session:
cookie:
name: AUTH_SESSION
Config option. The resulting cookies (after authentication) under localhost domain are:
What is interesting AUTH_SESSION cookie changes its value after signing in.
Additionally I have no idea where JSESSION_ID came from. Maybe that's the problem here?
By the way it works perfectly when using formLogin auth.

Resources