Spring Security OAuth2: '#oauth2.xxx' expressions not evaluted with multiple RequestMatchers mapped to the same FilterChain

拥有回忆 提交于 2019-12-13 09:25:45

问题


In a multi modules app I've defined 5 RequestMatchers mapped to the same FilterChain, like below:

@Configuration
public class Module1SecurityFilterChain extends ResourceServerConfigurerAdapter {

   @Override
   public void configure( HttpSecurity http ) throws Exception {
      http.sessionManagement().sessionCreationPolicy( STATELESS );
      http.requestMatchers().antMatchers( "/module1/**")
            .and()
            .authorizeRequests()
            .antMatchers( "/module1/resource").authenticated()
            .antMatchers( "/module1/test" ).access( "#oauth2.isClient()")
            .anyRequest().access( "#oauth2.hasScope('webclient')" );
   }
}

And module2:

@Configuration
public class Module2SecurityFilterChain extends ResourceServerConfigurerAdapter {

   @Override
   public void configure( HttpSecurity http ) throws Exception {
      http.sessionManagement().sessionCreationPolicy( STATELESS );
      http.requestMatchers().antMatchers( "/module2/**")
            .and()
            .authorizeRequests()
            .antMatchers( "/module2/resource").authenticated()
            .antMatchers( "/module2/test" ).access( "#oauth2.isClient()")
            .anyRequest().access( "#oauth2.hasScope('webclient')" );
   }
}

And enabled method security:

@Configuration
@EnableGlobalMethodSecurity( prePostEnabled = true, securedEnabled = true )
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {

    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        return new OAuth2MethodSecurityExpressionHandler();
    }
}

The problem is that all #oauth2.xx expressions are evaluated only for the 1st module requestmatcher /module1/** and ignored in others. When I authenticate a user and try to access to /module1/test the access is denied as expected whereas when accessing to /module2/test access is granted (it should also be denied).

Could someone explains me why and how to solve this? I know Spring Security isn't easy at all... Thanks again.

EDIT @Darren Forsythe (thanks for your comment) The filter chains created are:

INFO | o.s.s.w.DefaultSecurityFilterChain | Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern='/oauth/token'], Ant [pattern='/oauth/token_key'], Ant [pattern='/oauth/check_token']]], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@f55a810b, org.springframework.security.web.context.SecurityContextPersistenceFilter@85021903, org.springframework.security.web.header.HeaderWriterFilter@1d0744d1, org.springframework.security.web.authentication.logout.LogoutFilter@2d15146a, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@c38f3266, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@8f9bf85, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@74a71be5, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@e4eb6cc, org.springframework.security.web.session.SessionManagementFilter@22f6b39a, org.springframework.security.web.access.ExceptionTranslationFilter@960c464f, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@f7a19dc5]
INFO | o.s.s.w.DefaultSecurityFilterChain | Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern='/module1/**'], Ant [pattern='/module2/**'], Ant [pattern='/module3/**'], Ant [pattern='/module4/**'], Ant [pattern='/module5/**'], Ant [pattern='/module6/**']]], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@38ef2427, org.springframework.security.web.context.SecurityContextPersistenceFilter@a26ff7af, org.springframework.security.web.header.HeaderWriterFilter@5344e710, org.springframework.security.web.authentication.logout.LogoutFilter@da0534c8, org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter@2956c7ab, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5682f610, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@f4cbf7a4, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@d1b1395a, org.springframework.security.web.session.SessionManagementFilter@d352f8ab, org.springframework.security.web.access.ExceptionTranslationFilter@9bb1d86, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@73c7a695]
INFO | o.s.s.w.DefaultSecurityFilterChain | Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@1cc2056f, org.springframework.security.web.context.SecurityContextPersistenceFilter@259d95db, org.springframework.security.web.header.HeaderWriterFilter@de089e0b, org.springframework.security.web.authentication.logout.LogoutFilter@8b86b4c, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@96304ca8, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@1d5b7e4b, org.springframework.security.web.session.SessionManagementFilter@bd586b4d, org.springframework.security.web.access.ExceptionTranslationFilter@7cff2571]

As you can see, all module's urls are mapped to the same filter chain with this list of filters:

Security filter chain: [
  WebAsyncManagerIntegrationFilter
  SecurityContextPersistenceFilter
  HeaderWriterFilter
  LogoutFilter
  OAuth2AuthenticationProcessingFilter
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  FilterSecurityInterceptor
]

What I don't understand is why for the other modules the #oauth2.xx expression is not evaluated since the FilterChain is the same?


回答1:


Request matchers (specified in antMatchers, anyRequest, etc.) are processed by the filter chain in the order they are specified. Because multiple ResourceServiceConfiguredAdapter instances simply configure off of the same instance of HttpSecurity, the matchers are processed something like this for each one of your requests:

if (uri == "/module1/resource") {
    // ...
} else if (uri == "/module1/test") { 
    // ...
} else if (true) { // anyRequest
    // ...
} else if (uri = "/module2/resource") {
    // ...
} else if (uri = "/module2/test") {
    // ...
}

As you can see, the last two if conditions would never get hit.

Here are two things you can consider:

Replace anyRequest()

anyRequest is usually very handy; however, in this case, you don't actually mean "any request" since you are trying to narrow the scope to certain module paths. You might instead do:

http
    .requestMatchers()
        .antMatchers("/module2/**")
        .and()
    .authorizeRequests()
        .antMatchers("/module2/resource").authenticated()
        .antMatchers("/module2/test").access( "#oauth2.isClient()")
        .antMatchers("/module2/**").access( "#oauth2.hasScope('webclient')" );

That way, the module doesn't overreach and try and specify behavior that maybe it doesn't know about.

Truthfully, it is typically harmless to call anyRequest since you are already narrowing the scope of the filter chain already with requestMatchers. But, because you are composing a single HttpSecurity with multiple adapters, there is this hidden complexity.

oauth2ResourceServer() - Spring Security 5.1+

If you are on Spring Security 5.1, then there is actually support built into WebSecurityConfigurerAdapter natively, so you don't need to use ResourceServerConfigurerAdapter anymore, at least for JWT-encoded tokens at this point. This is also nice because two WebSecurityConfigurerAdapters are treated as separate filter chains.

Depending on the OAuth 2.0 features you need, you may be able to do that instead:

@EnableWebSecurity
public class Module1Config extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .requestMatchers()
                .antMatchers("/module1/**")
                .and()
            .authorizeRequests()
                .antMatchers("/module1/resource").authenticated()
                .anyRequest.hasRole("SCOPE_webclient")
            .oauth2ResourceServer()
                .jwt();
    }
}

This is an active area of development for Spring Security right now - porting features over into WebSecurityConfigurerAdapter; so definitely reach out with your specific use case to make sure that it gets prioritized if it isn't already in place.



来源:https://stackoverflow.com/questions/54030887/spring-security-oauth2-oauth2-xxx-expressions-not-evaluted-with-multiple-req

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!