EDIT:
log from org.springframework.security:
2022-01-17 12:31:03.495 IST 2022-01-17 10:31:03.495 DEBUG [080-exec-5] o.s.s.w.s.SessionManagementFilter - Request requested invalid session id D5F8BA31A3D7466AK3K3C8EA26A4F037 Default 2022-01-17 12:31:03.495 IST 2022-01-17 10:31:03.495 DEBUG [080-exec-5] o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext Debug 2022-01-17 12:31:03.495 IST "Request requested invalid session id D5F8BA31A3D7466AK3K3C8EA26A4F037" Debug 2022-01-17 12:31:03.495 IST "Set SecurityContextHolder to anonymous SecurityContext" Default 2022-01-17 12:31:03.494 IST 2022-01-17 10:31:03.494 DEBUG [080-exec-5] o.s.s.w.c.SecurityContextPersistenceFilter - Set SecurityContextHolder to empty SecurityContext Debug 2022-01-17 12:31:03.494 IST "Set SecurityContextHolder to empty SecurityContext" Default 2022-01-17 12:31:03.493 IST 2022-01-17 10:31:03.493 DEBUG [080-exec-5] o.s.security.web.FilterChainProxy - Securing GET /logo192.png Debug 2022-01-17 12:31:03.493 IST "Securing GET /logo192.png"
***But if I look in the logs some requests after I can get the valid auth:
Debug 2022-01-17 12:31:03.945 IST “Set SecurityContextHolder to SecurityContextImpl [Authentication=OAuth2AuthenticationToken [Principal=com..security.oauth.CustomOAuth2User@, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=***, SessionId=9438C880A19C93AADJI206B9B8B3386], Granted Authorities=[ROLE_USER, SCOPE_https://www.googleapis.com/auth/userinfo.email, SCOPE_https://www.googleapis.com/auth/userinfo.profile, SCOPE_openid]]]” Debug
2022-01-17 12:31:03.945 IST “Retrieved SecurityContextImpl [Authentication=OAuth2AuthenticationToken [Principal=com..security.oauth.CustomOAuth2User@, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=***, SessionId=9438C880A19C93AADJI206B9B8B3386], Granted Authorities=[ROLE_USER, SCOPE_https://www.googleapis.com/auth/userinfo.email, SCOPE_https://www.googleapis.com/auth/userinfo.profile, SCOPE_openid]]]” Debug
2022-01-17 12:31:03.945 IST “Retrieved SecurityContextImpl [Authentication=OAuth2AuthenticationToken [Principal=com..security.oauth.CustomOAuth2User@, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=***, SessionId=9438C880A19C93AADJI206B9B8B3386], Granted Authorities=[ROLE_USER, SCOPE_https://www.googleapis.com/auth/userinfo.email, SCOPE_https://www.googleapis.com/auth/userinfo.profile, SCOPE_openid]]]” Default
2022-01-17 12:31:03.944 IST 2022-01-17 10:31:03.944 DEBUG [080-exec-8] o.s.security.web.FilterChainProxy – Securing GET /auth/api/getBasicInfo
it looks like the session id is inconsistent
I use spring security builtin oauth2 social login option, I implemented an OAuth2LoginSuccess class with the onAuthenticationSuccess method and inside of it I fetch the user the corresponds to the social id I got from the oauth:
CustomOAuth2User oAuth2User = (CustomOAuth2User) authentication.getPrincipal(); int sociald = oAuth2User.getAttribute("id"); User user = usersUtils.getUserBySocailId(socialId); enter code here // add the user details to the Auth SecurityContextHolder.clearContext(); ((OAuth2AuthenticationToken) authentication).setDetails(user); SecurityContextHolder.getContext().setAuthentication(authentication);
If I debug inside the onAuthenticationSuccess I can see a valid auth with all the user details.
after the login I redirect to the home page and i send a auth get request to the server to check if there is a user logged in.
the problem is that 50% of the times the request is completed successfuly and the user can make authenticated requets.
but the other 50% i get redirected automaticly to Login page and when i check the log is see that Spring boot says that the user is unauthenticated and the auth is lost.
But in the onAuthenticationSuccess i can always see the correct auth.
My ApplicationSecurityConfig looks like this:
http.csrf().disable().authorizeRequests() .antMatchers("/login*", "/signin/**", "/signup/**", "/oauth2/**").permitAll() .antMatchers(Constants.ADMIN_PREFIX + "/**").hasRole("ADMIN") .antMatchers(Constants.AUTH_PREFIX + "/**").hasAnyRole("ADMIN", "USER") .antMatchers(Constants.PUBLIC_PREFIX + "/**").permitAll() .anyRequest().permitAll() .and() .exceptionHandling().authenticationEntryPoint(new UnauthenticatedRequestHandler()) .and() .formLogin() .passwordParameter("password") .usernameParameter("email") .loginPage("/Login") .loginProcessingUrl("/loginSecure").permitAll().successHandler(new LoginSuccess()).failureHandler(new FailureSuccess()) .and() .oauth2Login() .loginPage("/Login") .userInfoEndpoint() .userService(oAuth2UserService) .and() .successHandler(new OAuth2LoginSuccess()) .and() .rememberMe() .rememberMeParameter("remember-me") .tokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(21)) .userDetailsService(this.applicationUserService) .and() .logout() .clearAuthentication(true).invalidateHttpSession(true).logoutSuccessUrl("/login") .addLogoutHandler(new CustomLogOutHandler());
And this is the function i check if the user is logged in:
@GetMapping(Constants.AUTH_PREFIX + "/checkUserLogged") public Integer checkUserLogged(Authentication authentication,HttpServletRequest request) { try{ if (authentication != null) { User (User) authentication.getDetails(); if (user == null) { return -1; } return user.getId(); } } catch (Exception e){ logger.warning(e.getLocalizedMessage()); } return -1; }
but when the problem occur it dosen’t get to run the controller because spring security return unauthrozed error before.
Thank you in advance for your help
Advertisement
Answer
I found the solution, I hope this could help.
The thing that caused the problem for me was that GCP and GAE use multiple instances of the server, and if the user is logged in a certain instance does not mean the other instances are familiar with it too because the Spring HTTPSession is in-memory.
I Switched the Session platform to use the spring-session jdbc using the following configuration in the application.properties :
spring.session.store-type=jdbc
— you can use redis instead of jdbc, as long as the session is stored in a shared place among all instances.
also added the transaction manager to the SecurtityConfig:
@Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); }
and added the following configurations :
http.csrf().disable() .sessionManagement() .maximumSessions(1) .and() .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
In addition like @stringy05 mentioned the authrizenClient Repository needs ti be updated too:
/** * Use the servlet container session store for authorized OAuth2 Clients */ @Bean public OAuth2AuthorizedClientRepository authorizedClientRepository() { return new HttpSessionOAuth2AuthorizedClientRepository(); }
and add the .authorizedClientRepository line to the httpconfig:
.... .oauth2Login() .loginPage("/Login") .authorizedClientRepository(authorizedClientRepository) .authorizationEndpoint().and() .userInfoEndpoint() .userService(oAuth2UserService) .and() .successHandler(new OAuth2LoginSuccess())
….
Regarding the GAE, I added the following line to the app.yaml file:
network: session_affinity: true