Announcement Announcement Module
Collapse
No announcement yet.
"lock out" condition encountered with @PreAuthorize Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • "lock out" condition encountered with @PreAuthorize

    I've got a condition in which a failure to authorize apparently leaves behind some kind of artifact that causes authorization to continue to fail. Example:

    User JOE goes to access his BOOK. The method has a @PreAuthorize condition that ensures that the book and Joe both belong to the same club. This works fine. Next, I try to access a book that belongs to a different club, but I'm still logging in as Joe. This fails, as expected, with the Access is Denied error. Now, we go back to access the original book again. This time, it fails - Access is Denied.

    I cannot find anything in my own code that appears to be hanging on to any references. Are there any special gotcha's or tricks that I might need to be aware of with respect to Spring Security?

    I'll be happy to post code, but I don't want to flood the forum uselessly and I'm really stumped as to what might be relevant.

    Thanks,
    Dave

  • #2
    What's your @PreAuthorize condition?

    Comment


    • #3
      Currently my condition looks like this:
      Code:
      @PreAuthorize("principal.allureAdministrator == true or #player.customer == principal.customer")
      It used to look like:
      Code:
      @PreAuthorize("(#player.customer == principal.customer) or (principal.allureAdministrator == true)")
      I was thinking that there was something about the expression that might be causing my problem.

      Thanks!
      Dave

      Comment


      • #4
        I'm finding that this problem is throughout all of my secured interfaces. So, I thought I'd try posting more of my configuration in hopes that something will ring a bell.

        Example interface:
        Code:
        public interface FontSecuredService {
            @PreAuthorize("(#font.customer == principal.customer) or (principal.allureAdministrator == true)")
            public String getFontFilePath(Font font);
        }
        bean defining this interface:
        Code:
            <bean id="fontSecuredService" scope="prototype" class="com.allureglobal.harvey.webservice.secured.FontSecuredServiceImpl">
                <constructor-arg ref="fontService"/>
            </bean>
        security configuration:
        Code:
            <global-method-security pre-post-annotations="enabled">
                <protect-pointcut expression="execution(* com.allureglobal.harvey.securedservice.*SecuredService.*(..))" access="ROLE_USER,ROLE_PLAYER"/>
            </global-method-security>
            
            <http>
              <intercept-url pattern="/thirdParty/**"   access="ROLE_USER"/>
              <intercept-url pattern="/management/**"   access="ROLE_USER"/>
              <intercept-url pattern="/distribution/**" access="ROLE_PLAYER,ROLE_USER"/>
              <intercept-url pattern="/upload/**"       access="ROLE_PLAYER"/>
              <http-basic/>
            </http>
         
            <authentication-manager>
                <authentication-provider user-service-ref="userDetailsService">
                    <password-encoder hash="sha" base64="true"/>
                </authentication-provider>
            </authentication-manager>
                
            <beans:bean id="userDetailsService" scope="prototype" class="com.allureglobal.harvey.webservice.security.SalientUserDetailsService">
                <beans:constructor-arg ref="userDao"/>
                <beans:constructor-arg ref="playerDao"/>
                <beans:constructor-arg ref="fatherTime"/>
            </beans:bean>
            
            <beans:bean id="loggerListener" class="org.springframework.security.authentication.event.LoggerListener" />
            
            <beans:bean id="securityContextFacade" class="com.allureglobal.harvey.webservice.security.SecurityContextFacadeImpl"/>
        web services configuration:
        Code:
          <context:component-scan base-package="com.allureglobal.harvey.webservice" annotation-config="false"/>
        
          <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
        
          <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
        
          <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
            <property name="order" value="0"/>
          </bean>
        I hope someone can spot something. I'm stumped.
        Thanks,
        Dave

        Comment


        • #5
          Does it work if you remove the pointcut?

          Comment


          • #6
            I commented out the @PointCut and accompanying method in my service implementation, and I commented out the <protect-pointcut/> tag in my security configuration. This had no effect on the behavior.

            I assume that this should have been sufficient to remove that feature.

            Comment


            • #7
              So, I tried something a little more radical that brought about a change, but not any better. I moved my "secured" services beneath the "webservice" package defined in my source base so that the component scanner would find them. I then annotated all of the secured service implementations as @Service. Using this configuration, I did not encounter the lock-out problem, but it seems that the @PreAuthorize annotations are now completely ignored. I can get to any resource regardless of who owns it.

              For what it's worth, I thought I'd post this finding.

              Comment


              • #8
                I have some detailed information now. I figured out what package to put a DEBUG logger on, and now I can see what Security is actually deciding!

                Pointcuts are still commented out, and I moved the @PreAuthorize annotations to the implementation class (instead of the interface class).

                With this configuration:

                Try #1 - should succeed to call method. All voters return 1. Seems reasonable. Call succeeded.

                Try #2 - should fail. Call failed as expected.
                PreInvocationAuthorizationAdviceVoter@1c75cff, returned: -1
                RoleVoter@1b6a350, returned: 0
                AuthenticatedVoter@19bf7d0, returned: 0

                Try #3 - should succeed - same as Try #1. Call failed.
                PreInvocationAuthorizationAdviceVoter@1c75cff, returned: -1
                RoleVoter@1b6a350, returned: 0
                AuthenticatedVoter@19bf7d0, returned: 0

                Looking at both #2 and #3, I can also see that MethodSecurityInterceptor sees an authenticated principal with granted authorities: ROLE_USER. So, it seems strange that the RoleVoter would return a 0, right?
                Last edited by dhicks; Feb 10th, 2010, 03:34 PM. Reason: Additional Information Added

                Comment


                • #9
                  No. In your case you are using a PreAuthorize annotation. Whether a voter votes or not is determined by the metadata attributes for the invocation. RoleVoter has no input, as there are no "ROLE_" attributes defined, so it abstains.

                  If you want to check for a role using expressions you can use

                  Code:
                  @PreAuthorize("hasRole('ROLE_USER') and <whatever else you want>")
                  In general you can't mix different attribute sources for the same method. So a pointcut will be overriden by an annotation, for example.

                  Comment


                  • #10
                    I see. So having both a point-cut and a PreAuthorize is useless. I was using the Tutorial code as a sample to get started. That explains why the point-cut is commented out in the example code.

                    In general, the role has no real affect on whether I'll execute my methods or not. I think the definition of my <http> tag takes care of which roles have access to which URL's, anyway.

                    So, we're back to the authorization problem. For some reason, once an authorization fails, they all fail from that point on. I'm beginning to get pressure from "the powers" to cut and run to get the task done any way I can. I'd hate to bail out on this now, when it seems so close to working as it should.

                    I'm trying to soak up as much of this stuff as I can. I'm a bit of a Spring Security newbie (though, I'm sure that's painfully obvious), but learning a lot.

                    Thanks for the feedback. I guess I'll keep trying things, but I'm pretty much stumped.
                    Dave

                    Comment


                    • #11
                      One possible bug is the == comparison - unless the 2 objects in question implement Comparable, this will use the Java == operator, and not .equals, which may not provide correct or expected results for the #font.customer == principal.customer check.

                      Comment


                      • #12
                        That's a great possibility! I did make sure that the equals() was implemented properly, but I was not aware that I needed to implement Comparable. I'll check on that first thing in the morning!

                        Thanks for the tip!
                        Dave

                        Comment


                        • #13
                          Well, apparently it's not a problem with Comparable. Same result. After thinking about it last night, I really didn't think that would be it, though. The objects that are being compared are materialized by Hibernate. It's more likely that the same actual object instance is used in both cases. Still, it's good to know about this idiosyncrasy. Seems a strange way to implement "==", though. Is there some way of telling the expression to use .equals() ?

                          So, I'm still stumped and stuck. If I can't figure out a solution soon, I'll probably have to scrap all of this and hard-code all the security checks in my services. (Yuck!)

                          Comment


                          • #14
                            Well, I had a bit of an "ah ha" moment. The problem isn't specifically solved, but I realized that I can get around it.

                            In our case, we don't make use of the HTTP session. So, I did my testing again but shut down the browser between each try. Everything works as expected in this case. It's just when the browser is maintaining the session that things go awry.

                            Long story short, I can move forward with my own development. I'd still like to understand why this doesn't work in a session environment, though. It seems to me like there must be a subtle bug here - or we just haven't figured out what stupid, little something I've got misconfigured (greater chance of the latter being true).

                            Thanks for all the help! I'll keep my eyes on this thread, but I'm moving along, now.

                            Comment


                            • #15
                              I am new to spring security. Did any one try to integrate it with database i want to do this. Can any one tell me from where have to start.

                              Comment

                              Working...
                              X