6

I want to use OAuth2 for my REST spring boot project. Using some examples I have created configuration for OAuth2:

@Configuration
public class OAuth2Configuration {

    private static final String RESOURCE_ID = "restservice";

    @Configuration
    @EnableResourceServer
    protected static class ResourceServerConfiguration extends
          ResourceServerConfigurerAdapter {

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) {
            // @formatter:off
            resources
                    .resourceId(RESOURCE_ID);
            // @formatter:on
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            // @formatter:off
            http
                    .anonymous().disable()
                    .authorizeRequests().anyRequest().authenticated();
            // @formatter:on
        }

    }

    @Configuration
    @EnableAuthorizationServer
    protected static class AuthorizationServerConfiguration extends
             AuthorizationServerConfigurerAdapter {

        private TokenStore tokenStore = new InMemoryTokenStore();

        @Autowired
        @Qualifier("authenticationManagerBean")
        private AuthenticationManager authenticationManager;

        @Autowired
        private UserDetailsServiceImpl userDetailsService;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints)
            throws Exception {
          // @formatter:off
          endpoints
                  .tokenStore(this.tokenStore)
                  .authenticationManager(this.authenticationManager)
                  .userDetailsService(userDetailsService);
          // @formatter:on
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            // @formatter:off
            clients
                  .inMemory()
                  .withClient("clientapp")
                  .authorizedGrantTypes("password", "refresh_token", "trust")
                  .authorities("USER")
                  .scopes("read", "write")
                  .resourceIds(RESOURCE_ID)
                  .secret("clientsecret")
                  .accessTokenValiditySeconds(1200)
                  .refreshTokenValiditySeconds(3600);
            // @formatter:on
        }

        @Bean
        @Primary
        public DefaultTokenServices tokenServices() {
            DefaultTokenServices tokenServices = new DefaultTokenServices();
            tokenServices.setSupportRefreshToken(true);
            tokenServices.setTokenStore(this.tokenStore);
            return tokenServices;
        }
    }
}

This is my SecurityConfiguration class:

@Configuration
@EnableWebSecurity
@Order(1)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http
                .authorizeRequests().antMatchers("/api/register").permitAll()
                .and()
                .authorizeRequests().antMatchers("/api/free").permitAll()
                .and()
                .authorizeRequests().antMatchers("/oauth/token").permitAll()
                .and()
                .authorizeRequests().antMatchers("/api/secured").hasRole("USER")
                .and()
                .authorizeRequests().anyRequest().authenticated();
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

I tried to check my application with 2 simple requests:

@RequestMapping(value = "/api/secured", method = RequestMethod.GET)
public String checkSecured(){
    return "Authorization is ok";
}

@RequestMapping(value = "/api/free", method = RequestMethod.GET)
public String checkFree(){
    return "Free from authorization";
}

Firstly I checked two requests:

/api/free returned code 200 and the string "Free from authorization"

/api/secured returned {"timestamp":1487451065106,"status":403,"error":"Forbidden","message":"Access Denied","path":"/api/secured"}

And it seems that they work fine.

Then I got access_token (using credentials from my users database)

/oauth/token?grant_type=password&username=emaila&password=emailo

Response:

{"access_token":"3344669f-c66c-4161-9516-d7e2f31a32e8","token_type":"bearer","refresh_token":"c71c17e4-45ba-458c-9d98-574de33d1859","expires_in":1199,"scope":"read write"}

Then I tried to send a request (with the token I got) for resource which requires authentication:

/api/secured?access_token=3344669f-c66c-4161-9516-d7e2f31a32e8

Here is response:

{"timestamp":1487451630224,"status":403,"error":"Forbidden","message":"Access Denied","path":"/api/secured"}

I cannot understand why access is denied. I am not sure in configurations and it seems that they are incorrect. Also I still do not clearly understand relationships of methods configure(HttpSecurity http) in class which extends WebSecurityConfigurerAdapter and in another which extends ResourceServerConfigurerAdapter. Thank you for any help!

4
  • What happens when you send the Token as Header Authorization: Bearer [TOKEN]? Commented Feb 19, 2017 at 11:06
  • @dav1d I tried but access is still denied Commented Feb 19, 2017 at 13:41
  • Your question was helpful, however I got it to work only after removing the "@Order(1)" from your security class. It would have been very beneficial if you provided the full code or a Github link. Commented Apr 4, 2018 at 15:01
  • 1
    @SamwellTarly Sorry for late reply, here is the link: github.com/ahea/SocNetworkSpringApp Commented Apr 23, 2018 at 9:55

1 Answer 1

24

If you are using spring boot 1.5.1 or recently updated to it, note that they changed the filter order for spring security oauth2 (Spring Boot 1.5 Release Notes).

According to the release notes, try to add the following property to application.properties/yml, after doing that the resource server filters will be used after your other filters as a fallback - this should cause the authorization to be accepted before falling to the resource server:

security.oauth2.resource.filter-order = 3

You can find a good answer for your other questions here: https://stackoverflow.com/questions/28537181

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you very much for your answer. I added this property and removed @Order annotation. Now I can get access token and then, using it, finally get /api/secured resource. But I cannot get /api/free without token now. I think it can be fixed by changing configure methods.
I'm having a similar problem, while I'm requesting a secured resource with the access_token, it seems like this totally ignored and I'm redirected to make login... Do you know how can I debug it?
You might be trying to do an authorization_code flow instead of client_credentials / password flows, in auth code flow you should be redirected to a login page so it makes sense (oauth.net/2/grant-types/authorization-code)
@Tom can you pls look into this issue stackoverflow.com/questions/53537133/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.