Andrew Rutter
Andrew Rutter

Reputation: 1297

Unable to have a secure and non secure endpoint in a single Oauth secured Spring controller

I am putting together a REST api using Spring Boot which will be secured via OAuth2. I have a security application built which is working fine managing jwt tokens.

I am putting together a separate application that will handle some general user profile resource requests such as forgot password, registration and profile get operations. This is annotated with EnableOAuth2Resource which is correctly adding OAuth2AuthenticationProcessingFilter to the filter chain.

@SpringBootApplication
@EnableOAuth2Resource
public class ProfileApplication extends SpringBootServletInitializer {

    public static void main(String[] args) throws IOException {
        SpringApplication.run(ProfileApplication.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(ProfileApplication.class);
    }
}

The challenge I am facing is that I cannot find a way to configure security so that POST requests to a /profiles endpoint are unsecured while requests to GET or PUT pass in the derived @AuthenticationPrincipal from a provided bearer token.

I want to have the following in place within the API POST /profile create a new user - no security GET /profile/{id} get a user by id - requires admin permission or user is authd POST /password/reset - starts a password reset - no security

I have the following bean to configure security

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(-10) //SecurityProperties.ACCESS_OVERRIDE_ORDER)
class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override

    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/", "/public/**").permitAll()                
                .antMatchers(HttpMethod.POST, "/profiles/**").permitAll()
                .antMatchers(HttpMethod.GET, "/profiles/**").fullyAuthenticated()
                .antMatchers("/password/**").permitAll()
                .anyRequest().fullyAuthenticated()
                .and()
                .csrf().disable();
    }
}

With the above the GET endpoint invocation fails with a 403 error without any attempt to lookup the current user from the token BUT a post will go through. Looking in the logs I no longer see the OAuth2AuthenticationProcessingFilter in the filter chain. My attempt to addd some additional filters appears to cause it to no longer be registered.

This controller method looks like:

@RequestMapping(method = {RequestMethod.GET}, value="/profiles/{login:.+}")
@ResponseBody
public ResponseEntity<Profile> get(@AuthenticationPrincipal Principal currentUser, @PathVariable String login) {

If I set the order to SecurityProperties.ACCESS_OVERRIDE_ORDER then the GET request works and I see a lookup against my oauth service based on the profile in the jwt bearer token but the POST requests to either the profile or password controller fails with a 401. So it seems that the code never reaches this filter and is instead being intercepted by the OAuth2AuthenticationProcessingFilter and the request failing auth off the bat.

Is there a way to partially secure a Spring Boot application when using @EnableOAuth2Resource? Do I have to setup a different configuration bean to provide the necessary overrides and if so, based on what interface?

Upvotes: 2

Views: 3266

Answers (2)

Andrew Rutter
Andrew Rutter

Reputation: 1297

@maleenc's suggestion above was correct. I was missing the following ResourceServerConfigurerAdapter. Adding my OAuth2ServerConfiguration class and removing the other security filters resolved my issue

@Configuration
public class OAuth2ServerConfiguration {
    @Configuration
    @EnableResourceServer
    protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers("/", "/public/**").permitAll()                
                    .antMatchers("/password/**").permitAll()
                    .antMatchers(HttpMethod.POST, "/profiles").permitAll()
                    .and()
                    .csrf().disable();
        }
    }
}

Upvotes: 2

Maleen Abewardana
Maleen Abewardana

Reputation: 14572

I think you should move your oauth2 resources from the request matchers in your SecurityConfig and allow them to be handled by the resource server filter - the class which is extending ResourceServerConfigurerAdapter.

My answer is inspired by Dave Syer's answer which is given here. You can find a good security config here.

Or else try giving a higher order to the bean.

Upvotes: 3

Related Questions