Search code examples
javaspring-mvcspring-securityoauth-2.0

#oauth2 security expressions on method level


What should I do to be able to use #oauth2 security expressions on method level like on the example below?

@RequestMapping(value = "email", method = RequestMethod.GET)
  @ResponseBody
  @PreAuthorize("#oauth2.hasScope('read')")
  public String email() {

    return "[email protected]";
  }

If I do a request to that resource I receive

    [INFO] java.lang.IllegalArgumentException: Failed to evaluate expression '#oauth2.hasScope('read')'
[INFO]  at org.springframework.security.access.expression.ExpressionUtils.evaluateAsBoolean(ExpressionUtils.java:14)
[INFO]  at org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice.before(ExpressionBasedPreInvocationAdvice.java:44)
[INFO]  at org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter.vote(PreInvocationAuthorizationAdviceVoter.java:57)
[INFO]  at org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter.vote(PreInvocationAuthorizationAdviceVoter.java:25)
[INFO]  at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:62)
[INFO]  at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:232)
[INFO]  at org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor.invoke(AspectJMethodSecurityInterceptor.java:43)
[INFO]  at org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect.ajc$around$org_springframework_security_access_intercept_aspectj_aspect_AnnotationSecurityAspect$1$c4d57a2b(AnnotationSecurityAspect.aj:63)
[INFO]  at pl.insert.controllers.ResourceController.email(ResourceController.java:22)

The same thing works well if I specify the access in my ResourceServerConfiguration instead of @Controllers' methods

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

  @Override
  public void configure(HttpSecurity http) throws Exception {
    http.requestMatchers().antMatchers("/oauth/resources/**");
    http.authorizeRequests().anyRequest().access("#oauth2.hasScope('read')");
  }
}

Standard security expressions like @PreAuthorize("permitAll") or @PreAuthorize("denyAll") work as expected. So, probably I have to tell somehow to my AspectJMethodSecurityInterceptor to use OAuth2WebSecurityExpressionHandler. Any ideas?


Solution

  • To enable #oAuth2 security expressions it is only needed to set the default expression handler as OAuth2MethodSecurityExpressionHandler instead of DefaultMethodSecurityExpressionHandler. Because OAuth2MethodSecurityExpressionHandler extends it anyway, then the whole previous functionality remains the same. In my configuration I use both GlobalMethodSecurityConfiguration and WebSecurityConfigurerAdapter.

    @Configuration
    @EnableGlobalMethodSecurity
    public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
    
      @Override
      protected MethodSecurityExpressionHandler createExpressionHandler() {
        return new OAuth2MethodSecurityExpressionHandler();
      }
    }
    
    @Configuration
    @EnableWebSecurity
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
      ...
    }
    
    
    @Configuration
    @Import({ SecurityConfiguration.class, MethodSecurityConfiguration.class })
    public class AppConfiguration {
      ...
    }