MarioC
MarioC

Reputation: 3228

Spring oauth2 authorization code grant - Impossibile to reach /oauth/authorize

I'm trying to secure my rest api with authorization code flow, but i don't understand why i'm getting the message:

User must be authenticated with Spring Security before authorization can be completed.

I have a web part of the application with User and Admin access, and a REST api part with 2 different grants, on /api/** authorization code and on /oauth2/** with client_credentials.

The client_credential flow work, but the authorization code nope...

So, this is my Authorization Server configuration

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    DataSource dataSource;

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

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

        endpoints.tokenStore(tokenStore()).authenticationManager(authManager);

    }

    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

}

This is my resource server configuration

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter{

    @Autowired
    DataSource dataSource;

     @Override
        public void configure(HttpSecurity http) throws Exception {

           http
    .requestMatchers()
    .antMatchers("/api/**")
    .antMatchers("/oauth2/**")
    .and().authorizeRequests()
    .antMatchers("/api/**").access("hasRole('USER')")
    .antMatchers("/oauth2/**").authenticated()
    .and().httpBasic();
        }

     @Bean
        public TokenStore tokenStore() {
            return new JdbcTokenStore(dataSource);
        }

     @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {

            resources.tokenStore(tokenStore());
        }
}

And finally, this is the general Security

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier("customUserDetailsService")
    UserDetailsService userDetailsService;

    @Autowired
    CustomSuccessHandler customSuccessHandler;

    @Autowired
    CustomAuthenticationFailureHandler customAuthenticationFailureHandler;

    @Autowired
    DataSource dataSource;

    @Autowired
    public void configureGlobalService(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());

    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()

                .antMatchers("/", "/registration", "/registrationConfirm", "/resendRegistrationToken")
                .permitAll()

                .antMatchers("/edit/**", "/payment/**", "/plate/**", "/book/**", "/home", "/stop/**",
                        "/notification/**", "/include/**")
                .access("hasRole('USER') or hasRole('ADMIN') or hasRole('PARK')").antMatchers("/admin/**")
                .access("hasRole('ADMIN') or hasRole('PARK')").antMatchers("/updatePassword")
                .hasAuthority("CHANGE_PASSWORD_PRIVILEGE")

                .and().formLogin().loginPage("/")
                .successHandler(customSuccessHandler).failureHandler(customAuthenticationFailureHandler)
                .usernameParameter("email").passwordParameter("password").and().rememberMe()
                .rememberMeParameter("remember-me").tokenRepository(persistentTokenRepository())
                .tokenValiditySeconds(86400).and().exceptionHandling().accessDeniedPage("/Access_Denied").and()
                .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .logoutSuccessUrl("/?logout=true").invalidateHttpSession(false).deleteCookies("JSESSIONID");

        http.csrf().disable();

    }

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

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
        db.setDataSource(dataSource);
        return db;
    }

}

The user in the oauth_client_details table has ROLE_USER as authorities, client_id and client_secret are test/test

This is how I'm searching to get the Token with POSTMAN

POSTMAN OAUTH2 Token request

but i'm getting the exception

ERROR i.b.e.e.RestResponseEntityExceptionHandler[66] - 500 Status Code org.springframework.security.authentication.InsufficientAuthenticationException: User must be authenticated with Spring Security before authorization can be completed.

EDIT this is what i see when i push the Request Token button

Response

EDIT Inspecting the logs i also found that in my Security Filter chain there is no sign of any filter of Oauth2... When making the request to get the Authorization token i see:

2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 4 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 5 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 6 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 7 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 8 of 12 in additional filter chain; firing Filter: 'RememberMeAuthenticationFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[310] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman

Upvotes: 0

Views: 4566

Answers (1)

Luke Bajada
Luke Bajada

Reputation: 1852

The problem with your code is this part inside SecurityConfiguration:

.and().formLogin().loginPage("/")

Spring is not detecting your login page and thus you cannot be redirected to authenticate to it as a user.

The solution would be to change it to:

.and().formLogin()

You will then use Spring's default login page and the Authorization Code flow should work. After that works, you would need to debug as to why your login page at '/' is not being detected.

EDIT:

The real problem was that RestResponseEntityExceptionHandler.class is a @ControllerAdvice annotated class which was messing with the redirection issued in the ExceptionTranslationFilter. This was because it was catching the exception and throwing it to the front-end without allowing the ExceptionTranslationFilter to issue the redirection to the login page. Removing the use of RestResponseEntityExceptionHandler.class solves the issue and the Auth code flow works correctly.

Upvotes: 5

Related Questions