I am having a hard time getting Spring Security OAuth2 to work. I am able to get a access_token from /oauth/token endpoint but accessing a protected resource with that token in header "Authorization: Bearer $TOKEN" always redirects me to /login. This is a complete REST API.
OAuth2Config
@Configuration
public class OAuth2Configuration {
private static final String SERVER_RESOURCE_ID = "oauth2-server";
private static InMemoryTokenStore tokenStore = new InMemoryTokenStore();
@Configuration
@EnableResourceServer
protected static class ResourceServer extends ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore).resourceId(SERVER_RESOURCE_ID);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatchers().antMatchers("/admin**").and().authorizeRequests().antMatchers("/admin**").access("#oauth2.hasScope('read')");
}
}
@Configuration
@EnableAuthorizationServer
protected static class AuthConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore).approvalStoreDisabled();
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("my-client")
.authorizedGrantTypes("authorization_code","refresh_token", "password")
.authorities("ROLE_CLIENT")
.scopes("read")
.resourceIds(SERVER_RESOURCE_ID)
.secret("secret")
;
}
}
}
SecurityConfig class
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(bCryptPasswordEncoder());
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
Following are the debug logs
2017-04-10 10:58:31.634[0;39m [32mDEBUG[0;39m [35m6456[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.s.web.servlet.DispatcherServlet [0;39m [2m:[0;39m Initializing servlet 'dispatcherServlet'
[2m2017-04-10 10:58:31.635[0;39m [32m INFO[0;39m [35m6456[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.a.c.c.C.[Tomcat].[localhost].[/] [0;39m [2m:[0;39m Initializing Spring FrameworkServlet 'dispatcherServlet'
[2m2017-04-10 10:58:31.635[0;39m [32m INFO[0;39m [35m6456[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.s.web.servlet.DispatcherServlet [0;39m [2m:[0;39m FrameworkServlet 'dispatcherServlet': initialization started
[2m2017-04-10 10:58:31.635[0;39m [32mDEBUG[0;39m [35m6456[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.s.web.servlet.DispatcherServlet [0;39m [2m:[0;39m Using MultipartResolver [org.springframework.web.multipart.support.StandardServletMultipartResolver@40aad17d]
[2m2017-04-10 10:58:31.639[0;39m [32mDEBUG[0;39m [35m6456[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.s.web.servlet.DispatcherServlet [0;39m [2m:[0;39m Unable to locate LocaleResolver with name 'localeResolver': using default [org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver@70f4e8c6]
[2m2017-04-10 10:58:31.643[0;39m [32mDEBUG[0;39m [35m6456[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.s.web.servlet.DispatcherServlet [0;39m [2m:[0;39m Unable to locate ThemeResolver with name 'themeResolver': using default [org.springframework.web.servlet.theme.FixedThemeResolver@201a4016]
[2m2017-04-10 10:58:31.649[0;39m [32mDEBUG[0;39m [35m6456[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.s.web.servlet.DispatcherServlet [0;39m [2m:[0;39m Unable to locate RequestToViewNameTranslator with name 'viewNameTranslator': using default [org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator@5f14eeee]
[2m2017-04-10 10:58:31.656[0;39m [32mDEBUG[0;39m [35m6456[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.s.web.servlet.DispatcherServlet [0;39m [2m:[0;39m Unable to locate FlashMapManager with name 'flashMapManager': using default [org.springframework.web.servlet.support.SessionFlashMapManager@1688575]
[2m2017-04-10 10:58:31.656[0;39m [32mDEBUG[0;39m [35m6456[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.s.web.servlet.DispatcherServlet [0;39m [2m:[0;39m Published WebApplicationContext of servlet 'dispatcherServlet' as ServletContext attribute with name [org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcherServlet]
[2m2017-04-10 10:58:31.656[0;39m [32m INFO[0;39m [35m6456[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.s.web.servlet.DispatcherServlet [0;39m [2m:[0;39m FrameworkServlet 'dispatcherServlet': initialization completed in 21 ms
[2m2017-04-10 10:58:31.656[0;39m [32mDEBUG[0;39m [35m6456[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.s.web.servlet.DispatcherServlet [0;39m [2m:[0;39m Servlet 'dispatcherServlet' configured successfully
[2m2017-04-10 10:58:31.692[0;39m [32mDEBUG[0;39m [35m6456[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.s.web.servlet.DispatcherServlet [0;39m [2m:[0;39m DispatcherServlet with name 'dispatcherServlet' processing POST request for [/oauth/token]
[2m2017-04-10 10:58:31.695[0;39m [32mDEBUG[0;39m [35m6456[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36ms.w.s.m.m.a.RequestMappingHandlerMapping[0;39m [2m:[0;39m Looking up handler method for path /oauth/token
[2m2017-04-10 10:58:31.699[0;39m [32mDEBUG[0;39m [35m6456[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36ms.w.s.m.m.a.RequestMappingHandlerMapping[0;39m [2m:[0;39m Did not find handler method for [/oauth/token]
[2m2017-04-10 10:58:32.012[0;39m [32m INFO[0;39m [35m6456[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.s.s.o.p.token.store.JdbcTokenStore [0;39m [2m:[0;39m Failed to find access token for token 7c74f287-e187-4228-b0c2-b79972f9b89b
[2m2017-04-10 10:58:32.226[0;39m [32mDEBUG[0;39m [35m6456[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.s.w.s.m.m.a.HttpEntityMethodProcessor [0;39m [2m:[0;39m Written [7c74f287-e187-4228-b0c2-b79972f9b89b] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@2fd4312a]
[2m2017-04-10 10:58:32.226[0;39m [32mDEBUG[0;39m [35m6456[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.s.web.servlet.DispatcherServlet [0;39m [2m:[0;39m Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
[2m2017-04-10 10:58:32.226[0;39m [32mDEBUG[0;39m [35m6456[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.s.web.servlet.DispatcherServlet [0;39m [2m:[0;39m Successfully completed request
What is it that I am missing? I have almost tried every example over the web into my existing project but I am always redirected to the /login endpoint when I try to request a protected resource with a valid token.
Thanks.
So it turned out that since I was upgrading from an earlier version of spring boot to 1.5.2, in the release notes it is said that the order of the resource filter has been changed. See here. Just place this magic property in application.properties file and it fixes everything.
security.oauth2.resource.filter-order = 3
he default order of the OAuth2 resource filter has changed from 3 to SecurityProperties.ACCESS_OVERRIDE_ORDER - 1. This places it after the actuator endpoints but before the basic authentication filter chain. The default can be restored by setting security.oauth2.resource.filter-order = 3.