1

I came across this project in order to fix a issue which the server is responding with 401 unautorized to a OPTIONS request.

I looked in the project and ( It is a Spring 5 project bundled as a ear not a boot ) found that there is a CORS filter. Then I looked into security configs and found that there is two.

//@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomUserDetailsService customUserDetailsService;

    @Bean
    public CustomDaoAuthenticationProvider authenticationProvier() {
        CustomDaoAuthenticationProvider customProvider = new CustomDaoAuthenticationProvider();
        customProvider.setUserDetailsService(customUserDetailsService);
        customProvider.setPasswordEncoder(passwordEncoder());
        return customProvider;
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvier());

    }

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

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http
                .cors()
                .and()
                .csrf().disable()
                .anonymous().disable()
                .authorizeRequests()
                .antMatchers("/**").permitAll();
    }

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

}

The second one is

@Configuration
@EnableResourceServer
@EnableWebSecurity
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {

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

        http.anonymous().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .csrf().disable().authorizeRequests()

                .antMatchers(HttpMethod.GET, "/somepath/**").access("#oauth2.hasScope('some_scope') "
                + "and hasAnyRole('role_1','r')")
                ....
                .anyRequest().authenticated();
    }

    @Override
    public void configure(final ResourceServerSecurityConfigurer config) {
        config.tokenServices(tokenServices());
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        final JwtAccessTokenConverter converter = new JwtAccessTokenConverter();

        ClassPathResource resource = new ClassPathResource("id_rsa.pub");
        String publicKey = null;
        try {
            publicKey = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        converter.setVerifierKey(publicKey);
        return converter;
    }

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        return defaultTokenServices;
    }

}

After reading questions related to this what I figured it that OAuth2ResourceServerConfig gets precedence over WebSecurityConfig ( question here ).

So in the current set is it checking for both token and the password? If I increase the precedence of WebSecurityConfig will it solve the issue. If I have misunderstood anything here please fix it for me.

Susitha Ravinda Senarath
  • 1,648
  • 2
  • 27
  • 49

1 Answers1

0

I was facing the same issue too!

So what I did, I just exchange the OPTIONS request implicitly. Because Optional Request is just from browser to server to check whether Service is working or not.

If you notice, when we test endpoint from POSTMAN then this issue not apears.

So what I did

@Component
public class SecretKeyFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        HttpHeaders headers = request.getHeaders();

        if(!request.getMethod().name().equals("OPTIONS"))
        {
            
          /**
           * Do the authentication and valication of your request here.
           *
          **/
        }

        return chain.filter(exchange);
    }
}
Dharman
  • 30,962
  • 25
  • 85
  • 135
Dupinder Singh
  • 7,175
  • 6
  • 37
  • 61
  • Does it work like this? Because other than skipping the security check server need to set certain response headers like allowed origins etc – Susitha Ravinda Senarath Nov 13 '20 at 04:43
  • I am saying that! Just skip the `OPTIONS` request, because `OPTIONS` request will not take your Auth params with it, like some `headers` which contains `Auth token` or any other param. So just Skip the `OPTIONS` request and then Capture the other one and then apply the Security Aspects – Dupinder Singh Nov 13 '20 at 05:40