- 
                Notifications
    
You must be signed in to change notification settings  - Fork 6.2k
 
AuthorizationManager + Method Security Support #9350
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @evgeniycheban! This is a good start.
I've left some feedback inline. In addition to that, please keep classes final until there is a clear need for extension.
I have some additional thoughts, but I'm guessing they will shake out when you add Pre/PostAuthorize support.
        
          
                ...ork/security/access/intercept/aopalliance/MethodSecurityAuthorizationManagerInterceptor.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
              
          
                ...ngframework/security/config/annotation/method/configuration/MethodSecurityConfiguration.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
      2f7ca1f    to
    a2ae4a6      
    Compare
  
    | 
           @jzheaux I added support for   | 
    
a2ae4a6    to
    05a35ee      
    Compare
  
    There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @evgeniycheban! I've left some additional feedback.
        
          
                ...ccess/expression/method/ExpressionBasedPostMethodInvocationAuthorizationManagerResolver.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
              
          
                ...ccess/expression/method/ExpressionBasedPostMethodInvocationAuthorizationManagerResolver.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
              
          
                ...rg/springframework/security/access/intercept/aopalliance/AuthorizationMethodInterceptor.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
              
          
                ...ccess/expression/method/ExpressionBasedPostMethodInvocationAuthorizationManagerResolver.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
      fb11b02    to
    d0244a5      
    Compare
  
    There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @evgeniycheban! I've left my feedback inline.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this interface, though I wonder if a better name is AuthorizationManagerAfterAdvice. The reason for that is that it's clear from the name that it is intercepting and perhaps mutating the return value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed to AuthorizationManagerAfterAdvice.
        
          
                ...org/springframework/security/access/method/MethodInvocationAuthorizationManagerResolver.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
      d50798a    to
    3822746      
    Compare
  
    There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great, @evgeniycheban! It's really starting to take shape. I've left some feedback inline.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you could instead do:
this.pointcut = Pointcuts.union(this.beforeAdvice, this.afterAdvice);Then, you can remove the inner class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know Spring Security did a lot of this in the past, but I'd like to see if this can be changed to be bean-based instead of based on extending a class.
One way that might work would be to do:
@Autowired(required = false)
public void setMethodSecurityExpressionHandler(MethodSecurityExpressionHandler custom) {
    this.methodSecurityExpressionHandler = custom;
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If successful, then let's also make the class final
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The @Configuration class cannot be final because Spring creates a CGLIB proxy for it. I think we could make it just package private.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact, setting the proxyBeanMethods attribute to false allows the @Configuration class to be final.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might not go into this PR, but it would be nice if an application could do:
@Bean 
public AuthorizationManagerBeforeAdvice<MethodInvocation> myBeforeAdvice() {
    // ....
}
@Bean 
public AuthorizationManagerAfterAdvice<MethodInvocation> myAfterAdvice() {
    // ...
}And MethodSecurityConfiguration would take that one instead of its own.
This would be the equivalent of supplying a custom SecurityMetadataSource
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While the class is expression-based, it would be ambiguous if other expression-based ways to give advice were added later on to the framework. We might want to call this PreAnnotationAuthorizationManagerAfterAdvice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should match the AffirmativeBased matcher, since that's the default in @EnableGlobalMethodSecurity. It returns the first voter that grants and only denies if one of the voters denied.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. In the current version the DelegatingAuthorizationManagerBeforeAdvice returns the first granted AuthorizationDecision and the denied AuthorizationDecision only if one of the DelegatingAuthorizationManagerBeforeAdvices denied. If multiple DelegatingAuthorizationManagerBeforeAdvices denies then the first denied AuthorizationDecision is returned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd recommend that this change to a setter. Typically, Spring Security places required parameters in the constructor and optional ones as setters. Since there's a default handler that will work in most cases, using the default constructor will make it more convenient for applications to use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
3822746    to
    abc9965      
    Compare
  
    26a3ab8    to
    cb62099      
    Compare
  
    cb62099    to
    af92fd5      
    Compare
  
    | 
           @jzheaux I've updated the PR according to your comments.  | 
    
a5b27e9    to
    2b7e042      
    Compare
  
    There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your patience, @evgeniycheban, while I got back to you.
I've left some additional feedback inline.
| * @param beforeAdvice the {@link AuthorizationManagerBeforeAdvice} to use | ||
| * @param afterAdvice the {@link AuthorizationManagerAfterAdvice} to use | ||
| */ | ||
| public AuthorizationMethodInterceptor(AuthorizationManagerBeforeAdvice<MethodInvocation> beforeAdvice, | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rwinch made a good point that it would be nice to see if we can change AuthorizationManagerBeforeAdvice so that it doesn't extend AuthorizationManager.
Two ideas come to mind:
- Change this constructor to
 
public AuthorizationMethodInterceptor(AuthorizationManagerBeforeAdvice<MethodInvocation> beforeAdvice,
        AuthorizationManager<MethodInvocation> beforeManager,
        AuthorizationManagerAfterAdvice<MethodInvocation> afterAdvice,
        AuthorizationManager<MethodInvocation> afterManager)and then PreAnnotationAuthorizationManagerBeforeAdvice would split into two classes --PreFilterAuthorizationManagerBeforeAdvice and PreAuthorizeAuthorizationManager -- and likewise for PostAnnotationXXX
2. Keep the contract as-is, but split PreAnnotationAuthorizationManagerBeforeAdvice into PreFilterAuthorizationManagerBeforeAdvice and something like MethodMatcherAuthorizationManagerBeforeAdvice. The latter would could have an instance of AuthorizationManager (e.g. PreAuthorizeAuthorizationManager) that it would delegate to if the MethodMatcher matches.
The second seems ideal, but I'm listing both for completeness.
In both cases, it seems like the before advice contract would change to return void since not all advices would return an AuthorizationDecision anymore.
1029660    to
    60294fe      
    Compare
  
    806d203    to
    1689a72      
    Compare
  
    There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the updates, @evgeniycheban!
I've left some additional feedback inline.
Also, we're probably close enough to add @since 5.5 to new classes.
        
          
                ...rg/springframework/security/config/annotation/method/configuration/EnableMethodSecurity.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
      There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this class is no longer needed. DefaultPointcutAdvisor should suffice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
        
          
                ...ngframework/security/config/annotation/method/configuration/MethodSecurityConfiguration.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
      There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's please move all these classes to org.springframework.security.authorization.method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking it would be better to have this use MethodAuthorizationContext instead of MethodInvocation. That way, only one MethodAuthorizationContext needs to be generated in AuthorizationMethodInterceptor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
| 
           @jzheaux I updated the PR with the JSR-250 security annotations support.  | 
    
| 
           Thanks again for all the hard work on this PR, @evgeniycheban, it's much appreciated! It's been merged in 20778f7. I also added some polish commits relative to documentation and some small bug fixes. Finally, since we are close to release time, I polished the AOP structure, changing the advice classes to interceptors. These match very nicely with the surrounding interceptor and remove a number of classes needed to support the previous structure.  | 
    
Closes gh-9289