Is a stateless app compatible with formlogin? - spring

I'm struggling for some days with this problem : I have an authentication server with spring security. I use JWT tokens, and as I need my users to be able to logout from the font side, I need not to have a JSESSIONID, so I set the sessionCreationPolicy(SessionCreationPolicy.STATELESS)
Also I need a login form on the authentication server side, which I manage with formLogin().
Unfortunately, if I use those 2 configs at the same time, once the user have submited the login form, he's not redirected back to the front app.
If I drop the SessionCreationPolicy.STATELESS and set the formLogin() part, then the redirection is working, but then I got a session, and logout doesn't work.
If I set SessionCreationPolicy.STATELESS and httpBasic(), then the redirection is working, but of course I don't have the login form.
Is there any way to achieve that?
here the config :
http.cors().and().csrf().disable().
authorizeRequests()
.antMatchers("/token/*").permitAll()
.anyRequest().permitAll()
.and()
.httpBasic()
// .formLogin()
// .loginPage("/login")
// .permitAll()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

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 Boot Security: How to run authentication filter before CSRF in Spring Boot?

I am always getting unauthorize on Login.
On Login i need to authenticate user as well as generate CSRF token based on JWT token generated from user credentials.
I have CsrfCookieGeneratorFilter but i need to pass JWT generated after sucessfull authentication. My current code always execute CsrfFilterfirst and after that run authentication thing.
So Authentication First and then CsrfCookieGeneraterFilter.
Could anyone guide how to achieve using following builder (I am quite new to this Spring security thing implementation)
Following is code i am trying:
httpSecurity
.authorizeRequests().antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.csrf()
.requireCsrfProtectionMatcher(csrfRequestMatcher)
.csrfTokenRepository(customCsrfTokenRepository)
.and()
.cors()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.authenticationEntryPoint(this.jwtAuthenticationEntryPoint);
httpSecurity.addFilterAt(new CsrfCookieGeneratorFilter(customCsrfTokenRepository), CsrfFilter.class);
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);

Spring Boot OAuth2 Single Sign On Concept not working

I am trying to develop OAuth2 Client Application with Single Sign On. I have already developed Authorization Server and tested with Client Credentials flow and its working fine. But when I try to use Authorization Code Grant with Single Sign On I could not get it right. Client application takes me to Login Screen when I access authenticated URL, but once authenticated I am redirected to call back url that's fine. But afterwards I could not access any URL as it all authenticated URL are automatically redirected to CALL BACK url. I have permitted call back url in my Security class
My requirement is once authenticated it will allow other urls normally before authentication it should not allow any url.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
.and()
.authorizeRequests()
.antMatchers("/","/index.html", "/home.html", "/login**","/webjars/**", "/error**","/favicon.ico**","/oauth/token","/oauth/authorize**","/demo/1")
.permitAll()
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.and()
.httpBasic();
Here the call back url is demo/1 and Spring Security is not permitting any other url here.
My requirement is once authenticated it should allow other urls normally before authentication it should not allow any url.
http.authorizeRequests().antMatchers("/","/resources/**", "/**").permitAll().anyRequest().authenticated().and().formLogin()
.loginPage("/").permitAll().usernameParameter("username").passwordParameter("password")
.loginProcessingUrl("/j_spring_security_check").failureUrl("/")
.successHandler(myAuthenticationSuccessHandler()).and().logout().logoutSuccessUrl("/")
.logoutUrl("/logout").invalidateHttpSession(true).deleteCookies("JSESSIONID").and().csrf().disable().headers().frameOptions().sameOrigin();

Spring security: set-cookie doesn't work in non-spring environment

I have a spinrg boot app where my frontend code is placed inside the static folder, and everything works great there.
I develop my frontend source outside my spring project and build it to the static folder.
When I run my spring boot app, the frontend works great and the login stores a cookie named JSESSIONID then my API requests work.
The problem is that when I develop my frontend I'm serving my client outside of spring, and the cookie is not stored in my browser upon a successful login.
The question:
Any idea how I can solve it- access and store the cookie although the client is not served with spring?
My spring httpsecurity config:
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/resources/**" , "/assets/**" , "/api/information").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(successHandler())
.failureHandler(failureHandler())
// .failureUrl("/authentication/login-error.html")
.permitAll()
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler())
// .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()
.and()
.logout()
.deleteCookies("JSESSIONID")
.permitAll();
Set cookie received from spring:
set-cookie:JSESSIONID=1F16D001A85DDD17CE840CF2A3694231;path=/;Secure;HttpOnly

Custom .formLogin() Spring Security

I am trying to use my page created to authenticate, it is the login.jsf. I use in .loginPage / login.jsf with 2 inputs and 1 button to authenticate. However, by filling in the logins and password fields, and clicking the button, nothing happens. Unlike Spring Security own .formLogin() itself, which already does all the processing by clicking the button.
My method
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login.jsf").anonymous()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login.jsf")
.defaultSuccessUrl("/homepage.jsf")
.failureUrl("/login.jsf?error=true")
.and()
.logout().logoutSuccessUrl("/login.jsf");
}
Anyone have any suggestions?
Print screen default .formLogin()
Take a look at the following article from spring security documentation.
https://docs.spring.io/spring-security/site/docs/current/guides/html5/form-javaconfig.html#creating-a-login-view
Quoting the article,
The URL we submit our username and password to is the same URL as our
login form (i.e. /login), but a POST instead of a GET.
So I believe you have to make a POST call to the /login endpoint with your authentication details for it to work.
Don't use file extensions when specifying pages in the configuration. The ViewResolver will take care of it. Simply specify
.loginPage("/login").defaultSuccessUrl("/homepage")
.failureUrl("/login?error=true")
.and()
.logout().logoutSuccessUrl("/login");`
And make sure a ViewResolver is configured to append .jsf to the url. The DispatcherServlet will take care of locating the appropriate page.
Also, not to mention, you should have controllers with the appropriate #RequestMappings defined to handle your requests.

Resources