Weave RememberMe service with OpenID Connection - spring

Can't find the way how to implement RememberMe service in OpenID. Have a class that extends AbstractRememberMeServices and it works with simple form login. Have next logs after login:
2015-12-17 07:29:15.086 DEBUG 260 --- [nio-8080-exec-5] p.s.s.CustomPersistentRememberMeServices : Did not send remember-me cookie (principal did not set parameter 'remember-me')
2015-12-17 07:29:15.086 DEBUG 260 --- [nio-8080-exec-5] p.s.s.CustomPersistentRememberMeServices : Remember-me login not requested.
Login works through /openid?openid_identifier=IDENTIFIER

Just add setAlwaysRemember(true); to your AbstractRememberMeServices implementation's constructor.

Related

Logout handler is hanging

I'm upgrading a working application from Spring Boot 2.6.5 to 2.7.8 (Spring Security 5.7.6) so that I can better upgrade to 3.0.
Logout was working fine before. But after upgrading to Sprint Boot 2.7.8 the logout handling is hanging and never redirecting to the logoutSuccessUrl().
Here is the complete filter chain configuration:
http
.authorizeHttpRequests((authz) -> authz
.antMatchers("/webjars/**","/login/**","/mobile-manifest.json","/service-worker.js","/cache.manifest","/favicon.ico","/async/**","/api/**").permitAll()
.anyRequest().authenticated()
)
.httpBasic(withDefaults())
.formLogin(formLogin -> formLogin
.loginPage("/login")
.permitAll()
.loginProcessingUrl("/login")
.successHandler(savedRequestAwareAuthenticationSuccessHandler())
.failureUrl("/login?loginFailed=true"))
.logout( logout -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logoutSuccess=true")
.invalidateHttpSession(true)
.deleteCookies(COOKIE_STRING))
.rememberMe( rememberMe -> rememberMe
.key(TOKEN_KEY)
.rememberMeParameter(REMEMBER_ME_KEY)
.tokenRepository(persistentTokenRepository())
.userDetailsService(userSvc)
.tokenValiditySeconds(validitySeconds));
The output:
[https-jsse-nio-7001-exec-10] [DEBUG] [o.s.security.web.FilterChainProxy] - Securing POST /logout
[https-jsse-nio-7001-exec-10] [DEBUG] [o.s.s.w.c.HttpSessionSecurityContextRepository] - Retrieved SecurityContextImpl [Authentication=UsernamePasswordAuthenticationToken [Principal=UserProfile [ blah blah, eventRoles=null, lastLoginDisplay=today, directoryUrl=null, groups=[]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, SessionId=740230E1C02B57BEF504C23570FFA9EC], Granted Authorities=[]]]
[https-jsse-nio-7001-exec-10] [DEBUG] [o.s.s.w.c.SecurityContextPersistenceFilter] - Set SecurityContextHolder to SecurityContextImpl [Authentication=UsernamePasswordAuthenticationToken [Principal=UserProfile [blah blah eventRoles=null, lastLoginDisplay=today, directoryUrl=null, groups=[]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, SessionId=740230E1C02B57BEF504C23570FFA9EC], Granted Authorities=[]]]
[https-jsse-nio-7001-exec-10] [DEBUG] [o.s.s.w.a.logout.LogoutFilter] - Logging out [UsernamePasswordAuthenticationToken [Principal=UserProfile [blah blah, eventRoles=null, lastLoginDisplay=today, directoryUrl=null, groups=[]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, SessionId=740230E1C02B57BEF504C23570FFA9EC], Granted Authorities=[]]]
[https-jsse-nio-7001-exec-10] [DEBUG] [o.s.s.w.a.r.PersistentTokenBasedRememberMeServices] - Logout of user username
[https-jsse-nio-7001-exec-10] [DEBUG] [o.s.s.w.a.r.PersistentTokenBasedRememberMeServices] - Cancelling cookie
[https-jsse-nio-7001-exec-10] [DEBUG] [o.s.jdbc.core.JdbcTemplate] - Executing prepared SQL update
[https-jsse-nio-7001-exec-10] [DEBUG] [o.s.jdbc.core.JdbcTemplate] - Executing prepared SQL statement [delete from persistent_logins where username = ?]
[https-jsse-nio-7001-exec-10] [DEBUG] [o.s.jdbc.datasource.DataSourceUtils] - Fetching JDBC Connection from DataSource
[https-jsse-nio-7001-exec-10] [DEBUG] [o.s.s.w.a.l.SecurityContextLogoutHandler] - Invalidated session F3BC69312EC05C175A0FCEC298B49D06
[https-jsse-nio-7001-exec-10] [DEBUG] [o.s.s.w.c.HttpSessionSecurityContextRepository] - Did not store empty SecurityContext
[https-jsse-nio-7001-exec-10] [DEBUG] [o.s.s.w.c.HttpSessionSecurityContextRepository] - Did not store empty SecurityContext
[https-jsse-nio-7001-exec-10] [DEBUG] [o.s.s.w.c.SecurityContextPersistenceFilter] - Cleared SecurityContextHolder to complete request
Browser is never redirected to the loginSuccessUrl(), all DEBUG logging ends above. CSRF is enabled and logout was submitted POST.
I had .permitAll() in the logout configuration, but it seemed to have no effect in this case.
Screenshot showing request / response
Spring Security provides two implementations of LogoutSuccessHandler, see LogoutSuccessHandler:
LogoutSuccessHandler
The LogoutSuccessHandler is called after a successful logout by the LogoutFilter, to handle (for example) redirection or forwarding to the appropriate destination. Note that the interface is almost the same as the LogoutHandler but may raise an exception.
Spring Security provides the following implementations:
SimpleUrlLogoutSuccessHandler
HttpStatusReturningLogoutSuccessHandler
As mentioned earlier, you need not specify the SimpleUrlLogoutSuccessHandler directly. Instead, the fluent API provides a shortcut by setting the logoutSuccessUrl(). This sets up the SimpleUrlLogoutSuccessHandler under the covers. The provided URL is redirected to after a logout has occurred. The default is /login?logout.
The HttpStatusReturningLogoutSuccessHandler can be interesting in REST API type scenarios. Instead of redirecting to a URL upon the successful logout, this LogoutSuccessHandler lets you provide a plain HTTP status code to be returned. If not configured, a status code 200 is returned by default.
If you configure HTTP basic authentication, the HttpStatusReturningLogoutSuccessHandler is added, see
Default Logout Handler with HTTP Basic and XMLHttpRequest should be 204:
The default behavior for logout when the header X-Requested-With: XMLHttpRequest and HTTP Basic is enabled should be a 201. This will improve AngularJS experience which sends an accept header which includes text/html
See also: SEC-3103: Logout Success Content Negotiation.

Spring Boot/Security is not redirecting to Okta logout URL - OpenID Connect Logout Options with Spring Boot

Description:
I tried Logout sample application as given in blog: https://developer.okta.com/blog/2020/03/27/spring-oidc-logout-options, it is working as expected.
But with the same configurations, we are unable to logout from Okta in our main/ organizations’ Application.
Expected Flow:
On logout button click, UI calls ‘…/testbootapp/logout’ → Spring Security by default handles logout Spring Boot logout
‘OidcClientInitiatedLogoutSuccessHandler’ is configured in SpringBoot application, this should redirect to enter link description here
--- Here, in our application Spring Security is not redirecting to Okta logout URL
Implementation Details:
Spring boot dependency version: 2.7.0
application.properties is same as defined in blog
Attached SecurityConfiguration class as used in our application:
SecurityConfiguration.java
After enabling spring security logs in our application, we saw that ‘o.s.s.web.DefaultRedirectStrategy’ does not generate Okta logout URL, instead redirects to root URL
Extracted Logs from our Application:
Jul 21 2022 12:47:16 PM IST DEBUG o.s.s.w.a.l.SecurityContextLogoutHandler -Invalidated session 280BDF27CFF81149D6C829EF2ADAC9DF
Jul 21 2022 12:47:16 PM IST DEBUG o.s.s.web.DefaultRedirectStrategy -Redirecting to /testbootapp/
Extracted Logs from Sample application given in blog:
2022-07-21 11:25:20.230 DEBUG 7382 — [nio-8080-exec-5] o.s.s.w.a.l.SecurityContextLogoutHandler : Invalidating session: C54C40030C14B14F9F03250B769D2E99
2022-07-21 11:25:20.231 DEBUG 7382 — [nio-8080-exec-5] o.s.s.web.DefaultRedirectStrategy : Redirecting to ‘https://dev-.oktapreview.com/oauth2/default/v1/logout?id_token_hint=&post_logout_redirect_uri=https://twitter.com/’
Add the the below attribute in the ClientRegistration :
.providerConfigurationMetadata(Map.of("end_session_endpoint","{idc url}/oauth2/v1/logout"))
That would hit server and do the complete logout.

Spring WebFlux creates new session cookie after logout

I have a SpringBoot WebFlux application that uses Netty and Spring Security. In my security config, I have
.logout().logoutUrl("/logout").logoutSuccessHandler(new HttpStatusReturningServerLogoutSuccessHandler())
and I can see that the security context is removed upon a POST to /logout
2022-05-31 11:52:05.700 DEBUG 37892 --- [or-http-epoll-3] o.s.s.w.s.a.logout.LogoutWebFilter : Logging out user 'AnonymousAuthenticationToken [Principal=anonymous, Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[ROLE_ANONYMOUS]]' and transferring to logout destination
2022-05-31 11:52:05.700 DEBUG 37892 --- [or-http-epoll-3] ebSessionServerSecurityContextRepository : Removed SecurityContext stored in WebSession: 'org.springframework.web.server.session.InMemoryWebSessionStore$InMemoryWebSession#1e33c2b6'
but the response infuriatingly contains a new Set-Cookie header for a new Session Cookie! Is this coming from Netty? How can I turn this off? Why is there no session configuration option for ServerHttpSecurity, where I could tell it to make new session only if required?
Any help appreciated, thanks
I figured out that the sessionId is changed in WebSessionServerSecurityContextRepository when the context is removed, but if I add
.logoutHandler(new WebSessionServerLogoutHandler())
to the configuration then it removes the SESSION cookie completely. Hopefully this helps someone else.

Spring Boot authentication not available from error page

Depending on whether the user is logged in, I want to display an element on an error page e.g.
<div sec:authorize="isAuthenticated()">
Logged in
</div>
The problem is, however is that the current Authentication Principal is being cleared for some reason. I thought it had something to do with the No Auth for You bug, so I added
security.filter-dispatcher-types: ASYNC, FORWARD, INCLUDE, REQUEST, ERROR
However still the problem persists. I loaded up both projects and debug-logged spring security. With the No Auth For You project I'm getting:
SecurityContextHolder now cleared, as request processing completed
Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade#76d66409
Processing ErrorPage[errorCode=0, location=/error]
/error at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
/error at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImp.....
Which gives the correct security context.
With my project I'm getting
SecurityContextHolder now cleared, as request processing completed
Cleared thread-bound request context: org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper#380b96d
Processing ErrorPage[errorCode=0, location=/error]
/error at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
/error at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
No HttpSession currently exists
No SecurityContext was available from the HttpSession: null. A new one will be created.
So the issue seems to be "No HttpSession currently exists". I am using Redis Sessions, if that makes a difference. However I don't know really where to go from here, when it comes to debugging.
I am using the GlobalDefaultException handler code from the Spring blog, if that makes any difference. However I actually ported this handler to the No Auth For You project, so I don't believe it is that.
If I leave this error page and view any other page, then I am still logged in.
Update
I removed Redis and it could find the session. Maybe it is something to do with Tomcat and Redis?
Update 2018
I have looked at this again, and I think it has something to do with the GlobalExceptionHandler (as mentioned before taken from Spring's blog).
"If you want to have a default handler for any exception, there is a slight wrinkle. You need to ensure annotated exceptions are handled by the framework."
#ControllerAdvice
public class GlobalExceptionHandler
{
#ExceptionHandler({Exception.class})
#ResponseStatus(value = INTERNAL_SERVER_ERROR)
public String exception(
HttpServletRequest request,
Exception e,
Model model
) throws Exception
{
// other logging things here
if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null)
{
// template that renders this can't access the SecurityContext
throw e;
}
// this template can access the SecurityContext
return "error";
}
}
The caught exception is able to access the SecurityContext, however the re-thrown exceptions (handled by Spring) can't access the SecurityContext.
Remember that both templates can access the SecurityContext, when Redis is not being used. I looked at the documentation for Spring Session and it says
"...[t]his creates a Spring Bean with the name of springSessionRepositoryFilter that implements Filter. The filter is what is in charge of replacing the HttpSession implementation to be backed by Spring Session."
So maybe this bean isn't being used for some reason?
Under Spring Boot 2.0.0.M7 it works, so I wonder what was changed
DEBUG 3767 --- [0.1-8080-exec-1] o.s.security.web.FilterChainProxy : /errorTest/notFound at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG 3767 --- [0.1-8080-exec-1] o.s.d.redis.core.RedisConnectionUtils : Opening RedisConnection
DEBUG 3767 --- [0.1-8080-exec-1] io.lettuce.core.RedisChannelHandler : dispatching command AsyncCommand [type=HGETALL, output=MapOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command]
[SNIP REDIS]
DEBUG 3767 --- [0.1-8080-exec-1] o.s.d.redis.core.RedisConnectionUtils : Closing Redis Connection
DEBUG 3767 --- [0.1-8080-exec-1] w.c.HttpSessionSecurityContextRepository : Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl#936f4f11: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken
I think it is related to the following issue:
https://github.com/spring-projects/spring-boot/issues/5737
I think it makes sense to change SecurityFilterAutoConfiguration to use the ERROR dispatch type by default. The ERROR dispatch type is also the default of Spring Security's Servlet Java Config.
The reason the ERROR dispatch type makes sense for Spring Security is many times navigation is based on the permissions of the current user. Without Spring Security being populated, the error page may not have
meaningful navigation.

remove OAuth2AuthenticationProcessingFilter from/oauth/token filter chain

I am trying to implement OAuth2 into my Spring Boot app. When making a call to /oauth/token using a password grant, I am able to authenticate using Basic auth with a username/password against a database. The authentication object is loaded into the security context and the filter continues. However I noticed that further down the line the OAuth2AuthenticationProcessingFilter is called and cleans out the security context b/c no OAuth bearer token is found. This ultimately results in an authentication failure at the TokenEndpoint.postAccessToken method (e.g. /oauth/token).
Is it expected that the OAuth2AuthenticationProcessingFilter would be called during a /oauth/token call? If not, any ideas why? If it is expected what is the best fix/work around for this issue, to set stateless on the OAuth2AuthenticationProcessingFilter to false? Not sure if that is a good idea or not...
Some relevant info, I am using xml config for my spring security settings and JavaConfig for the rest. The grant type is password on the /oauth/token call.
Any help is greatly appreciated. Below are some log messages for context on what I am seeing.
09/30/15 22:42:50.899 [http-nio-9931-exec-8] DEBUG o.s.s.o.p.c.ClientCredentialsTokenEndpointFilter - Authentication success. Updating SecurityContextHolder to contain: org.springframework.security.oauth2.provider.OAuth2Authentication#9d98054f: Principal: testUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_USER
09/30/15 22:42:50.899 [http-nio-9931-exec-8] DEBUG o.s.s.o.p.a.BearerTokenExtractor - Token not found in headers. Trying request parameters.
09/30/15 22:42:50.899 [http-nio-9931-exec-8] DEBUG o.s.s.o.p.a.BearerTokenExtractor - Token not found in request parameters. Not an OAuth2 request.
09/30/15 22:42:50.899 [http-nio-9931-exec-8] DEBUG o.s.s.o.p.a.OAuth2AuthenticationProcessingFilter - Clearing security context.
09/30/15 22:42:50.900 [http-nio-9931-exec-8] DEBUG o.s.s.o.p.a.OAuth2AuthenticationProcessingFilter - No token in request, will continue chain.
09/30/15 22:42:50.900 [http-nio-9931-exec-8] DEBUG o.s.s.o.p.a.BearerTokenExtractor - Token not found in headers. Trying request parameters.
09/30/15 22:42:50.900 [http-nio-9931-exec-8] DEBUG o.s.s.o.p.a.BearerTokenExtractor - Token not found in request parameters. Not an OAuth2 request.
09/30/15 22:42:50.900 [http-nio-9931-exec-8] DEBUG o.s.s.o.p.a.OAuth2AuthenticationProcessingFilter - No token in request, will continue chain.
09/30/15 22:42:50.934 [http-nio-9931-exec-8] DEBUG o.s.s.o.p.e.FrameworkEndpointHandlerMapping - Looking up handler method for path /oauth/token
09/30/15 22:42:50.937 [http-nio-9931-exec-8] DEBUG o.s.s.o.p.e.FrameworkEndpointHandlerMapping - Returning handler method [public org.springframework.http.ResponseEntity<org.springframework.security.oauth2.common.OAuth2AccessToken> org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(java.security.Principal,java.util.Map<java.lang.String, java.lang.String>) throws org.springframework.web.HttpRequestMethodNotSupportedException]
09/30/15 22:42:50.958 [http-nio-9931-exec-8] INFO o.s.s.o.p.endpoint.TokenEndpoint - Handling error: InsufficientAuthenticationException, There is no client authentication. Try adding an appropriate authentication filter.
09/30/15 22:42:51.070 [http-nio-9931-exec-8] DEBUG o.s.s.w.a.ExceptionTranslationFilter - Chain processed normally
09/30/15 22:42:51.070 [http-nio-9931-exec-8] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed

Resources