I'm trying to include a 'third-party' url in a vaadin 14 + spring boot application, namely the redirect url of spring-security for a single-sign on '/oauth2/authorization/github'.
However the vaadin servlet seems to intercept this url and shows an error message that the route is unknown.
Could not navigate to 'oauth2/authorization/github'
Reason: Couldn't find route for 'oauth2/authorization/github'
How can this be prevented so the oauth2 url can be reached? I checked the vaadin documentation but found no information on how to exclude particular paths from the regular router navigation mechanism.
The spring-boot oauth2 tutorial is from the official spring site https://spring.io/guides/tutorials/spring-boot-oauth2/ and the following dependencies were added:
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin</artifactId>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-spring-boot-starter</artifactId>
</dependency>
The WebSecurityConfigurerAdapter is properly in place since the standard spring-security shows the abovementioned GitHub Auth link on the root '/' of the page. Also for the root page the unknown route error isn't shown.
I also tried the example in https://vaadin.com/learn/tutorials/securing-your-app-with-spring-security/setting-up-spring-security and it works for the regular login page but again prevents visiting the oauth2 link.
Is it required to implement a request filter that dispatches this or can the exclusion be configured somewhere?
edit: As reqested here's the WebSecurityAdapterConfigurer
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
// Register our CustomRequestCache, that saves unauthorized access attempts, so
// the user is redirected after login.
.requestCache().requestCache(new CustomRequestCache())
// Restrict access to our application.
.and().authorizeRequests()
// Allow all flow internal requests.
.requestMatchers(SecurityUtils::isFrameworkInternalRequest).permitAll()
// Allow all requests by logged in users.
.anyRequest().authenticated()
// Configure the login page.
.and().oauth2Login()
.and().formLogin().loginPage(LOGIN_URL).permitAll().loginProcessingUrl(LOGIN_PROCESSING_URL)
.failureUrl(LOGIN_FAILURE_URL)
// Configure logout
.and().logout().logoutSuccessUrl(LOGOUT_SUCCESS_URL);
}
#Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers(
// Vaadin Flow static resources
"/VAADIN/**",
// the standard favicon URI
"/favicon.ico",
// the robots exclusion standard
"/robots.txt",
// web application manifest
"/manifest.webmanifest",
"/sw.js",
"/offline-page.html",
// icons and images
"/icons/**",
"/images/**",
// (development mode) static resources
"/frontend/**",
// (development mode) webjars
"/webjars/**",
// (development mode) H2 debugging console
"/h2-console/**",
// (production mode) static resources
"/frontend-es5/**", "/frontend-es6/**",
// oauth2
"/user/**",
"/oauth2/**"
);
}
After checking the tutorial that #anasmi commented it turned out that the WebSecurity configuratin containing the oauth antmatcher was wrong in the first place.
The effect that can now be observed is that the spring security oauth2 filter forwards to /login which does not display the page configured for the vaadin route but a default with the authorization link to github.
Here's a debug log if it helps to understand what's going on:
onTranslationFilter : Calling Authentication entry point.
uthenticationEntryPoint : Trying to match using AndRequestMatcher [requestMatchers=[NegatedRequestMatcher [requestMatcher=RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]], MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager#5be8fdbf, matchingMediaTypes=[application/xhtml+xml, image/*, text/html, text/plain], useEquals=false, ignoredMediaTypes=[*/*]]]]
her.AndRequestMatcher : Trying to match using NegatedRequestMatcher [requestMatcher=RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]]
.NegatedRequestMatcher : matches = true
her.AndRequestMatcher : Trying to match using MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager#5be8fdbf, matchingMediaTypes=[application/xhtml+xml, image/*, text/html, text/plain], useEquals=false, ignoredMediaTypes=[*/*]]
TypeRequestMatcher : httpRequestMediaTypes=[text/html, application/xhtml+xml, image/webp, application/xml;q=0.9, */*;q=0.8]
TypeRequestMatcher : Processing text/html
TypeRequestMatcher : application/xhtml+xml .isCompatibleWith text/html = false
TypeRequestMatcher : image/* .isCompatibleWith text/html = false
TypeRequestMatcher : text/html .isCompatibleWith text/html = true
her.AndRequestMatcher : All requestMatchers returned true
uthenticationEntryPoint : Match found! Executing org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint#20728225
RedirectStrategy : Redirecting to 'http://localhost:8080/login'
iters.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#169ed862
curityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
ontextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
.AntPathRequestMatcher : Checking match of request : '/login'; against '/VAADIN/**'
.AntPathRequestMatcher : Checking match of request : '/login'; against '/favicon.ico'
.AntPathRequestMatcher : Checking match of request : '/login'; against '/robots.txt'
.AntPathRequestMatcher : Checking match of request : '/login'; against '/manifest.webmanifest'
.AntPathRequestMatcher : Checking match of request : '/login'; against '/sw.js'
.AntPathRequestMatcher : Checking match of request : '/login'; against '/offline-page.html'
.AntPathRequestMatcher : Checking match of request : '/login'; against '/icons/**'
.AntPathRequestMatcher : Checking match of request : '/login'; against '/images/**'
.AntPathRequestMatcher : Checking match of request : '/login'; against '/frontend/**'
.AntPathRequestMatcher : Checking match of request : '/login'; against '/webjars/**'
.AntPathRequestMatcher : Checking match of request : '/login'; against '/h2-console/**'
.AntPathRequestMatcher : Checking match of request : '/login'; against '/frontend-es5/**'
.AntPathRequestMatcher : Checking match of request : '/login'; against '/frontend-es6/**'
FilterChainProxy : /login at position 1 of 15 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
FilterChainProxy : /login at position 2 of 15 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
curityContextRepository : HttpSession returned null object for SPRING_SECURITY_CONTEXT
curityContextRepository : No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade#2fe150b5. A new one will be created.
FilterChainProxy : /login at position 3 of 15 in additional filter chain; firing Filter: 'HeaderWriterFilter'
FilterChainProxy : /login at position 4 of 15 in additional filter chain; firing Filter: 'LogoutFilter'
tcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', GET]
.AntPathRequestMatcher : Checking match of request : '/login'; against '/logout'
tcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', POST]
.AntPathRequestMatcher : Request 'GET /login' doesn't match 'POST /logout'
tcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', PUT]
.AntPathRequestMatcher : Request 'GET /login' doesn't match 'PUT /logout'
tcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', DELETE]
.AntPathRequestMatcher : Request 'GET /login' doesn't match 'DELETE /logout'
tcher.OrRequestMatcher : No matches found
FilterChainProxy : /login at position 5 of 15 in additional filter chain; firing Filter: 'OAuth2AuthorizationRequestRedirectFilter'
.AntPathRequestMatcher : Checking match of request : '/login'; against '/oauth2/authorization/{registrationId}'
FilterChainProxy : /login at position 6 of 15 in additional filter chain; firing Filter: 'OAuth2LoginAuthenticationFilter'
.AntPathRequestMatcher : Checking match of request : '/login'; against '/login/oauth2/code/*'
FilterChainProxy : /login at position 7 of 15 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
.AntPathRequestMatcher : Request 'GET /login' doesn't match 'POST /login'
FilterChainProxy : /login at position 8 of 15 in additional filter chain; firing Filter: 'DefaultLoginPageGeneratingFilter'
iters.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#169ed862
curityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
ontextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
.AntPathRequestMatcher : Checking match of request : '/oauth2/authorization/github'; against '/VAADIN/**'
.AntPathRequestMatcher : Checking match of request : '/oauth2/authorization/github'; against '/favicon.ico'
.AntPathRequestMatcher : Checking match of request : '/oauth2/authorization/github'; against '/robots.txt'
.AntPathRequestMatcher : Checking match of request : '/oauth2/authorization/github'; against '/manifest.webmanifest'
.AntPathRequestMatcher : Checking match of request : '/oauth2/authorization/github'; against '/sw.js'
.AntPathRequestMatcher : Checking match of request : '/oauth2/authorization/github'; against '/offline-page.html'
.AntPathRequestMatcher : Checking match of request : '/oauth2/authorization/github'; against '/icons/**'
.AntPathRequestMatcher : Checking match of request : '/oauth2/authorization/github'; against '/images/**'
.AntPathRequestMatcher : Checking match of request : '/oauth2/authorization/github'; against '/frontend/**'
.AntPathRequestMatcher : Checking match of request : '/oauth2/authorization/github'; against '/webjars/**'
.AntPathRequestMatcher : Checking match of request : '/oauth2/authorization/github'; against '/h2-console/**'
.AntPathRequestMatcher : Checking match of request : '/oauth2/authorization/github'; against '/frontend-es5/**'
.AntPathRequestMatcher : Checking match of request : '/oauth2/authorization/github'; against '/frontend-es6/**'
FilterChainProxy : /oauth2/authorization/github at position 1 of 15 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
FilterChainProxy : /oauth2/authorization/github at position 2 of 15 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
curityContextRepository : HttpSession returned null object for SPRING_SECURITY_CONTEXT
curityContextRepository : No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade#2fe150b5. A new one will be created.
FilterChainProxy : /oauth2/authorization/github at position 3 of 15 in additional filter chain; firing Filter: 'HeaderWriterFilter'
FilterChainProxy : /oauth2/authorization/github at position 4 of 15 in additional filter chain; firing Filter: 'LogoutFilter'
tcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', GET]
.AntPathRequestMatcher : Checking match of request : '/oauth2/authorization/github'; against '/logout'
tcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', POST]
.AntPathRequestMatcher : Request 'GET /oauth2/authorization/github' doesn't match 'POST /logout'
tcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', PUT]
.AntPathRequestMatcher : Request 'GET /oauth2/authorization/github' doesn't match 'PUT /logout'
tcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', DELETE]
.AntPathRequestMatcher : Request 'GET /oauth2/authorization/github' doesn't match 'DELETE /logout'
tcher.OrRequestMatcher : No matches found
FilterChainProxy : /oauth2/authorization/github at position 5 of 15 in additional filter chain; firing Filter: 'OAuth2AuthorizationRequestRedirectFilter'
.AntPathRequestMatcher : Checking match of request : '/oauth2/authorization/github'; against '/oauth2/authorization/{registrationId}'
.AntPathRequestMatcher : Checking match of request : '/oauth2/authorization/github'; against '/oauth2/authorization/{registrationId}'
RedirectStrategy : Redirecting to 'https://github.com/login/oauth/authorize?response_type=code&client_id=3a39e84cc95590698a1b&scope=read:user&state=yaVXu6gS7Zcwud2oT_SWsbkj-DbxxxqF46lQ%3D&redirect_uri=http://localhost:8080/login/oauth2/code/github'
iters.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#169ed862
curityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
ontextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
.AntPathRequestMatcher : Checking match of request : '/login/oauth2/code/github'; against '/VAADIN/**'
.AntPathRequestMatcher : Checking match of request : '/login/oauth2/code/github'; against '/favicon.ico'
.AntPathRequestMatcher : Checking match of request : '/login/oauth2/code/github'; against '/robots.txt'
.AntPathRequestMatcher : Checking match of request : '/login/oauth2/code/github'; against '/manifest.webmanifest'
.AntPathRequestMatcher : Checking match of request : '/login/oauth2/code/github'; against '/sw.js'
.AntPathRequestMatcher : Checking match of request : '/login/oauth2/code/github'; against '/offline-page.html'
.AntPathRequestMatcher : Checking match of request : '/login/oauth2/code/github'; against '/icons/**'
.AntPathRequestMatcher : Checking match of request : '/login/oauth2/code/github'; against '/images/**'
.AntPathRequestMatcher : Checking match of request : '/login/oauth2/code/github'; against '/frontend/**'
.AntPathRequestMatcher : Checking match of request : '/login/oauth2/code/github'; against '/webjars/**'
.AntPathRequestMatcher : Checking match of request : '/login/oauth2/code/github'; against '/h2-console/**'
.AntPathRequestMatcher : Checking match of request : '/login/oauth2/code/github'; against '/frontend-es5/**'
.AntPathRequestMatcher : Checking match of request : '/login/oauth2/code/github'; against '/frontend-es6/**'
FilterChainProxy : /login/oauth2/code/github?code=c8b1870a2477fef6f032&state=yaVXu6gS7Zcwud2oT_SWsbkj-DbxxxqF46lQ%3D at position 1 of 15 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
FilterChainProxy : /login/oauth2/code/github?code=c8b1870a2477fef6f032&state=yaVXu6gS7Zcwud2oT_SWsbkj-DbxxxqF46lQ%3D at position 2 of 15 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
curityContextRepository : HttpSession returned null object for SPRING_SECURITY_CONTEXT
curityContextRepository : No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade#2fe150b5. A new one will be created.
FilterChainProxy : /login/oauth2/code/github?code=c8b1870a2477fef6f032&state=yaVXu6gS7Zcwud2oT_SWsbkj-DbxxxqF46lQ%3D at position 3 of 15 in additional filter chain; firing Filter: 'HeaderWriterFilter'
FilterChainProxy : /login/oauth2/code/github?code=c8b1870a2477fef6f032&state=yaVXu6gS7Zcwud2oT_SWsbkj-DbxxxqF46lQ%3D at position 4 of 15 in additional filter chain; firing Filter: 'LogoutFilter'
tcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', GET]
.AntPathRequestMatcher : Checking match of request : '/login/oauth2/code/github'; against '/logout'
tcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', POST]
.AntPathRequestMatcher : Request 'GET /login/oauth2/code/github' doesn't match 'POST /logout'
tcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', PUT]
.AntPathRequestMatcher : Request 'GET /login/oauth2/code/github' doesn't match 'PUT /logout'
tcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', DELETE]
.AntPathRequestMatcher : Request 'GET /login/oauth2/code/github' doesn't match 'DELETE /logout'
tcher.OrRequestMatcher : No matches found
FilterChainProxy : /login/oauth2/code/github?code=c8b1870a2477fef6f032&state=yaVXu6gS7Zcwud2oT_SWsbkj-DbxxxqF46lQ%3D at position 5 of 15 in additional filter chain; firing Filter: 'OAuth2AuthorizationRequestRedirectFilter'
.AntPathRequestMatcher : Checking match of request : '/login/oauth2/code/github'; against '/oauth2/authorization/{registrationId}'
FilterChainProxy : /login/oauth2/code/github?code=c8b1870a2477fef6f032&state=yaVXu6gS7Zcwud2oT_SWsbkj-DbxxxqF46lQ%3D at position 6 of 15 in additional filter chain; firing Filter: 'OAuth2LoginAuthenticationFilter'
.AntPathRequestMatcher : Checking match of request : '/login/oauth2/code/github'; against '/login/oauth2/code/*'
ginAuthenticationFilter : Request is to process authentication
ion.ProviderManager : Authentication attempt using org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationProvider
stTemplate : HTTP POST https://github.com/login/oauth/access_token
stTemplate : Accept=[application/json, application/*+json]
stTemplate : Writing [{grant_type=[authorization_code], code=[c8b1870a2477fef6f032], redirect_uri=[http://localhost:8080/login/oauth2/code/github]}] as "application/x-www-form-urlencoded;charset=UTF-8"
stTemplate : Response 200 OK
stTemplate : Reading to [org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse] as "application/json;charset=utf-8"
stTemplate : HTTP GET https://api.github.com/user
stTemplate : Accept=[application/json, application/*+json]
stTemplate : Response 200 OK
stTemplate : Reading to [java.util.Map<java.lang.String, java.lang.Object>]
nAuthenticationStrategy : Delegating to org.springframework.security.web.authentication.session.ChangeSessionIdAuthenticationStrategy#10bebcb4
ginAuthenticationFilter : Authentication success. Updating SecurityContextHolder to contain: org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken#19bf8c7c
nticationSuccessHandler : Redirecting to DefaultSavedRequest Url: http://localhost:8080/
RedirectStrategy : Redirecting to 'http://localhost:8080/'
iters.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#169ed862
curityContextRepository : SecurityContext 'org.springframework.security.core.context.SecurityContextImpl#19bf8c7c'
ontextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
.AntPathRequestMatcher : Checking match of request : '/'; against '/VAADIN/**'
.AntPathRequestMatcher : Checking match of request : '/'; against '/favicon.ico'
.AntPathRequestMatcher : Checking match of request : '/'; against '/robots.txt'
.AntPathRequestMatcher : Checking match of request : '/'; against '/manifest.webmanifest'
.AntPathRequestMatcher : Checking match of request : '/'; against '/sw.js'
.AntPathRequestMatcher : Checking match of request : '/'; against '/offline-page.html'
.AntPathRequestMatcher : Checking match of request : '/'; against '/icons/**'
.AntPathRequestMatcher : Checking match of request : '/'; against '/images/**'
.AntPathRequestMatcher : Checking match of request : '/'; against '/frontend/**'
.AntPathRequestMatcher : Checking match of request : '/'; against '/webjars/**'
.AntPathRequestMatcher : Checking match of request : '/'; against '/h2-console/**'
.AntPathRequestMatcher : Checking match of request : '/'; against '/frontend-es5/**'
.AntPathRequestMatcher : Checking match of request : '/'; against '/frontend-es6/**'
FilterChainProxy : / at position 1 of 15 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
FilterChainProxy : / at position 2 of 15 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
curityContextRepository : Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl#19bf8c7c'
FilterChainProxy : / at position 3 of 15 in additional filter chain; firing Filter: 'HeaderWriterFilter'
FilterChainProxy : / at position 4 of 15 in additional filter chain; firing Filter: 'LogoutFilter'
tcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', GET]
.AntPathRequestMatcher : Checking match of request : '/'; against '/logout'
tcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', POST]
.AntPathRequestMatcher : Request 'GET /' doesn't match 'POST /logout'
tcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', PUT]
.AntPathRequestMatcher : Request 'GET /' doesn't match 'PUT /logout'
tcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', DELETE]
.AntPathRequestMatcher : Request 'GET /' doesn't match 'DELETE /logout'
tcher.OrRequestMatcher : No matches found
FilterChainProxy : / at position 5 of 15 in additional filter chain; firing Filter: 'OAuth2AuthorizationRequestRedirectFilter'
.AntPathRequestMatcher : Checking match of request : '/'; against '/oauth2/authorization/{registrationId}'
FilterChainProxy : / at position 6 of 15 in additional filter chain; firing Filter: 'OAuth2LoginAuthenticationFilter'
.AntPathRequestMatcher : Checking match of request : '/'; against '/login/oauth2/code/*'
FilterChainProxy : / at position 7 of 15 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
.AntPathRequestMatcher : Request 'GET /' doesn't match 'POST /login'
FilterChainProxy : / at position 8 of 15 in additional filter chain; firing Filter: 'DefaultLoginPageGeneratingFilter'
FilterChainProxy : / at position 9 of 15 in additional filter chain; firing Filter: 'DefaultLogoutPageGeneratingFilter'
.AntPathRequestMatcher : Checking match of request : '/'; against '/logout'
FilterChainProxy : / at position 10 of 15 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
SavedRequest : pathInfo: both null (property equals)
SavedRequest : queryString: both null (property equals)
SavedRequest : requestURI: arg1=/; arg2=/ (property equals)
SavedRequest : serverPort: arg1=8080; arg2=8080 (property equals)
SavedRequest : requestURL: arg1=http://localhost:8080/; arg2=http://localhost:8080/ (property equals)
SavedRequest : scheme: arg1=http; arg2=http (property equals)
SavedRequest : serverName: arg1=localhost; arg2=localhost (property equals)
SavedRequest : contextPath: arg1=; arg2= (property equals)
SavedRequest : servletPath: arg1=/; arg2=/ (property equals)
FilterChainProxy : / at position 11 of 15 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
FilterChainProxy : / at position 12 of 15 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
FilterChainProxy : / at position 13 of 15 in additional filter chain; firing Filter: 'SessionManagementFilter'
FilterChainProxy : / at position 14 of 15 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
FilterChainProxy : / at position 15 of 15 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
rSecurityInterceptor : Secure object: FilterInvocation: URL: /; Attributes: [authenticated]
.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter#201c9f26, returned: 1
rSecurityInterceptor : Authorization successful
rSecurityInterceptor : RunAsManager did not change Authentication object
FilterChainProxy : / reached end of additional filter chain; proceeding with original chain
ispatcherServlet : GET "/", parameters={}
impleUrlHandlerMapping : Mapped to org.springframework.web.servlet.mvc.ServletForwardingController#46beee3b
iters.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#169ed862
ispatcherServlet : Completed 200 OK
onTranslationFilter : Chain processed normally
ontextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
.AntPathRequestMatcher : Checking match of request : '/VAADIN/build/webcomponentsjs/webcomponents-loader.js'; against '/VAADIN/**'
FilterChainProxy : /VAADIN/build/webcomponentsjs/webcomponents-loader.js has an empty filter list
ispatcherServlet : GET "/VAADIN/build/webcomponentsjs/webcomponents-loader.js", parameters={}
impleUrlHandlerMapping : Mapped to org.springframework.web.servlet.mvc.ServletForwardingController#46beee3b
You may have been bitten by the Vaadin tutorial, the example code of which, if you used it in your app, has basically removed your antmatchers and http configuration properties from the overall equation.
The problem is in the class ConfigureUIServiceInitListener.java
private void beforeEnter(BeforeEnterEvent event) {
if (!LoginView.class.equals(event.getNavigationTarget()) //
&& !SecurityUtils.isUserLoggedIn()) { //
event.rerouteTo(LoginView.class); //
}
}
I ran into a similar problem when trying to make a registration page work. All unauthorized requests are redirected to the login url. Nothing you will do can change this until you do something like this in this method of the class, if you've taken their advice and used it to secure the Vaadin login:
private void beforeEnter(BeforeEnterEvent event) {
if (!LoginView.class.equals(event.getNavigationTarget()) && !**RegisterView.class.equals**(event.getNavigationTarget())//
&& !SecurityUtils.isUserLoggedIn()) { //
event.rerouteTo(LoginView.class); //
}
}
Obviously, our use cases are slightly different. But this is where you'll have to create an exception case because otherwise the beforeEnter method will only allow authenticated requests to access internal framework event. Anything other than LoginView will be redirected to /login. All of your attempts to hammer spring security into allowing your url to be accessed by an as-of-yet authenticated user will be fruitless!
This is highly annoying in the sense that one has to configure http security and then make sure they've added any new exceptions in this method.
Related
I was trying to integrate oauth2 based token having client credential grant type with spring session based authentication. It's working fine with oauth token and the authorities given.
It's not working when I have combined them both. It always calls UsernamePasswordAuthenticationFilter and not OAuth2AuthenticationProcessingFilter
How to make them work together? Here is my ResourceServer configuration
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(SPARKLR_RESOURCE_ID).stateless(false);
}
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
// Since we want the protected resources to be accessible in the UI as well we need
// session creation to be allowed (it's disabled by default in 2.0.6)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.requestMatchers().antMatchers("/api/account/**", "/oauth/users/**", "/oauth/clients/**","/me")
.and()
.authorizeRequests()
.antMatchers("/api/account/**").access("#oauth2.hasScope('read') or (!#oauth2.isOAuth() and hasRole('ROLE_USER'))")
.regexMatchers(HttpMethod.DELETE, "/oauth/users/([^/].*?)/tokens/.*")
.access("#oauth2.clientHasRole('ROLE_CLIENT') and (hasRole('ROLE_USER') or #oauth2.isClient()) and #oauth2.hasScope('write')")
.regexMatchers(HttpMethod.GET, "/oauth/clients/([^/].*?)/users/.*")
.access("#oauth2.clientHasRole('ROLE_CLIENT') and (hasRole('ROLE_USER') or #oauth2.isClient()) and #oauth2.hasScope('read')")
.regexMatchers(HttpMethod.GET, "/oauth/clients/.*")
.access("#oauth2.clientHasRole('ROLE_CLIENT') and #oauth2.isClient() and #oauth2.hasScope('read')");
// #formatter:on
}
}
The issue is, in filter chain OAuth2AuthenticationProcessingFilter is not getting called. So the token validation is not happening for any rest call. Below is the filter chain.
XNIO-2 task-1] o.s.security.web.FilterChainProxy : /api/account at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
XNIO-2 task-1] o.s.security.web.FilterChainProxy : /api/account at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
XNIO-2 task-1] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
XNIO-2 task-1] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
XNIO-2 task-1] o.s.security.web.FilterChainProxy : /api/account at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
XNIO-2 task-1] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#74d294b6
XNIO-2 task-1] o.s.security.web.FilterChainProxy : /api/account at position 4 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
XNIO-2 task-1] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/api/logout', GET]
XNIO-2 task-1] o.s.s.web.util.matcher.OrRequestMatcher : No matches found
XNIO-2 task-1] o.s.security.web.FilterChainProxy : /api/account at position 5 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
XNIO-2 task-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /api/account' doesn't match 'POST /api/authentication
XNIO-2 task-1] o.s.security.web.FilterChainProxy : /api/account at position 6 of 12 in additional filter chain; firing Filter: 'DefaultLoginPageGeneratingFilter'
XNIO-2 task-1] o.s.security.web.FilterChainProxy : /api/account at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
XNIO-2 task-1] o.s.security.web.FilterChainProxy : /api/account at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
XNIO-2 task-1] o.s.security.web.FilterChainProxy : /api/account at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
XNIO-2 task-1] o.s.s.w.a.AnonymousAuthenticationFilter : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken#9055c2bc: Principal: anonymousUser; Credentials
XNIO-2 task-1] o.s.security.web.FilterChainProxy : /api/account at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
XNIO-2 task-1] o.s.security.web.FilterChainProxy : /api/account at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
XNIO-2 task-1] o.s.security.web.FilterChainProxy : /api/account at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
Edit:
I'm trying to merge these 2 projects together. https://github.com/jhipster/jhipster-sample-app and https://github.com/spring-projects/spring-security-oauth/tree/master/samples/oauth2/sparklr
You are using spring boot 1.5 so your resource server filter chain by default has a higher order than the custom filter chain that jhipster added. Either you need to change the orders, or change the pattern matchers so that the OAuth resources are not matched by the main filter chain. The spring boot user guide recommends that you put a custom filter chain in at a specific order (SecurityProperties.ACCESS_OVERRIDE_ORDER). Probably a good a idea to follow that advice.
I've been working with Spring Security for two weeks now and it's working well except for anonymous users and session timeouts.
Use Case #1
An anonymous user can visit the site and view public pages (/home, /about, /signup, etc.) for as long as they want (no session timeouts).
If the user selects a protected page the login screen appears.
Use Case #2
A registered user logs in and can view protected pages.
If their session times out, the invalidSessionUrl page is displayed and the user is directed to log in.
I've read a ton of SO and blog posts but I can't seem to find the solution to Use Case #1. I'm using Spring 4.1.6.RELEASE, Spring Security 4.0.2 RELEASE and Tomcat8.
Here is my security config:
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home", "/about", "/login**", "/thankyou", "/user/signup**", "/errors/**").permitAll()
.regexMatchers("/user/signup/.*").permitAll()
.antMatchers("/recipe/listRecipes*").hasAuthority("GUEST")
.antMatchers("/recipe/addRecipe*").hasAuthority("AUTHOR")
.antMatchers("/admin/**").hasAuthority("ADMIN")
.anyRequest().authenticated()
.expressionHandler(secExpressionHandler())
.and()
.formLogin()
.loginPage("/login")
.failureUrl("/login?err=1")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/thankyou")
.deleteCookies( "JSESSIONID" )
.invalidateHttpSession(false)
.and()
.exceptionHandling()
.accessDeniedPage("/errors/403")
.and()
.rememberMe()
.key("recipeOrganizer")
.tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(960) //.tokenValiditySeconds(1209600)
.rememberMeParameter("rememberMe");
http
.sessionManagement()
.sessionAuthenticationErrorUrl("/errors/402")
.invalidSessionUrl("/errors/invalidSession")
.maximumSessions(1)
.maxSessionsPreventsLogin(true)
.expiredUrl("/errors/expiredSession")
.and()
.sessionFixation().migrateSession();
Any action by an anonymous user after the session expires results in an invalid session exception. The problem is in the security filter chain (see log below) the AnonymousAuthenticationFilter (#11) creates a new session, but the SessionManagementFilter (#12) retrieves the prior expired session, compares it to the new one and throws the invalidsession exception. I want this to happen for logged in users, but not for anonymous users. However, at the time the exception is thrown the security context has been destroyed so I can't know whether the prior session was from an anonymous or logged in user.
Solutions I've considered are:
Set the global session timeout to 24 hours or more then adjust the timeout for registered users in a LoginSuccessHandler and RememberMeSuccessHandler.
Turn off security for the public pages.
Create a separate cookie to indicate the type of user (anon vs. logged in), and query that in the InvalidSessionStrategy to redirect anon users to the /home page.
Create a custom filter that is executed first to identify an anon user (possible?) and simply extend the current session.
Write some javascript or jquery to periodically check the session timeout and reset it for anon users.
Solution #1 may result in issues with expired sessions on the server (not sure if this is a big deal). #2 doesn't feel right to me, especially if a public page may include any info about a logged in user. #3 might work except that the anon user could click on a public link other than the home page but get redirected to the home page because I don't think there's a way to tell in the InvalidSessionStrategy which link they were trying to access? I'm not sure if #4 will work or not - haven't tried it yet. #5 might also work but it increases network traffic?
I'm hoping that someone can point me to a practical solution. This has to be something that many sites deal with but I'm going around in circles trying to solve. Thanks in advance for any advice or tips.
Here's a portion of a log to illustrate what happens. I've set the session timeout to 60 seconds for testing purposes.
Initial access to website
20:49:29.823 DEBUG: org.springframework.security.web.FilterChainProxy - / at position 11 of 14 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
20:49:29.839 DEBUG: org.springframework.security.web.authentication.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken#9055c2bc: Principal: anonymousUser; 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_ANONYMOUS'
20:49:29.839 DEBUG: org.springframework.security.web.FilterChainProxy - / at position 12 of 14 in additional filter chain; firing Filter: 'SessionManagementFilter'
20:49:29.839 DEBUG: org.springframework.security.web.FilterChainProxy - / at position 13 of 14 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
20:49:29.839 DEBUG: org.springframework.security.web.FilterChainProxy - / at position 14 of 14 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
20:49:29.839 DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/'; against '/'
20:49:29.839 DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /; Attributes: [permitAll]
20:49:29.854 DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken#9055c2bc: Principal: anonymousUser; 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_ANONYMOUS
20:49:29.871 DEBUG: org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter#ff577, returned: 1
20:49:29.871 DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Authorization successful
20:49:30.136 DEBUG: net.mycompany.myapp.config.SessionListener - AuthenticationSuccess - principal: anonymousUser
20:49:30.167 DEBUG: net.mycompany.myapp.config.SessionListener - AuthenticationSuccess - authority contains: ROLE_ANONYMOUS
20:49:30.167 INFO : net.mycompany.myapp.config.SessionListener - sessionCreated: Session created on: Mon Sep 21 20:49:30 CDT 2015
20:49:30.167 INFO : net.mycompany.myapp.config.SessionListener - sessionCreated: Session last accessed on: Mon Sep 21 20:49:30 CDT 2015
20:49:30.167 INFO : net.mycompany.myapp.config.SessionListener - sessionCreated: Session expires after: 60 seconds
20:49:30.167 INFO : net.mycompany.myapp.config.SessionListener - sessionCreated: Session ID: CA34FE74B56B8EF94181B1231A7D4FF6
Session times out after 60 seconds
20:50:46.015 INFO : net.mycompany.myapp.config.SessionDestroyedListener - destroyedEvent
20:50:46.015 INFO : net.mycompany.myapp.config.SessionDestroyedListener - object:org.springframework.security.web.session.HttpSessionDestroyedEvent[source=org.apache.catalina.session.StandardSessionFacade#17827f3e]
20:50:46.015 INFO : net.mycompany.myapp.config.SessionListener - sessionDestroyed: Session created on: Mon Sep 21 20:49:30 CDT 2015
20:50:46.015 INFO : net.mycompany.myapp.config.SessionListener - sessionDestroyed: Session last accessed on: Mon Sep 21 20:49:32 CDT 2015
20:50:46.015 INFO : net.mycompany.myapp.config.SessionListener - sessionDestroyed: Session expires after: 60 seconds
20:50:46.015 INFO : net.mycompany.myapp.config.SessionListener - sessionDestroyed: Session ID: CA34FE74B56B8EF94181B1231A7D4FF6
Click on "/home" link (unsecured)
20:50:53.927 DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/home'; against '/resources/**'
20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 1 of 14 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 2 of 14 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
20:50:53.927 DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - No HttpSession currently exists
20:50:53.927 DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: null. A new one will be created.
20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 3 of 14 in additional filter chain; firing Filter: 'HeaderWriterFilter'
20:50:53.927 DEBUG: org.springframework.security.web.header.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#4c668dec
20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 4 of 14 in additional filter chain; firing Filter: 'CsrfFilter'
20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 5 of 14 in additional filter chain; firing Filter: 'LogoutFilter'
20:50:53.927 DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /home' doesn't match 'POST /logout
20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 6 of 14 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
20:50:53.927 DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Request 'GET /home' doesn't match 'POST /login
20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 7 of 14 in additional filter chain; firing Filter: 'ConcurrentSessionFilter'
20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 8 of 14 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 9 of 14 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 10 of 14 in additional filter chain; firing Filter: 'RememberMeAuthenticationFilter'
20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 11 of 14 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
20:50:53.927 DEBUG: org.springframework.security.web.authentication.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken#9055c2bc: Principal: anonymousUser; 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_ANONYMOUS'
20:50:53.927 DEBUG: org.springframework.security.web.FilterChainProxy - /home at position 12 of 14 in additional filter chain; firing Filter: 'SessionManagementFilter'
20:50:53.927 DEBUG: org.springframework.security.web.session.SessionManagementFilter - Requested session ID CA34FE74B56B8EF94181B1231A7D4FF6 is invalid.
20:50:53.927 DEBUG: org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy - Starting new session (if required) and redirecting to '/errors/invalidSession'
20:50:53.927 DEBUG: net.mycompany.myapp.config.SessionListener - AuthenticationSuccess - principal: anonymousUser
20:50:53.927 DEBUG: net.mycompany.myapp.config.SessionListener - AuthenticationSuccess - authority contains: ROLE_ANONYMOUS
20:50:53.927 INFO : net.mycompany.myapp.config.SessionListener - sessionCreated: Session created on: Mon Sep 21 20:50:53 CDT 2015
20:50:53.927 INFO : net.mycompany.myapp.config.SessionListener - sessionCreated: Session last accessed on: Mon Sep 21 20:50:53 CDT 2015
20:50:53.942 INFO : net.mycompany.myapp.config.SessionListener - sessionCreated: Session expires after: 60 seconds
20:50:53.942 INFO : net.mycompany.myapp.config.SessionListener - sessionCreated: Session ID: 6F7FD6230BC075B7768648BBBC08E3F4
20:50:53.942 DEBUG: org.springframework.security.web.session.HttpSessionEventPublisher - Publishing event: org.springframework.security.web.session.HttpSessionCreatedEvent[source=org.apache.catalina.session.StandardSessionFacade#412cbe09]
20:50:53.942 DEBUG: org.springframework.security.web.DefaultRedirectStrategy - Redirecting to '/myapp/errors/invalidSession'
I posted a similar question a few days after this one: Why does anonymous user get redirected to expiredsessionurl by Spring Security, for which I've posted an answer. Solution #2 above works, but I don't like turning off all security even for public pages. What I ended up implementing was a combination of #3 and #4. See the linked question for the full answer.
This is a old question but I have a similar problem even now (Spring Security 5.5.1)
I found some answers but they seemed too fragile for me:
Why does anonymous user get redirected to expiredsessionurl by Spring Security (uses Cookie to detect)
Spring Security getting the acess attributes of patterns in intercept-url (using custom url interceptor)
This is what works for me (using a custom filter for Spring Security)
/**
* https://doanduyhai.wordpress.com/2012/04/21/spring-security-part-vi-session-timeout-handling-for-ajax-calls/
* 1. detect session expiry and ajax request --> send custom error code so that
* client side can detect and handle as necessary if not, it will be a redirect
* to login page and with 200 response
*
* https://forum.primefaces.org/viewtopic.php?t=16735 (use xml partial response for redirect)
* #author RadianceOng
*/
public class AjaxTimeoutRedirectFilter extends GenericFilterBean {
static Logger lg = Logger.getLogger(AjaxTimeoutRedirectFilter.class);
private ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer();
private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
String invalidSessionUrl;
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (IOException ex) {
throw ex;
} catch (Exception ex) {
Throwable[] causeChain = throwableAnalyzer.determineCauseChain(ex);
Exception ase = (AuthenticationException) throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, causeChain);
if (ase == null) {
ase = (AccessDeniedException) throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
}
if (ase != null) {
if (ase instanceof AuthenticationException) {
throw (AuthenticationException) ase;
} else if (ase instanceof AccessDeniedException) {
AccessDeniedException ade = (AccessDeniedException) ase;
if (authenticationTrustResolver.isAnonymous(SecurityContextHolder.getContext().getAuthentication())) {
logger.trace("User session expired or not logged in yet and trying to access unauthorized resource");
HttpServletRequest httpReq = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
if (isAjaxRequest(httpReq)) {
logger.trace("Ajax call detected, redirecting");
/**
* Session expiry check is copied from SessionManagementFilter
* accessdenied check is derived from ExceptionTranslationFilter
* No idea what is the order... This is a workaround.
*/
final String redirectUrl = invalidSessionUrl;
sendAjaxRedirect(resp, httpReq, redirectUrl);
} else {
logger.trace("Normal call detected, redirecting");
new SimpleRedirectInvalidSessionStrategy(invalidSessionUrl).onInvalidSessionDetected(httpReq, resp);
}
} else {
throw ade;
}
}
} else {
throw ex;
}
}
}
public String getInvalidSessionUrl() {
return invalidSessionUrl;
}
public void setInvalidSessionUrl(String invalidSessionUrl) {
this.invalidSessionUrl = invalidSessionUrl;
}
private boolean isAjaxRequest(HttpServletRequest httpReq) {
return new AjaxRedirectUtils().isAjaxRequest(httpReq);
}
private void sendAjaxRedirect(HttpServletResponse resp, HttpServletRequest httpReq, final String redirectUrl) throws IOException {
new AjaxRedirectUtils().sendAjaxRedirect(resp, httpReq, redirectUrl);
}
private static final class DefaultThrowableAnalyzer extends ThrowableAnalyzer {
/**
* #see
* org.springframework.security.web.util.ThrowableAnalyzer#initExtractorMap()
*/
protected void initExtractorMap() {
super.initExtractorMap();
registerExtractor(ServletException.class, new ThrowableCauseExtractor() {
public Throwable extractCause(Throwable throwable) {
ThrowableAnalyzer.verifyThrowableHierarchy(throwable, ServletException.class);
return ((ServletException) throwable).getRootCause();
}
});
}
}
}
In the XML configuration for Spring Security, add the filter after EXCEPTION_TRANSLATION_FILTER so that it can detect access denied
<http>
<custom-filter ref="ajaxTimeoutRedirectFilter" after="EXCEPTION_TRANSLATION_FILTER"/>
</http>
Note that if you use the built-in session management, make sure you do not use the invalid-session-url or related else that will take effect instead
<http>
<session-management>
</session-management>
</http>
This filter also caters for Ajax redirection. I left that out as that is not relevant to the question
In summary, what this achieves is to redirect only if access denied. So non- logged-in users will not get redirected unless they access a unauthorized page. Logged-in users whose sessions expire will get redirected when they access an unauthorized page.
I added spring security filter to my MVC project with java config. The project have a /home method which only allow authenticated user to access.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/home").authenticated()
.and().formLogin()
.and().httpBasic();
}
which is working as expected, when I request "http://localhost:8080/project/home" it kicks my out to "/login". After successful login, I can now view "/home"
then I add OAuth2, pretty much same setting as Sparklr2 example
#Configuration
public class OAuthServerConfig {
private static final String RESOURCE_ID = "cpe";
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID).stateless(false);
}
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
// Since we want the protected resources to be accessible in the UI as well we need
// session creation to be allowed (it's disabled by default in 2.0.6)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.requestMatchers().antMatchers("/device/**", "/oauth/users/**", "/oauth/clients/**","/me")
.and()
.authorizeRequests()
.antMatchers("/me").access("#oauth2.hasScope('read')")
.antMatchers("/device").access("#oauth2.hasScope('read') or (!#oauth2.isOAuth() and hasRole('ROLE_USER'))")
//.antMatchers("/device/trusted/**").access("#oauth2.hasScope('trust')")
.antMatchers("/device/user/**").access("#oauth2.hasScope('trust')")
.antMatchers("/device/**").access("#oauth2.hasScope('read') or (!#oauth2.isOAuth() and hasRole('ROLE_USER'))")
.antMatchers("/device/register").access("#oauth2.hasScope('write') or (!#oauth2.isOAuth() and hasRole('ROLE_USER'))")
.regexMatchers(HttpMethod.DELETE, "/oauth/users/([^/].*?)/tokens/.*")
.access("#oauth2.clientHasRole('ROLE_CLIENT') and (hasRole('ROLE_USER') or #oauth2.isClient()) and #oauth2.hasScope('write')")
.regexMatchers(HttpMethod.GET, "/oauth/clients/([^/].*?)/users/.*")
.access("#oauth2.clientHasRole('ROLE_CLIENT') and (hasRole('ROLE_USER') or #oauth2.isClient()) and #oauth2.hasScope('read')")
.regexMatchers(HttpMethod.GET, "/oauth/clients/.*")
.access("#oauth2.clientHasRole('ROLE_CLIENT') and #oauth2.isClient() and #oauth2.hasScope('read')");
// #formatter:on
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Autowired
private TokenStore tokenStore;
#Autowired
private UserApprovalHandler userApprovalHandler;
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
//needs to be change
#Value("${tonr.redirect:http://localhost:8080/tonr2/sparklr/redirect}")
private String tonrRedirectUri;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//JdbcClientDetailsServiceBuilder
clients.jdbc(dataSource);
}
#Bean
public TokenStore tokenStore() {
//return new InMemoryTokenStore();
return new JdbcTokenStore(dataSource);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler)
.authenticationManager(authenticationManager);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.realm("dragonfly/client");
}
}
protected static class Stuff {
#Autowired
private ClientDetailsService clientDetailsService;
#Autowired
private TokenStore tokenStore;
#Bean
public ApprovalStore approvalStore() throws Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}
#Bean
#Lazy
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public DragonflyUserApprovalHandler userApprovalHandler() throws Exception {
DragonflyUserApprovalHandler handler = new DragonflyUserApprovalHandler();
handler.setApprovalStore(approvalStore());
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
handler.setUseApprovalStore(true);
return handler;
}
}
}
with only 1 client detail
client.dataSource(dataSource)
.withClient("my-trusted-client-with-secret")
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust")
.secret("somesecret");
I run this on my tomcat server, the OAuth works, I make request to /oauth/token, it successfully returns token to me.
I restart my application, then request /home without login, it shows up my home view with full content, without login, I couldn't understand. here is the server log when I request /home
it try to match OAuth filter first, which has Order 0. no match found. then check session, no session found, create a new one.
then it says it is not OAuth request and no token found.
and it continues down the filter chain, AnonymousAuthenticationFilter, then granted ROLE_ANONYMOUS, by that it response to the request with successful.
which is the opposite to my rule .antMatchers("/home").authenticated()
How does that happen?
14:40:51.843 [http-nio-8080-exec-6] DEBUG
o.s.s.w.u.matcher.OrRequestMatcher - Trying to match using Ant
[pattern='/oauth/token'] 14:40:51.843 [http-nio-8080-exec-6] DEBUG
o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request :
'/home'; against '/oauth/token' 14:40:51.843 [http-nio-8080-exec-6]
DEBUG o.s.s.w.u.matcher.OrRequestMatcher - Trying to match using Ant
[pattern='/oauth/token_key'] 14:40:51.843 [http-nio-8080-exec-6] DEBUG
o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request :
'/home'; against '/oauth/token_key' 14:40:51.843
[http-nio-8080-exec-6] DEBUG o.s.s.w.u.matcher.OrRequestMatcher -
Trying to match using Ant [pattern='/oauth/check_token'] 14:40:51.843
[http-nio-8080-exec-6] DEBUG o.s.s.w.u.m.AntPathRequestMatcher -
Checking match of request : '/home'; against '/oauth/check_token'
14:40:51.843 [http-nio-8080-exec-6] DEBUG
o.s.s.w.u.matcher.OrRequestMatcher - No matches found 14:40:51.843
[http-nio-8080-exec-6] DEBUG o.s.s.w.u.matcher.OrRequestMatcher -
Trying to match using
org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration$NotOAuthRequestMatcher#7926d3d3
14:40:51.843 [http-nio-8080-exec-6] DEBUG
o.s.s.w.u.matcher.OrRequestMatcher - matched 14:40:51.843
[http-nio-8080-exec-6] DEBUG o.s.security.web.FilterChainProxy - /home
at position 1 of 11 in additional filter chain; firing Filter:
'WebAsyncManagerIntegrationFilter' 14:40:51.844 [http-nio-8080-exec-6]
DEBUG o.s.security.web.FilterChainProxy - /home at position 2 of 11 in
additional filter chain; firing Filter:
'SecurityContextPersistenceFilter' 14:40:51.844 [http-nio-8080-exec-6]
DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - No HttpSession
currently exists 14:40:51.844 [http-nio-8080-exec-6] DEBUG
o.s.s.w.c.HttpSessionSecurityContextRepository - No SecurityContext
was available from the HttpSession: null. A new one will be created.
14:40:51.844 [http-nio-8080-exec-6] DEBUG
o.s.security.web.FilterChainProxy - /home at position 3 of 11 in
additional filter chain; firing Filter: 'HeaderWriterFilter'
14:40:51.844 [http-nio-8080-exec-6] DEBUG
o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since
it did not match the requestMatcher
org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#3d823ea7
14:40:51.844 [http-nio-8080-exec-6] DEBUG
o.s.security.web.FilterChainProxy - /home at position 4 of 11 in
additional filter chain; firing Filter: 'LogoutFilter' 14:40:51.844
[http-nio-8080-exec-6] DEBUG o.s.s.w.u.m.AntPathRequestMatcher -
Checking match of request : '/home'; against '/logout' 14:40:51.844
[http-nio-8080-exec-6] DEBUG o.s.security.web.FilterChainProxy - /home
at position 5 of 11 in additional filter chain; firing Filter:
'OAuth2AuthenticationProcessingFilter' 14:40:51.844
[http-nio-8080-exec-6] DEBUG o.s.s.o.p.a.BearerTokenExtractor - Token
not found in headers. Trying request parameters. 14:40:51.844
[http-nio-8080-exec-6] DEBUG o.s.s.o.p.a.BearerTokenExtractor - Token
not found in request parameters. Not an OAuth2 request. 14:40:51.844
[http-nio-8080-exec-6] DEBUG
o.s.s.o.p.a.OAuth2AuthenticationProcessingFilter - No token in
request, will continue chain. 14:40:51.844 [http-nio-8080-exec-6]
DEBUG o.s.security.web.FilterChainProxy - /home at position 6 of 11 in
additional filter chain; firing Filter: 'RequestCacheAwareFilter'
14:40:51.844 [http-nio-8080-exec-6] DEBUG
o.s.security.web.FilterChainProxy - /home at position 7 of 11 in
additional filter chain; firing Filter:
'SecurityContextHolderAwareRequestFilter' 14:40:51.844
[http-nio-8080-exec-6] DEBUG o.s.security.web.FilterChainProxy - /home
at position 8 of 11 in additional filter chain; firing Filter:
'AnonymousAuthenticationFilter' 14:40:51.844 [http-nio-8080-exec-6]
DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Populated
SecurityContextHolder with anonymous token:
'org.springframework.security.authentication.AnonymousAuthenticationToken#9055c2bc:
Principal: anonymousUser; 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_ANONYMOUS' 14:40:51.844 [http-nio-8080-exec-6] DEBUG
o.s.security.web.FilterChainProxy - /home at position 9 of 11 in
additional filter chain; firing Filter: 'SessionManagementFilter'
14:40:51.844 [http-nio-8080-exec-6] DEBUG
o.s.security.web.FilterChainProxy - /home at position 10 of 11 in
additional filter chain; firing Filter: 'ExceptionTranslationFilter'
14:40:51.844 [http-nio-8080-exec-6] DEBUG
o.s.security.web.FilterChainProxy - /home at position 11 of 11 in
additional filter chain; firing Filter: 'FilterSecurityInterceptor'
14:40:51.844 [http-nio-8080-exec-6] DEBUG
o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request :
'/home'; against '/me' 14:40:51.844 [http-nio-8080-exec-6] DEBUG
o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request :
'/home'; against '/device' 14:40:51.844 [http-nio-8080-exec-6] DEBUG
o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request :
'/home'; against '/device/user/' 14:40:51.844 [http-nio-8080-exec-6]
DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request :
'/home'; against '/device/' 14:40:51.844 [http-nio-8080-exec-6]
DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request :
'/home'; against '/device/register' 14:40:51.844
[http-nio-8080-exec-6] DEBUG o.s.s.w.u.m.RegexRequestMatcher -
Checking match of request : '/home'; against
'/oauth/clients/([^/].?)/users/.' 14:40:51.844
[http-nio-8080-exec-6] DEBUG o.s.s.w.u.m.RegexRequestMatcher -
Checking match of request : '/home'; against '/oauth/clients/.'
14:40:51.844 [http-nio-8080-exec-6] DEBUG
o.s.s.w.a.i.FilterSecurityInterceptor - Public object - authentication
not attempted 14:40:51.844 [http-nio-8080-exec-6] DEBUG
o.s.security.web.FilterChainProxy - /home reached end of additional
filter chain; proceeding with original chain 14:40:51.844
[http-nio-8080-exec-6] DEBUG o.s.web.servlet.DispatcherServlet -
DispatcherServlet with name 'dispatcher' processing GET request for
[/Dragonfly/home] 14:40:51.844 [http-nio-8080-exec-6] DEBUG
o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method
for path /home 14:40:51.845 [http-nio-8080-exec-6] DEBUG
o.s.w.s.m.m.a.RequestMappingHandlerMapping - Returning handler method
[public java.lang.String
com.umedia.Dragonfly.controller.HomeController.home()] 14:40:51.845
[http-nio-8080-exec-6] DEBUG o.s.b.f.s.DefaultListableBeanFactory -
Returning cached instance of singleton bean 'homeController'
14:40:51.845 [http-nio-8080-exec-6] DEBUG
o.s.web.servlet.DispatcherServlet - Last-Modified value for
[/Dragonfly/home] is: -1 14:40:51.845 [http-nio-8080-exec-6] DEBUG
o.s.web.servlet.DispatcherServlet - Rendering view
[org.springframework.web.servlet.view.JstlView: name 'home'; URL
[/WEB-INF/views/home.jsp]] in DispatcherServlet with name 'dispatcher'
14:40:51.845 [http-nio-8080-exec-6] DEBUG
o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of
singleton bean 'requestDataValueProcessor' 14:40:51.845
[http-nio-8080-exec-6] DEBUG o.s.web.servlet.view.JstlView -
Forwarding to resource [/WEB-INF/views/home.jsp] in
InternalResourceView 'home' 14:40:51.847 [http-nio-8080-exec-6] DEBUG
o.s.web.servlet.DispatcherServlet - Successfully completed request
14:40:51.847 [http-nio-8080-exec-6] DEBUG
o.s.s.w.a.ExceptionTranslationFilter - Chain processed normally
14:40:51.847 [http-nio-8080-exec-6] DEBUG
o.s.s.w.c.HttpSessionSecurityContextRepository - SecurityContext is
empty or contents are anonymous - context will not be stored in
HttpSession. 14:40:51.847 [http-nio-8080-exec-6] DEBUG
o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now
cleared, as request processing completed 14:40:51.865
[http-nio-8080-exec-7] DEBUG o.s.s.w.u.matcher.OrRequestMatcher -
Trying to match using Ant [pattern='/oauth/token'] 14:40:51.865
[http-nio-8080-exec-7] DEBUG o.s.s.w.u.m.AntPathRequestMatcher -
Checking match of request : '/resources/05.jpg'; against
'/oauth/token' 14:40:51.865 [http-nio-8080-exec-7] DEBUG
o.s.s.w.u.matcher.OrRequestMatcher - Trying to match using Ant
[pattern='/oauth/token_key'] 14:40:51.865 [http-nio-8080-exec-7] DEBUG
o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request :
'/resources/05.jpg'; against '/oauth/token_key' 14:40:51.865
[http-nio-8080-exec-7] DEBUG o.s.s.w.u.matcher.OrRequestMatcher -
Trying to match using Ant [pattern='/oauth/check_token'] 14:40:51.865
[http-nio-8080-exec-7] DEBUG o.s.s.w.u.m.AntPathRequestMatcher -
Checking match of request : '/resources/05.jpg'; against
'/oauth/check_token' 14:40:51.865 [http-nio-8080-exec-7] DEBUG
o.s.s.w.u.matcher.OrRequestMatcher - No matches found 14:40:51.865
[http-nio-8080-exec-7] DEBUG o.s.s.w.u.matcher.OrRequestMatcher -
Trying to match using
org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration$NotOAuthRequestMatcher#7926d3d3
14:40:51.865 [http-nio-8080-exec-7] DEBUG
o.s.s.w.u.matcher.OrRequestMatcher - matched 14:40:51.865
[http-nio-8080-exec-7] DEBUG o.s.security.web.FilterChainProxy -
/resources/05.jpg at position 1 of 11 in additional filter chain;
firing Filter: 'WebAsyncManagerIntegrationFilter' 14:40:51.865
[http-nio-8080-exec-7] DEBUG o.s.security.web.FilterChainProxy -
/resources/05.jpg at position 2 of 11 in additional filter chain;
firing Filter: 'SecurityContextPersistenceFilter' 14:40:51.865
[http-nio-8080-exec-7] DEBUG
o.s.s.w.c.HttpSessionSecurityContextRepository - HttpSession returned
null object for SPRING_SECURITY_CONTEXT 14:40:51.865
[http-nio-8080-exec-7] DEBUG
o.s.s.w.c.HttpSessionSecurityContextRepository - No SecurityContext
was available from the HttpSession:
org.apache.catalina.session.StandardSessionFacade#ba8ab6a. A new one
will be created. 14:40:51.865 [http-nio-8080-exec-7] DEBUG
o.s.security.web.FilterChainProxy - /resources/05.jpg at position 3 of
11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
14:40:51.865 [http-nio-8080-exec-7] DEBUG
o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since
it did not match the requestMatcher
org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#3d823ea7
14:40:51.865 [http-nio-8080-exec-7] DEBUG
o.s.security.web.FilterChainProxy - /resources/05.jpg at position 4 of
11 in additional filter chain; firing Filter: 'LogoutFilter'
14:40:51.865 [http-nio-8080-exec-7] DEBUG
o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request :
'/resources/05.jpg'; against '/logout' 14:40:51.865
[http-nio-8080-exec-7] DEBUG o.s.security.web.FilterChainProxy -
/resources/05.jpg at position 5 of 11 in additional filter chain;
firing Filter: 'OAuth2AuthenticationProcessingFilter' 14:40:51.865
[http-nio-8080-exec-7] DEBUG o.s.s.o.p.a.BearerTokenExtractor - Token
not found in headers. Trying request parameters. 14:40:51.865
[http-nio-8080-exec-7] DEBUG o.s.s.o.p.a.BearerTokenExtractor - Token
not found in request parameters. Not an OAuth2 request. 14:40:51.865
[http-nio-8080-exec-7] DEBUG
o.s.s.o.p.a.OAuth2AuthenticationProcessingFilter - No token in
request, will continue chain. 14:40:51.865 [http-nio-8080-exec-7]
DEBUG o.s.security.web.FilterChainProxy - /resources/05.jpg at
position 6 of 11 in additional filter chain; firing Filter:
'RequestCacheAwareFilter' 14:40:51.865 [http-nio-8080-exec-7] DEBUG
o.s.security.web.FilterChainProxy - /resources/05.jpg at position 7 of
11 in additional filter chain; firing Filter:
'SecurityContextHolderAwareRequestFilter' 14:40:51.865
[http-nio-8080-exec-7] DEBUG o.s.security.web.FilterChainProxy -
/resources/05.jpg at position 8 of 11 in additional filter chain;
firing Filter: 'AnonymousAuthenticationFilter' 14:40:51.865
[http-nio-8080-exec-7] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter -
Populated SecurityContextHolder with anonymous token:
'org.springframework.security.authentication.AnonymousAuthenticationToken#6faeba70:
Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated:
true; Details:
org.springframework.security.web.authentication.WebAuthenticationDetails#fffbcba8:
RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId:
737F9CEEE6747FABCB433614EF76CF3B; Granted Authorities: ROLE_ANONYMOUS'
14:40:51.865 [http-nio-8080-exec-7] DEBUG
o.s.security.web.FilterChainProxy - /resources/05.jpg at position 9 of
11 in additional filter chain; firing Filter:
'SessionManagementFilter' 14:40:51.865 [http-nio-8080-exec-7] DEBUG
o.s.security.web.FilterChainProxy - /resources/05.jpg at position 10
of 11 in additional filter chain; firing Filter:
'ExceptionTranslationFilter' 14:40:51.865 [http-nio-8080-exec-7] DEBUG
o.s.security.web.FilterChainProxy - /resources/05.jpg at position 11
of 11 in additional filter chain; firing Filter:
'FilterSecurityInterceptor' 14:40:51.865 [http-nio-8080-exec-7] DEBUG
o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request :
'/resources/05.jpg'; against '/me' 14:40:51.865 [http-nio-8080-exec-7]
DEBUG o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request :
'/resources/05.jpg'; against '/device' 14:40:51.865
[http-nio-8080-exec-7] DEBUG o.s.s.w.u.m.AntPathRequestMatcher -
Checking match of request : '/resources/05.jpg'; against
'/device/user/' 14:40:51.865 [http-nio-8080-exec-7] DEBUG
o.s.s.w.u.m.AntPathRequestMatcher - Checking match of request :
'/resources/05.jpg'; against '/device/' 14:40:51.865
[http-nio-8080-exec-7] DEBUG o.s.s.w.u.m.AntPathRequestMatcher -
Checking match of request : '/resources/05.jpg'; against
'/device/register' 14:40:51.865 [http-nio-8080-exec-7] DEBUG
o.s.s.w.u.m.RegexRequestMatcher - Checking match of request :
'/resources/05.jpg'; against '/oauth/clients/([^/].?)/users/.'
14:40:51.865 [http-nio-8080-exec-7] DEBUG
o.s.s.w.u.m.RegexRequestMatcher - Checking match of request :
'/resources/05.jpg'; against '/oauth/clients/.' 14:40:51.865
[http-nio-8080-exec-7] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor -
Public object - authentication not attempted 14:40:51.865
[http-nio-8080-exec-7] DEBUG o.s.security.web.FilterChainProxy -
/resources/05.jpg reached end of additional filter chain; proceeding
with original chain 14:40:51.865 [http-nio-8080-exec-7] DEBUG
o.s.web.servlet.DispatcherServlet - DispatcherServlet with name
'dispatcher' processing GET request for [/Dragonfly/resources/05.jpg]
14:40:51.865 [http-nio-8080-exec-7] DEBUG
o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method
for path /resources/05.jpg 14:40:51.866 [http-nio-8080-exec-7] DEBUG
o.s.w.s.m.m.a.RequestMappingHandlerMapping - Did not find handler
method for [/resources/05.jpg] 14:40:51.866 [http-nio-8080-exec-7]
DEBUG o.s.s.o.p.e.FrameworkEndpointHandlerMapping - Looking up handler
method for path /resources/05.jpg 14:40:51.866 [http-nio-8080-exec-7]
DEBUG o.s.s.o.p.e.FrameworkEndpointHandlerMapping - Did not find
handler method for [/resources/05.jpg] 14:40:51.866
[http-nio-8080-exec-7] DEBUG o.s.w.s.h.SimpleUrlHandlerMapping -
Matching patterns for request [/resources/05.jpg] are [/resources/**]
14:40:51.866 [http-nio-8080-exec-7] DEBUG
o.s.w.s.h.SimpleUrlHandlerMapping - URI Template variables for request
[/resources/05.jpg] are {} 14:40:51.866 [http-nio-8080-exec-7] DEBUG
o.s.w.s.h.SimpleUrlHandlerMapping - Mapping [/resources/05.jpg] to
HandlerExecutionChain with handler [ResourceHttpRequestHandler
[locations=[ServletContext resource [/resources/]],
resolvers=[org.springframework.web.servlet.resource.PathResourceResolver#20458412]]]
and 1 interceptor 14:40:51.866 [http-nio-8080-exec-7] DEBUG
o.s.web.servlet.DispatcherServlet - Last-Modified value for
[/Dragonfly/resources/05.jpg] is: -1 14:40:51.867
[http-nio-8080-exec-7] DEBUG o.s.web.servlet.DispatcherServlet - Null
ModelAndView returned to DispatcherServlet with name 'dispatcher':
assuming HandlerAdapter completed request handling 14:40:51.867
[http-nio-8080-exec-7] DEBUG o.s.web.servlet.DispatcherServlet -
Successfully completed request 14:40:51.867 [http-nio-8080-exec-7]
DEBUG o.s.s.w.a.ExceptionTranslationFilter - Chain processed normally
14:40:51.867 [http-nio-8080-exec-7] DEBUG
o.s.s.w.c.HttpSessionSecurityContextRepository - SecurityContext is
empty or contents are anonymous - context will not be stored in
HttpSession. 14:40:51.867 [http-nio-8080-exec-7] DEBUG
o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now
cleared, as request processing completed
it looks like you have problems with your project setup and pom configuration
You added spring boot dependencies, yet you don't use spring boot.
Your project is package as jar, yet you you have WEB-INF and use WebApplicationInitializer rather than spring boot
Your pom dependencies is wrong
I have modified several things:
move WebContent folder and rename it to src/main/webapp
update your pom configuration
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.umedia</groupId>
<artifactId>Dragonfly</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>Dragonfly</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.4.5</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1201-jdbc41</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>1.1.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.0</version>
<configuration>
<path>/</path>
</configuration>
</plugin>
</plugins>
<finalName>liveBLE</finalName>
</build>
</project>
run it using mvn tomcat7:run. If I access /home I will be redirected to login page and if I access /device i will get
<oauth>
<error_description>
Full authentication is required to access this resource
</error_description>
<error>unauthorized</error>
</oauth>
This is the expected behavior using OAuth and Spring security.
As per the post Spring Security: Redirect to invalid-session-url instead of logout-success-url on successful logout, when logging out of a session Spring Security redirects to the user defined invalid-session-url.
<session-management invalid-session-url="/invalidSession.jsp">
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</session-management>
However, if a logout-success url is set
<logout invalidate-session="true"
logout-success-url="/logoutSuccess.jsp"
logout-url="/logout" />
Spring still redirects to the invalid session URL after redirecting to the logout-success url. This happens even when the logoutSuccess url is unsecured. I.e.,
<intercept-url pattern="/logoutSuccess.jsp*" access="permitAll"/>
Is this a Spring bug? Since the logout-success-url is set and unsecured it seems that the user should not be redirected to invalid session url after reaching the logout success url.
The log looks as follows:
INFO: [DEBUG,SimpleUrlLogoutSuccessHandler] Using default Url: /logoutSuccess.jsp
INFO: [DEBUG,DefaultRedirectStrategy] Redirecting to '/Application/logoutSuccess.jsp'
INFO: [DEBUG,HttpSessionSecurityContextRepository] SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
INFO: [DEBUG,SecurityContextPersistenceFilter] SecurityContextHolder now cleared, as request processing completed
INFO: [DEBUG,FilterChainProxy] /logoutSuccess.jsp at position 1 of 10 in additional filter chain; firing Filter: 'ConcurrentSessionFilter'
INFO: [DEBUG,FilterChainProxy] /logoutSuccess.jsp at position 2 of 10 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
INFO: [DEBUG,HttpSessionSecurityContextRepository] No HttpSession currently exists
INFO: [DEBUG,HttpSessionSecurityContextRepository] No SecurityContext was available from the HttpSession: null. A new one will be created.
INFO: [DEBUG,FilterChainProxy] /logoutSuccess.jsp at position 3 of 10 in additional filter chain; firing Filter: 'LogoutFilter'
INFO: [DEBUG,FilterChainProxy] /logoutSuccess.jsp at position 4 of 10 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
INFO: [DEBUG,FilterChainProxy] /logoutSuccess.jsp at position 5 of 10 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
INFO: [DEBUG,FilterChainProxy] /logoutSuccess.jsp at position 6 of 10 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
INFO: [DEBUG,FilterChainProxy] /logoutSuccess.jsp at position 7 of 10 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
INFO: [DEBUG,AnonymousAuthenticationFilter] Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken#9055c2bc: Principal: anonymousUser; 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_ANONYMOUS'
INFO: [DEBUG,FilterChainProxy] /logoutSuccess.jsp at position 8 of 10 in additional filter chain; firing Filter: 'SessionManagementFilter'
INFO: [DEBUG,SessionManagementFilter] Requested session ID a396530a530b344ff531ab657e32 is invalid.
INFO: [DEBUG,SimpleRedirectInvalidSessionStrategy] Starting new session (if required) and redirecting to '/invalidsession.jsp'
INFO: [DEBUG,HttpSessionEventPublisher] Publishing event: org.springframework.security.web.session.HttpSessionCreatedEvent[source=org.apache.catalina.session.StandardSessionFacade#564c4200]
INFO: [DEBUG,DefaultRedirectStrategy] Redirecting to '/Application/invalidsession.jsp'
This is explained in the reference manual.
To summarise, the "invalid session" functionality is based on the validity of the submitted session cookie, so if you access the site (or more specifically, the security filter chain) after logging out, and you still have a JSESSIONID cookie, you may trigger this undesired behaviour.
As described in the same part of the manual, you can try using
<logout invalidate-session="true"
logout-success-url="/logoutSuccess.jsp"
logout-url="/logout" delete-cookies="JSESSIONID" />
to remove the cookie when logging out.
You must take care, sometimes using invalidate-session='true' and delete-cookies=JSESSIONID together along with limited number of sessions that a user can have, might get you "Maximum sessions of 1 for this principal exceeded" error when you try to log in even after you log out.
It is advisable to use only Delete-cookies to remove necessary session information when u are using Spring Security 3.1 and above.
Configure the logout as below to delete cookies in the security configure WebSecurityConfigurerAdapter class.
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
//set access to all pages including session time out page where session time out is set in the application.properties page
httpSecurity
.authorizeRequests().antMatchers("/","/products","/product/show/*","/session","/console/*","/h2-console/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().permitAll();
//delete cookies so it won't get forwarded to session out page
httpSecurity.logout().deleteCookies("auth_code", "JSESSIONID").invalidateHttpSession(true);
httpSecurity.csrf().disable();
httpSecurity.headers().frameOptions().disable();
httpSecurity.sessionManagement().invalidSessionUrl("/session");
}
And finally in the session expiration forward page delete the cookies manually
#RequestMapping("/session")
String session(HttpServletRequest request,HttpServletResponse response){
SecurityContextHolder.clearContext();
HttpSession session= request.getSession(false);
Cookie[] cookies = request.getCookies();
// Delete all the cookies
if (cookies != null) {
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
cookies[i].setValue(null);
cookies[i].setMaxAge(0);
response.addCookie(cookie);
}
}
SecurityContextHolder.clearContext();
if(session != null) {
session.invalidate();
}
return "session";
}
The below code creates a Spring Authentication object that has the role_user associated as when I looked at the SecurityContext context = SecurityContextHolder.getContext(); at the very end it does have the ROLE_USER and a principal of UserDetails so somehow its not getting associated to my HttpSession. Any ideas? My exception is below as well
public String login(){
if(signUpDetailBean.getEmail() != null){
sers currentUser = userManager.getUser(signUpDetailBean.getEmail());
authenticateUserAndSetSession(currentUser, (HttpServletRequest) FacesUtils.getExternalContext().getRequest());
clearForm();
return "/registered/home.html";
}else{
clearForm();
return "/auth/login.html";
}
}
private void authenticateUserAndSetSession(Users user, HttpServletRequest request)
{
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
user.getUsername(), user.getPassword());
// generate session if one doesn't exist
request.getSession();
token.setDetails(new WebAuthenticationDetails(request));
Authentication authenticatedUser = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authenticatedUser);
SecurityContext context = SecurityContextHolder.getContext();
}
19:11:07,599 DEBUG AntPathRequestMatcher:72 - Checking match of request : '/registered/home.html'; against '/javax.faces.resource/**'
19:11:07,600 DEBUG AntPathRequestMatcher:72 - Checking match of request : '/registered/home.html'; against '/services/rest-api/1.0/**'
19:11:07,600 DEBUG AntPathRequestMatcher:72 - Checking match of request : '/registered/home.html'; against '/preregistered/*'
19:11:07,600 DEBUG FilterChainProxy:263 - /registered/home.html at position 1 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.context.SecurityContextPersistenceFilter#3486a602'
19:11:07,600 DEBUG HttpSessionSecurityContextRepository:138 - HttpSession returned null object for SPRING_SECURITY_CONTEXT
19:11:07,600 DEBUG HttpSessionSecurityContextRepository:84 - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade#1985b723. A new one will be created.
19:11:07,601 DEBUG FilterChainProxy:263 - /registered/home.html at position 2 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.authentication.logout.LogoutFilter#5b4c1313'
19:11:07,601 DEBUG FilterChainProxy:263 - /registered/home.html at position 3 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#5f787338'
19:11:07,601 DEBUG FilterChainProxy:263 - /registered/home.html at position 4 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.savedrequest.RequestCacheAwareFilter#5cd4927f'
19:11:07,601 DEBUG DefaultSavedRequest:316 - pathInfo: both null (property equals)
19:11:07,602 DEBUG DefaultSavedRequest:316 - queryString: both null (property equals)
19:11:07,602 DEBUG DefaultSavedRequest:338 - requestURI: arg1=/dreamcatcher/registered/modify.html; arg2=/dreamcatcher/registered/home.html (property not equals)
19:11:07,602 DEBUG HttpSessionRequestCache:75 - saved request doesn't match
19:11:07,603 DEBUG FilterChainProxy:263 - /registered/home.html at position 5 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#7ddff76'
19:11:07,603 DEBUG FilterChainProxy:263 - /registered/home.html at position 6 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter#8afbefd'
19:11:07,603 DEBUG FilterChainProxy:263 - /registered/home.html at position 7 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.authentication.AnonymousAuthenticationFilter#775a9fdf'
19:11:07,604 DEBUG AnonymousAuthenticationFilter:68 - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken#d45457b8: Principal: guest; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#1de60: RemoteIpAddress: 0:0:0:0:0:0:0:1%0; SessionId: 2A7602A6013D6200B7A663CEED58C478; Granted Authorities: ROLE_ANONYMOUS'
19:11:07,604 DEBUG FilterChainProxy:263 - /registered/home.html at position 8 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.session.SessionManagementFilter#51d394ab'
19:11:07,605 DEBUG FilterChainProxy:263 - /registered/home.html at position 9 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.access.ExceptionTranslationFilter#19c59085'
19:11:07,605 DEBUG FilterChainProxy:263 - /registered/home.html at position 10 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.access.intercept.FilterSecurityInterceptor#3c92218c'
19:11:07,605 DEBUG AntPathRequestMatcher:72 - Checking match of request : '/registered/home.html'; against '/**/*.xhtml'
19:11:07,606 DEBUG AntPathRequestMatcher:72 - Checking match of request : '/registered/home.html'; against '/auth/**'
19:11:07,606 DEBUG AntPathRequestMatcher:72 - Checking match of request : '/registered/home.html'; against '/auth/*'
19:11:07,607 DEBUG AntPathRequestMatcher:72 - Checking match of request : '/registered/home.html'; against '/registered/*'
19:11:07,607 DEBUG FilterSecurityInterceptor:191 - Secure object: FilterInvocation: URL: /registered/home.html; Attributes: [ROLE_USER]
19:11:07,608 DEBUG FilterSecurityInterceptor:291 - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken#d45457b8: Principal: guest; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#1de60: RemoteIpAddress: 0:0:0:0:0:0:0:1%0; SessionId: 2A7602A6013D6200B7A663CEED58C478; Granted Authorities: ROLE_ANONYMOUS
19:11:07,608 DEBUG AffirmativeBased:53 - Voter: org.springframework.security.access.vote.RoleVoter#44548719, returned: -1
19:11:07,616 DEBUG AffirmativeBased:53 - Voter: org.springframework.security.access.vote.AuthenticatedVoter#554ff490, returned: 0
19:11:07,636 DEBUG ExceptionTranslationFilter:151 - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:71)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:203)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:114)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:268)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:95)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:268)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:100)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:268)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:79)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:268)
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:112)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:268)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:268)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:35)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:268)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:187)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:268)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:268)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:268)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:121)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:244)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:550)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:380)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:243)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:288)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:680)
19:11:07,637 DEBUG HttpSessionRequestCache:41 - DefaultSavedRequest added to Session: DefaultSavedRequest[http://localhost:8080/dreamcatcher/registered/home.html]
19:11:07,638 DEBUG ExceptionTranslationFilter:175 - Calling Authentication entry point.
19:11:07,638 DEBUG DefaultRedirectStrategy:36 - Redirecting to 'http://localhost:8080/dreamcatcher/auth/login.html'
19:11:07,639 DEBUG SecurityContextPersistenceFilter:90 - SecurityContextHolder now cleared, as request processing completed
19:11:07,651 DEBUG AntPathRequestMatcher:72 - Checking match of request : '/auth/login.html'; against '/javax.faces.resource/**'
19:11:07,652 DEBUG AntPathRequestMatcher:72 - Checking match of request : '/auth/login.html'; against '/services/rest-api/1.0/**'
19:11:07,652 DEBUG AntPathRequestMatcher:72 - Checking match of request : '/auth/login.html'; against '/preregistered/*'
19:11:07,652 DEBUG FilterChainProxy:263 - /auth/login.html at position 1 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.context.SecurityContextPersistenceFilter#3486a602'
19:11:07,653 DEBUG HttpSessionSecurityContextRepository:138 - HttpSession returned null object for SPRING_SECURITY_CONTEXT
19:11:07,653 DEBUG HttpSessionSecurityContextRepository:84 - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade#1985b723. A new one will be created.
19:11:07,653 DEBUG FilterChainProxy:263 - /auth/login.html at position 2 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.authentication.logout.LogoutFilter#5b4c1313'
19:11:07,653 DEBUG FilterChainProxy:263 - /auth/login.html at position 3 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#5f787338'
19:11:07,654 DEBUG FilterChainProxy:263 - /auth/login.html at position 4 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.savedrequest.RequestCacheAwareFilter#5cd4927f'
19:11:07,654 DEBUG DefaultSavedRequest:316 - pathInfo: both null (property equals)
19:11:07,654 DEBUG DefaultSavedRequest:316 - queryString: both null (property equals)
19:11:07,655 DEBUG DefaultSavedRequest:338 - requestURI: arg1=/dreamcatcher/registered/home.html; arg2=/dreamcatcher/auth/login.html (property not equals)
19:11:07,655 DEBUG HttpSessionRequestCache:75 - saved request doesn't match
19:11:07,655 DEBUG FilterChainProxy:263 - /auth/login.html at position 5 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#7ddff76'
19:11:07,655 DEBUG FilterChainProxy:263 - /auth/login.html at position 6 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter#8afbefd'
19:11:07,656 DEBUG FilterChainProxy:263 - /auth/login.html at position 7 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.authentication.AnonymousAuthenticationFilter#775a9fdf'
19:11:07,656 DEBUG AnonymousAuthenticationFilter:68 - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken#d45457b8: Principal: guest; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#1de60: RemoteIpAddress: 0:0:0:0:0:0:0:1%0; SessionId: 2A7602A6013D6200B7A663CEED58C478; Granted Authorities: ROLE_ANONYMOUS'
19:11:07,656 DEBUG FilterChainProxy:263 - /auth/login.html at position 8 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.session.SessionManagementFilter#51d394ab'
19:11:07,657 DEBUG FilterChainProxy:263 - /auth/login.html at position 9 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.access.ExceptionTranslationFilter#19c59085'
19:11:07,657 DEBUG FilterChainProxy:263 - /auth/login.html at position 10 of 10 in additional filter chain; firing Filter: 'org.springframework.security.web.access.intercept.FilterSecurityInterceptor#3c92218c'
19:11:07,658 DEBUG AntPathRequestMatcher:72 - Checking match of request : '/auth/login.html'; against '/**/*.xhtml'
19:11:07,658 DEBUG AntPathRequestMatcher:72 - Checking match of request : '/auth/login.html'; against '/auth/**'
19:11:07,658 DEBUG FilterSecurityInterceptor:191 - Secure object: FilterInvocation: URL: /auth/login.html; Attributes: [ROLE_ANONYMOUS, ROLE_USER]
19:11:07,659 DEBUG FilterSecurityInterceptor:291 - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken#d45457b8: Principal: guest; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#1de60: RemoteIpAddress: 0:0:0:0:0:0:0:1%0; SessionId: 2A7602A6013D6200B7A663CEED58C478; Granted Authorities: ROLE_ANONYMOUS
19:11:07,659 DEBUG AffirmativeBased:53 - Voter: org.springframework.security.access.vote.RoleVoter#44548719, returned: 1
19:11:07,659 DEBUG FilterSecurityInterceptor:212 - Authorization successful
19:11:07,660 DEBUG FilterSecurityInterceptor:222 - RunAsManager did not change Authentication object
19:11:07,660 DEBUG FilterChainProxy:252 - /auth/login.html reached end of additional filter chain; proceeding with original chain
19:11:07,672 DEBUG DefaultListableBeanFactory:430 - Creating instance of bean 'authentication'
19:11:07,677 DEBUG InjectionMetadata:82 - Processing injected method of bean 'authentication': AutowiredFieldElement for com.dc.web.beans.LayoutBean com.dc.web.actions.BaseAction.layoutBean
19:11:07,678 DEBUG InjectionMetadata:82 - Processing injected method of bean 'authentication': AutowiredFieldElement for com.dc.web.beans.AuthenticationBean com.dc.web.actions.Authentication.authenticationBean
19:11:07,679 DEBUG InjectionMetadata:82 - Processing injected method of bean 'authentication': AutowiredFieldElement for com.dc.api.service.UserManager com.dc.web.actions.Authentication.userManager
19:11:07,679 DEBUG DefaultListableBeanFactory:242 - Returning cached instance of singleton bean 'userManager'
19:11:07,680 DEBUG InjectionMetadata:82 - Processing injected method of bean 'authentication': AutowiredFieldElement for com.dc.api.service.Utilities com.dc.web.actions.Authentication.utilities
19:11:07,681 DEBUG DefaultListableBeanFactory:242 - Returning cached instance of singleton bean 'utilities'
19:11:07,681 DEBUG InjectionMetadata:82 - Processing injected method of bean 'authentication': AutowiredFieldElement for com.dc.web.util.PasswordMailContentHelper com.dc.web.actions.Authentication.passwordMailContentHelper
19:11:07,682 DEBUG DefaultListableBeanFactory:242 - Returning cached instance of singleton bean 'passwordMailContentHelper'
19:11:07,683 DEBUG InjectionMetadata:82 - Processing injected method of bean 'authentication': AutowiredFieldElement for com.dc.web.util.UsernameMailContentHelper com.dc.web.actions.Authentication.usernameMailContentHelper
19:11:07,683 DEBUG DefaultListableBeanFactory:242 - Returning cached instance of singleton bean 'usernameMailContentHelper'
19:11:07,684 DEBUG InjectionMetadata:82 - Processing injected method of bean 'authentication': AutowiredFieldElement for org.springframework.security.authentication.encoding.PasswordEncoder com.dc.web.actions.Authentication.passwordEncoder
19:11:07,684 DEBUG DefaultListableBeanFactory:242 - Returning cached instance of singleton bean 'passwordEncoder'
19:11:07,685 DEBUG DefaultListableBeanFactory:458 - Finished creating instance of bean 'authentication'
19:11:07,690 DEBUG DefaultListableBeanFactory:430 - Creating instance of bean 'signUpDetail'
19:11:07,692 DEBUG InjectionMetadata:82 - Processing injected method of bean 'signUpDetail': AutowiredFieldElement for com.dc.web.beans.LayoutBean com.dc.web.actions.BaseAction.layoutBean
19:11:07,692 DEBUG InjectionMetadata:82 - Processing injected method of bean 'signUpDetail': AutowiredFieldElement for private com.dc.web.beans.SignUpDetailBean com.dc.web.actions.SignUpDetail.signUpDetailBean
19:11:07,693 DEBUG InjectionMetadata:82 - Processing injected method of bean 'signUpDetail': AutowiredFieldElement for private com.dc.api.service.UserManager com.dc.web.actions.SignUpDetail.userManager
19:11:07,694 DEBUG DefaultListableBeanFactory:242 - Returning cached instance of singleton bean 'userManager'
19:11:07,695 DEBUG InjectionMetadata:82 - Processing injected method of bean 'signUpDetail': AutowiredFieldElement for protected org.springframework.security.authentication.AuthenticationManager com.dc.web.actions.SignUpDetail.authenticationManager
19:11:07,695 DEBUG DefaultListableBeanFactory:242 - Returning cached instance of singleton bean 'org.springframework.security.authenticationManager'
19:11:07,696 DEBUG InjectionMetadata:82 - Processing injected method of bean 'signUpDetail': AutowiredFieldElement for com.dc.api.service.Utilities com.dc.web.actions.SignUpDetail.utilities
19:11:07,697 DEBUG DefaultListableBeanFactory:242 - Returning cached instance of singleton bean 'utilities'
19:11:07,697 DEBUG DefaultListableBeanFactory:458 - Finished creating instance of bean 'signUpDetail'
19:11:07,716 DEBUG DefaultListableBeanFactory:430 - Creating instance of bean 'layout'
19:11:07,717 DEBUG InjectionMetadata:82 - Processing injected method of bean 'layout': AutowiredFieldElement for com.dc.web.beans.LayoutBean com.dc.web.actions.BaseAction.layoutBean
19:11:07,718 DEBUG InjectionMetadata:82 - Processing injected method of bean 'layout': AutowiredFieldElement for private com.dc.web.beans.LayoutBean com.dc.web.actions.Layout.layoutBean
19:11:07,719 DEBUG DefaultListableBeanFactory:458 - Finished creating instance of bean 'layout'
19:11:07,738 DEBUG ExceptionTranslationFilter:98 - Chain processed normally
19:11:07,738 DEBUG HttpSessionSecurityContextRepository:271 - SecurityContext contents are anonymous - context will not be stored in HttpSession.
19:11:07,739 DEBUG SecurityContextPersistenceFilter:90 - SecurityContextHolder now cleared, as request processing completed
We need to put the security context in session. Otherwise it won't work. You can use this
SecurityContextHolder.getContext().setAuthentication(authentication);
request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
I'm losing my login credentials between a successful login and the redirect from my AuthenticationSuccessHandler in one app, but not in another that's essentially doing the same things.
To build onto manishpal's answer, I'll give some context on where to put it. (I am using Kotlin, sorry for the different syntax)
Within your application, you will probably have some kind of function that handles authentication of a user. Within my application, it is a POST endpoint for login.
#PostMapping("/login")
fun handleLogin(#RequestParam username:String?, #RequestParam password:String?) {
authenticate(username, password)
return "redirect:/"
}
fun authenticate(username:String?, password:String?) {
val user = database.findByUserName(username)
if(user.password != password) throw IllegalArgumentException()
}
Now, this is where I would add the first line of pal's answer. Spring applications have a static object called the SecurityContextHolder which you can use to access the details of the currently logged in user. In this case, we are going to set the authentication of this context ourselves.
fun authenticate(username:String?, password:String?) {
val user = database.findByUserName(username)
if (user.password != password) throw IllegalArgumentException()
val token = UsernamePasswordAuthenticationToken(user.username, user.password)
SecurityContextHolder.getContext().authentication = token
}
Now, we have set the authentication of the user in the context of this request, but it will go away after this endpoint finishes executing. We now want to set the authentication for the user across the entire session that the user is active. For this, we will have to add another parameter to our login endpoint:
#PostMapping("/login")
fun handleLogin(#RequestParam username:String?, #RequestParam password:String?, request: HttpServletRequest) {
authenticate(username, password)
request.session.setAttribute(
HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,
SecurityContextHolder.getContext()
)
return "redirect:/"
}
This `request` parameter is automatically wired into the function call by spring, so no action is needed to include it in your HTTP request to your application.