Announcement Announcement Module
No announcement yet.
How do I authorize a method with role OR another role & Page Title Module
Move Remove Collapse
This topic is closed
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • How do I authorize a method with role OR another role &

    Hi there,

    First of all I just want to say that Acegi is really cool once you wrap your head around it. This hasn't been quick for me, but I think I'm finally getting the hang of it.

    Here's my problem:

    Let's say I have ROLE_A and ROLE_B for users. I want to secure my getFooById method so that only ROLE_A users can see the results, whatever they are. This, in itself, is easy enough:

    And if I want to secure it so that only ROLE_B owners (having correct ACL permissions) of the returned object can see the results, I can do this:


    Now, given those two definitions, how would I say "allow the object returned by getFooById for any ROLE_A and only ROLE_B with the ACL permissions"? In other words, how would I combine these two requirements?

    Is this possible, or do I need to propogate the ACL entries to the ROLE_A user as well? I'm looking to avoid creating tons of ACL entries if possible, but if that's the way to do it (i.e. ROLE_A, ROLE_B, AFTER_ACL_READ) where ROLE_A has all the duplicate ACL entries of ROLE_B, well, then I'll deal with it. However, I'm sure i'm just missing something. Thoughts?

  • #2
    Frst up,,AFTER_ACL_READ is perfectly on the right track. But you'll need to expand it to =ROLE_A,ROLE_B, so that both ROLE_A and ROLE_B users can call the method. Typically a generic ROLE_EVERYONE is used, as you know security will actually be enforced on the returned object via the AfterInvocationManager, so there's no need to list every allowed role.

    The next issue is how to wire up AFTER_ACL_READ to do its magic. The beans you want are like this (as getFooById returns just a single instance, not a collection):

       <bean id="afterInvocationManager" class="net.sf.acegisecurity.afterinvocation.AfterInvocationProviderManager">
          <property name="providers">
                <ref local="afterAclRead"/>
       <bean id="afterAclRead" class="net.sf.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationProvider">
          <property name="aclManager"><ref local="aclManager"/></property>
          <property name="requirePermission">
    		    <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
    		    <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
       <bean id="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
          <property name="staticField"><value>net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION</value></property>
       <bean id="net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
          <property name="staticField"><value>net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ</value></property>
    Now all you need to do is make your AclManager indicate to grant access to all ROLE_A members, and only some ROLE_B members. This is more a case of assigning appropriate permissions for both role recipients via the JdbcExtendedDaoImpl (or some other implementation if you customised it). People usually construct a hierarchy, so all the Foos are have a common parent, and it is to this common parent you create a single ACL record granting the read privilege to ROLE_A.

    Hope this clears things up a little.


    • #3
      Thanks Ben. Actually, I had gotten to the point of setting up the afterInvocationManager and other necessary dependencies -- it worked great -- I was more wondering if there was a way to enforce ACL-level security on one role but not another for the same method invocation.

      I think I'll end up assigning multiple roles per user (as you suggested) and writing some more ACL management code.

      What I was hoping to avoid is having to assign ACL permissions to every Foo in the system once a new sysadmin came on board, and having to give ACL permissions to every sysadmin in the system every time a new Foo is added, but I guess programmatically this isn't really that hard. I'm just lazy .

      Is it possible to have a parent object of a different type than the child object (ie.. a SecurityParent class that simply serves to aggregate the Foos under its ACL definition?). This way I could create arbitrary secure objects for each class for each user, and just have that one secure object exist w/o having to deal with it specifically in the bus. logic.

      I guess with great power comes great responsibility..


      • #4
        Ok, I figured it out -- turned out to be so simple

        I guess I had it in my head that any ACL definition also had to have a role definition, but on further thought it's pretty obvious that they work independently (and each voter will do its job).

        So, to secure a method based on role *and* ACL, you just say:
        Code:, AFTER_ACL_READ
        This allows ROLE_A to always see everything, whereas ROLE_B will need the required ACL permissions for the object to see it.

        I feel like i'm getting the hang of this...

        Hope this helps someone else.


        • #5
          Just to elaborate....

          Taking that example, AFTER_ACL_READ will always need to approve the object being returned. But for the method to be invoked in the first place, whether ROLE_A and ROLE_B is needed will depend on the AccessDecisionVoter used:

          - UnanimousBased would need the user to hold both ROLE_A and ROLE_B
          - AffirmativeBased would need the user to hold either ROLE_A or ROLE_B (or both)
          - ConensusBased would need the user to hold either ROLE_A or ROLE_B (or both)

          ConsensusBased is an interesting one. If a user holds just ROLE_A, but not ROLE_B, RoleVoter will vote +1 affirmative, and -1 deny. So ConsensusBased will decide by default to allow access (based on its allowIfEqualGrantedDeniedDecisions property). If there was also a ROLE_C config attribute, and the user still only held ROLE_A, that would be +1 but -2 - more deny votes than affirmative votes, and access would be denied.

          If you're using ACLs you don't even need to have a ROLE_*. Instead you can rely solely on the AfterInvocationManager to reject access from unauthorised users. However, it's better practice to stop the invocation before it even takes place if the user is unauthenticated, so a ROLE_EVERYONE (or similar) is the norm.

          Hope this elaborates somewhat on the subtle interactions going on.


          • #6
            Yes, that helps -- thanks!. Knowledge of exactly how the voters work will be very useful when I have more complex requirements (soon enough). The biggest challenge for me was just realizing that roles and ACL permissions can act completely independently of one another; somehow I thought ACLs had to be tied to roles.

            I think a HOW TO discussion would be really useful in the documentation. In other words, how would I deal with case X, or case Y, and so on. I guess this forum serves that purpose, but eventually some of these cases (including the onewe were discussing above) will start to come up quite often. Maybe some kind of wiki? Also, a one-page HTML version of the current guide would be great -- it makes it much much easier to search the guide quickly for keywords.

            But this is nitpicking. Thanks again for all your hard work creating Acegi and help in this forum. Keep up the good work.


            • #7
              We already have a single HTML page. You can find the link off