How to redirect using spring security session time out? - spring

I'm using spring boot 2.2.0.M2 spring security this package version is 5.2.0, my project fronted is done in vuejs 2.6.10
What I want to archive seems very simple, when spring security session is time out i want to redirect ( force browser ) to go to URL http://localhost:8080/
What I was trying till now is:
I have created configuration class:
#Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter
{
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.formLogin()
.loginPage("/")
.defaultSuccessUrl("/admin#/timetable")
.permitAll()
.and().logout()
.logoutSuccessUrl("/")
.permitAll()
.and()
.sessionManagement()
.maximumSessions(1)
.expiredUrl("/")
.expiredSessionStrategy(event -> event.getResponse().sendRedirect("/"));
// this supoose to work right?
}
}
and in my application.properties I have added for testing purpouses:
# Server
server.servlet.session.timeout=1m
And after one minute nothing happens.
So I thought that maybe something is wrong and session is not timeout so I've run my application in debug mode and I putted break point in
package org.springframework.security.web.session;
...
public class HttpSessionEventPublisher implements HttpSessionListener
{
...
public void sessionDestroyed(HttpSessionEvent event) {
//my break point
}
}
And after one minute I'm in, debugger stopped in sessionDestroyed method so session is no longer exist.
About my UI, I'm using vuejs embedded in thyme leaf page:
So my question is do You know how to force browser to reload my application or redirect to http://localhost:8080/ when spring security session is expired (timeout) ?

Related

TemplateInputeException while trying to serve frontend on my Spring Boot App

Controller Class:
#Controller
public class FirstRestController {
#GetMapping("/")
public String budget() {
return "budget";
}
Security Config:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/h2-console/**").permitAll()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic();
}
package structure image
I try to build a frontend for my web application. I'm using the Controller to serve my html Pages. But they are not rendering proberly. I always get a 404 not found Exception.
Now I tried it with Thymeleaf. But i always catch the TemplateInputeException. Thymeleaf is configured in my Pom.xml. I don't know where to debug this. I can't find a typo. So I think it's a bigger configuration I missed. Do I have to configure my resource folder somewhere? How can I server my html frontend pages in the app?
I tried to reinstall Thymeleaf. I already restarted IntelliJ. It tried to use the RequestMapping annotation. I renamed the static folder to public. I tried different paths.

How to secure only swagger UI page " swagger-ui/index.html#/ " and all other API end points should not be authenticated in Spring boot

I have a requirement where I just need to secure the Swagger UI page. All other endpoints I have written in the application should not be authenticated.
For this, I am using the Spring security starter. I have the Security Config for Spring boot in place. I am trying to authenticate ("/v2/api-docs") because this is where we see all the endpoints in Swagger UI. And also I am trying to permit ("/calculator-controller/callCalculatorServiceUsingPOST") which I see in browser URL when I click on my end point Try it now button and also permitting ("/calculate") which is in my controller. To be safer, I have tried to permit all possible combinations, but no luck.
What Am I missing ???
#Configuration #EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.authorizeRequests()
.antMatchers("/v2/api-docs").authenticated()
.antMatchers("/calculator-
controller/callCalculatorServiceUsingPOST",
"calculator-controller/**", "/calculate")
.permitAll()
.and()
.httpBasic();
}
}

Spring Security redirecting custom login page to itself - Too Many Redirects

I'm currently developing a custom login-page for my Spring Boot Application but I just can't get it to work. Using the default one works fine but as soon as I try to use my custom file, it just repeatedly redirects me until my Browser give up.
Other posts suggest permitting access to the login-path to erveryone but this also doesn't seem to work.
Here is my code:
WebSecurityConfig
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
}
And Controller for login-page
#Controller
public class WebController {
#GetMapping("/login")
public String login () {
return "login";
}
}
Any ideas what I'm missing?
You are probably using a lot of CSS and JS file link links, according to your code Spring Boot must first authenticate all the links, which is why it redirects to your login page many times.
add following code to bypass security authentication of resource link
public void configure(WebSecurity web) {
web.ignoring()
.antMatchers("/bower_components/**", "/dist/**", "/plugins/**"); //write your resource directory name
}

Spring Boot OAuth2 errors after invalidating session and accessing data from Resource Server

My architecture consists of three applications:
Authorization Server (10.10.1.1:8080)
Client A (10.10.3.3:8084)
Client B (10.10.2.2:8089)
Both Client A and B are serving static Angular files. Both clients are "communicating" with each other - it is possible to navigate from the first one to another one and back as well (through normal window.location.replace).
Everything works great instead of one specific situation.
I'm logging into Client A application (through Authorization server redirect).
I'm opening Client B - user is properly authenticated based on Client A.
I'm coming back to Client A - user is still authenticated. (I can repeat steps 2 and 3 endlessly)
I'm logging out from Client A.
I'm logging in again into Client A with the same or different user.
I'm opening Client B and getting blank page due to some network issues.
After page refresh everything works fine (JSESSIONID is changing in the browser and user is properly authenticated).
I've tried couple different approaches and configurations using session invalidation. Session is properly invalidated but then it is not created again (user is changing to anonymous instead of being properly taken from Client A).
Then follows redirect to authorization server, which isn't available for some reason.
The problem here is that normal flow after redirect (step 2) is:
Redirect to 10.10.2.2:8089/home-page
/home-page gets 302 REDIRECT in network tab to /login
/login redirects to 10.10.1.1:8080/oauth/authorize
then it redirects back to /home-page with status 200 OK.
Error flow after redirect (step 6) is:
Redirect to 10.10.2.2:8089/home-page
/home-page gets 200 OK in network tab
application loads the page and it makes request for user data (/api/user) which gets 401
the entire redirect cycle takes place and ends with unability to redirect to 10.10.1.1:8080/oauth/authorize
after page refresh everything works fine.
I've tried:
couple different approaches and configurations in security (both on Client A and Client B)
allowing all origins in CorsFilter (for testing purposes - even that didn't help)
adding another cookie through server.servlet.cookie.name and erasing it by deleteCookies() or proper handler
adding maximumSessions(2) for tests purposes - even that didn't help
At last I made some tricky solution. I made request to Client B before redirect to Client A. It removed JSESSIONID through HttpServletResponse. It helped, but only when I'm working on one browser tab.
If I have two tabs opened (one with Client A and one with Client B) after doing step 5 and 6 and refreshing the page on Client B, problem still persists (because I didn't erase JSESSIONID from the browser).
I don't know if I understand this problem properly (that JSESSIONID is problematic in the browser), so correct me if I'm wrong. Also - I don't know how to erase this cookie or allow OAuth2 Filters to automatically create new one and invalidate the session in proper way.
Can anybody help me with this problem and show what I'm doing wrong here?
Client A - Security Configuration
#Configuration
#EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public OAuth2RestTemplate oauth2RestTemplate(final OAuth2ClientContext context,
final OAuth2ProtectedResourceDetails details) {
return new OAuth2RestTemplate(details, context);
}
#Override
public void configure(final HttpSecurity http) throws Exception {
http
.formLogin()
.and()
.logout().clearAuthentication(true)
.invalidateHttpSession(true)
// .deleteCookies("JSESSIONID")
// .logoutSuccessHandler((httpServletRequest, httpServletResponse, authentication) -> {httpServletResponse.setStatus(HttpServletResponse.SC_OK);})
.addLogoutHandler(new ProperCookieClearingLogoutHandler("JSESSIONID"))
.and()
.authorizeRequests()
.antMatchers("/index.html", "/main.html", "/login", "/resources/**", ...)
.permitAll()
.anyRequest()
.authenticated()
.and()
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
}
Client B - Security Configuration
#Configuration
#EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public OAuth2RestTemplate oauth2RestTemplate(final OAuth2ClientContext context,
final OAuth2ProtectedResourceDetails details) {
return new OAuth2RestTemplate(details, context);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.logout().clearAuthentication(true)
.invalidateHttpSession(true)
// .deleteCookies("JSESSIONID")
// .logoutSuccessHandler((httpServletRequest, httpServletResponse, authentication) -> {httpServletResponse.setStatus(HttpServletResponse.SC_OK);})
.addLogoutHandler(new ProperCookieClearingLogoutHandler("JSESSIONID"))
.and()
.authorizeRequests()
.antMatchers("/index.html", "/main.html", "/resources/**", "/login/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
}
Authorization Server - Security Configuration
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login")
.permitAll().and()
.formLogin().failureHandler(new FailureAuthenticationHandler())
.loginPage("/login").permitAll()
.and().requestMatchers()
.antMatchers("/login")
.antMatchers("/oauth/authorize")
.antMatchers("/oauth/confirm_access")
.and()
.anyRequest().authenticated()
.and().sessionManagement().maximumSessions(-1).expiredUrl("/...").sessionRegistry(sessionRegistry());
}
#Bean
SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
... authentication providers ...
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
CustomTokenStore customTokenStore;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("x").secret("x")
.authorizedGrantTypes("x").autoApprove(true).scopes("x");
}
#Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.tokenStore(customTokenStore).authenticationManager(authenticationManager);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer.allowFormAuthenticationForClients();
}
}
Full log from Client B:
https://pastebin.com/aVc5AXcx
Thank you in advance.
24.10.2020 - TOPIC EDIT
After digging deeper and doing some research I probably found a core of the problem, but I don't know how to solve it yet.
First problem
There are two OAuth2 clients (annoted with #EnableOAuth2Sso) that share the same session and user data, but they don't know about each other openly (and about each other login/logout state).
I'm working on Client B and triggering logout call on that specific client.
Then I'm redirecting to authorization server login page with specific logout params.
I'm making logout call to authorization server on POST method and /logout path.
After successfull user logout I'm doing window.location.replace to Client A, which gets unauthorized error in network tab (401):
WWW-Authenticate header: Bearer realm="oauth2-resource", error="invalid_token", error_description="Invalid access token: 27ef8abe-e8e5-4d07-aaf4-a82a8757614e"
And in console of Client A I get:
UserInfoTokenServices: Could not fetch user details: class org.springframework.security.oauth2.client.resource.UserRedirectRequiredException, A redirect is required to get the users approval.
Second problem
Similiar situation is in the base problem stated in this topic. After relogin on Client A and page refresh on Client B, it has some session/token in cache and think that user is still authenticated in that client. It returns status 200 OK in HTML routing path (f.e. /home-page), but gets unauthorized on first request to API and giving the same invalid_token header:
WWW-Authenticate header: Bearer realm="oauth2-resource", error="invalid_token", error_description="Invalid access token: 4026cf9f-8081-4870-b9bf-6e6ff89d4ded" (401)
And in Resource Server I get:
Unable to obtain a new access token for resource 'null'. The provider manager is not configured to support it.
Both clients have the same configuration in properties
security.oauth2.client.client-id=x
security.oauth2.client.client-secret=y
security.oauth2.client.user-authorization-uri=http://${auhorization.server.url}/oauth/authorize
security.oauth2.client.access-token-uri=http://${auhorization.server.url}/oauth/token
security.oauth2.resource.user-info-uri=http://${resource.server.url}/user
Conclusion
I've tried adding csrfHeaderFilter and OAuth2ClientContextFilter from this topic, but it didn't help.
https://github.com/spring-guides/tut-spring-security-and-angular-js/issues/76
So the question is how to handle logout / refresh session and user context in another client after logout from the second one (and authorization server)? I don't know if I'm getting this process right, but I'm still anylizing what's going on here...
Can anybody show me some solution?

Spring Security - Redirect to custom login page without going through controller

I am currently using Spring Boot + Spring Security to develop a simple website that need user to login to access it. I have created my own custom static login page under resources/templates1/bruceLogin1.html. Any unathenticated access to my website to first be redirected to the login page URL which is http://localhost:8080/templates1/bruceLogin1.html
Note: that I am NOT creating any controller for this login URL, hence I am expecting the bruceLogin1.html to be accessed directly bypassing controller. Because i directly allow access to this html page without going thru controller, I assume no view resolver (e.g thymleaf) is required.
I open my browser, and enter http://localhost:8080/blablabl, and browser redirect me to http://localhost:8080/templates1/bruceLogin1.html , but sadly, i got error
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sat Jan 11 12:40:37 SGT 2020
There was an unexpected error (type=Not Found, status=404).
No message available
Below is my configuration,
#SpringBootApplication
#EnableWebSecurity
public class SpringSecurityCatalogApplication implements WebMvcConfigurer {
public static void main(String[] args) {
SpringApplication.run(SpringSecurityCatalogApplication.class, args);
}
#EnableWebSecurity
#Order(Ordered.HIGHEST_PRECEDENCE)
class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/templates1/bruceLogin1.html")
.permitAll();
}
}
}
Think instead of putting under resources/template1 folder, i will just put the custom login page into either resources/static or resources/public folder.
Then configure as shown below
#EnableWebSecurity
#Order(Ordered.HIGHEST_PRECEDENCE)
class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/bruceLogin1.html")
.permitAll();
}
}
Open browser and access any URL, you will be redirected to http://localhost:8080/bruceLogin1.html. And thats it!
Note that this does not require any controller nor view resolver.

Resources