Announcement Announcement Module
Collapse
No announcement yet.
Dynamic Authorization Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Dynamic Authorization

    Hi,
    Is it possible to make ROLE-METHOD mapping in a database table... For example:
    <bean id="bankManagerSecurity" class="net.sf.acegisecurity.intercept.method.Metho dSecurityInterceptor">
    ...
    <property name="objectDefinitionSource">
    <value> net.sf.acegisecurity.context.BankManager.delete*=R OLE_SUPERVISOR,RUN_AS_SERVER
    net.sf.acegisecurity.context.BankManager.getBalanc e=ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOME R,RUN_AS_SERVER

    </value>
    </property>
    </bean>
    Can't we hold net.sf.acegisecurity.context.BankManager.delete* and roles that which were permitted to invoke it, in a database table...

    We want to make such a thing because in our application 'Administrator' can create new roles at runtime and can map these roles to the methods... According to the example above 'Administrator' must add method-role mapping definition in applicationContext.xml after creating roles...

    Or is there a better way of implementing this kind of dynamic authorization.
    We exactly want to do this:
    At runtime 'Administrator' will give permissions to users for reaching appropriate jsp pages. How can we implement this?

    Thanks in advance.




    [/b]

  • #2
    You can implement your own ObjectDefinitionSource and refer to it via <ref bean="myDatabaseDrivenObjectDefinitionSource"/>.

    Comment


    • #3
      yDatabaseDrivenObjectDefinitionSource

      Can you give some more information about creating database driven ObjectDefinitionSource. API docs and ReferenceManual don't give any information about this.
      From reference manual:
      The MethodSecurityInterceptor can be configured with configuration attributes in three ways. The first is .....
      The third is via writing your own ObjectDefinitionSource, although this is beyond the scope of this document.
      Where can we find information about creating custom ObjectDefinitionSource...
      Thanks...

      Comment


      • #4
        You're interested in method interception, meaning you're using MethodSecurityInterceptor. It uses a marker interface which is derived from ObjectDefinitionSource called MethodDefinitionSource.

        To write a custom MethodDefinitionSource you'll need to read the JavaDocs for ObjectDefinitionSource. There are three methods, each well defined by the JavaDocs. Indeed there are two concrete implementations - MethodDefinitionMap and MethodDefinitionAttributes - which implement MethodDefinitionSource. These both use AbstractMethodDefinitionSource, which implementes two of the three methods you need to handle from the ObjectDefinitionSource contract. You're only left to handle:

        Code:
            /**
             * Performs the actual lookup of the relevant
             * <code>ConfigAttributeDefinition</code> for the specified
             * <code>MethodInvocation</code>.
             * 
             * <P>
             * Provided so subclasses need only to provide one basic method to properly
             * interface with the <code>MethodDefinitionSource</code>.
             * </p>
             *
             * @return the <code>ConfigAttributeDefinition</code> that applies to the
             *         specified <code>MethodInvocation</code>
             */
            protected abstract ConfigAttributeDefinition lookupAttributes&#40;
                MethodInvocation mi&#41;;
        Hope that's enough info. If not, please post a specifc question.

        Comment


        • #5
          Thanks Ben you explained the relationships very well.
          There are some points that I don't understand and want your help.
          1-> How the MethodDefinitionSource is constructed from the value of objectDefinitionSource in the following example.
          Code:
          	<bean id="securityInterceptor" class="net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor">
              	<property name="authenticationManager"><ref bean="authenticationManager"/></property>
              	<property name="accessDecisionManager"><ref bean="businessAccessDecisionManager"/></property>
              	<property name="runAsManager"><ref bean="runAsManager"/></property>
           		<property name="objectDefinitionSource">
          			<value>
          				sample.user.service.UserManager.save*=ROLE_SUPERVISOR,RUN_AS_SERVER
          				sample.user.service.UserManager.remove*=ROLE_SUPERVISOR,RUN_AS_SERVER
          			</value>
          		</property>
          	</bean>
          2-> Rather than writing the method=ConfigAttributeDefinition mapping in the applicationConfig.xml, I want to hold these values in a database table. For example, MethodAuthorizations table holds a MethodName field (which holds values like sample.user.service.UserManager.save*) and a ConfigAttributeDefinition field(which holds the values like ROLE_SUPERVISOR,RUN_AS_SERVER). After retrieving these values from database I will re-construct them as shown in the above example and I will pass them to MethodDefinitionMap for retrieving ConfigAttributeDefinition for MethodSecurityInterceptor. But I don't know how to handle lookupAttributes() method of MyCustomMethodDefinition class which will extend from AbstractMethodDefinitionSource. Can you help me for accomplishing this subject.
          Thanks for your helps.

          Comment


          • #6
            To answer question 1, this works because Spring automatically applies PropertyEditors. Because MethodSecurityInterceptor.objectDefinitionSource is a MethodDefinitionSource, Spring uses the MethodDefinitionSourceEditor. The MethodDefinitionSourceEditor gets passed the entire multi-line String that comprises the entire object definition. It then tokenizes it as if it were a standard Java Properties file. This results in the property name of each line (ie anything to the left of the equals sign) being treated as the method name and passed to the newly created MethodDefinitionMap, with the property value of each line (ie anything to the right of the equals sign) being passed to a ConfigAttributeEditor. ConfigAttributeEditor uses the comma delimiter to build a SecurityConfig instance of each token, putting them all into a ConfigAttributeDefinition that is then returned. The returned ConfigAttributeDefinition is passed to the MethodDefinitionMap.

            To answer question 2, I'd normalise the database so you have a SECURE_OBJECT table, a ROLES table, and a SECURE_OBJECT-ROLES table. Thus your DatabaseObjectDefinitionSource can be wired to either a MethodSecurityInterceptor or a FilterSecurityInterceptor. The SECURE_OBJECT table should have a TYPE column to denote whether it's for a MethodInvocation or a FilterInvocation declaration. Once you've got the schema sorted out, it's a simple matter to build a ConfigAttributeDefinition in response to a request. I'd consider returning null to the getConfigAttributeDefinitions() method, as it's only used by AbstractSecurityInterceptor to help with inital configuration checking.

            Comment


            • #7
              Thanks again Ben, I implemented my DatabaseDrivenMethodDefinitionSource with your helps.

              I created the schema as you defined. Here is my protected ConfigAttributeDefinition lookupAttributes(MethodInvocation mi) method;

              Code:
              	protected ConfigAttributeDefinition lookupAttributes&#40;MethodInvocation mi&#41; &#123;
              		//construct secureObjectName 
              		String secureObjectName=mi.getMethod&#40;&#41;.getDeclaringClass&#40;&#41;.getName&#40;&#41; +"."+ mi.getMethod&#40;&#41;.getName&#40;&#41;;
              		SecureObject secureObject=securityManager.getSecureObject&#40;secureObjectName&#41;;
              		if&#40;secureObject==null&#41;//if secure object not exist in database
              			return null;
              		//retrieving roles associated with this secure object
              		List secureObjectRoles=&#40;List&#41;securityManager.getSecureObjectRoles&#40;secureObject&#41;;
              		//creating ConfigAttributeDefinition
              		if&#40;!secureObjectRoles.isEmpty&#40;&#41;&#41;&#123;
              			ConfigAttributeEditor configAttrEditor=new ConfigAttributeEditor&#40;&#41;;
              			StringBuffer rolesStr=new StringBuffer&#40;&#41;;
              			for&#40;int i=0;i<secureObjectRoles.size&#40;&#41;;i++&#41;&#123;
              				SecureObjectRole sor=&#40;SecureObjectRole&#41;secureObjectRoles.get&#40;i&#41;;
              				rolesStr.append&#40;sor.getRole&#40;&#41;.getRoleName&#40;&#41;&#41;.append&#40;","&#41;;
              			&#125;
              			configAttrEditor.setAsText&#40; rolesStr.toString&#40;&#41;.substring&#40;0,rolesStr.length&#40;&#41;-1&#41; &#41;;
              			ConfigAttributeDefinition configAttrDef=&#40;ConfigAttributeDefinition&#41;configAttrEditor.getValue&#40;&#41;;
              			return configAttrDef;
              		&#125;
              		return null;
              		
              	&#125;
              -I have one more question about this subject. For every declared method, lookupAttributes() method reaches database for retrieving secureObjectRoles. This may decrease the performance of the application... Can you suggest anything better.
              very happy now...

              Comment


              • #8
                Sure, just use a caching layer like EH-CACHE. Take a look at the implementation of DaoAuthenticationProvider and UserCache for a guide.

                Comment


                • #9
                  Wow, cool thread - I think I'll use this approach in my app too.

                  Ben, I'll summarize this if you're interested in adding it to the user's manual.

                  Scott

                  Comment


                  • #10
                    Hi Scott - no problemo. I always welcome contributions. Feel free to email me any diffs etc.

                    Thanks
                    Ben

                    Comment


                    • #11
                      Hibernate laziness complication...

                      mavisaka or Ben,

                      If I use a daoAuthenticationProvider as my authenticationManager, and I hang my role set off of the user's object graph, I get a LazyInstantiationException when the DatabaseDrivenMethodDefinitionSource tries to iterate through the roles. I think this is because the lifespan of the Hibernate Session ends after the authentication process, making the roles unavailable for instantiation. I've tried to make the role set non-lazy to no avail, and I've also tried to use BeanUtils.copyProperties() in my daoAuthenticationProvider to return a more fully instantiated user object, but that doesn't work either.

                      Any recommendations? Big thanks in advance...
                      Scott

                      Comment


                      • #12
                        Have you tried the Hibernate.initialize(Object) static method?

                        Comment


                        • #13
                          I tried (thanks for the tip) but it didn't work, so I ended up creating an additional non-lazy object and Hibernate mapping specifically for authentication and authorization.

                          Comment


                          • #14
                            Hi ,
                            Code:
                            protected ConfigAttributeDefinition lookupAttributes(MethodInvocation mi) {
                            		//construct secureObjectName 
                            		String secureObjectName=mi.getMethod().getDeclaringClass().getName() +"."+ mi.getMethod().getName();
                            		SecureObject secureObject=securityManager.getSecureObject(secureObjectName);
                            		if(secureObject==null)//if secure object not exist in database
                            			return null;
                            		//retrieving roles associated with this secure object
                            		List secureObjectRoles=(List)securityManager.getSecureObjectRoles(secureObject);
                            		//creating ConfigAttributeDefinition
                            		if(!secureObjectRoles.isEmpty()){
                            			ConfigAttributeEditor configAttrEditor=new ConfigAttributeEditor();
                            			StringBuffer rolesStr=new StringBuffer();
                            			for(int i=0;i<secureObjectRoles.size();i++){
                            				SecureObjectRole sor=(SecureObjectRole)secureObjectRoles.get(i);
                            				rolesStr.append(sor.getRole().getRoleName()).append(",");
                            			}
                            			configAttrEditor.setAsText( rolesStr.toString().substring(0,rolesStr.length()-1) );
                            			ConfigAttributeDefinition configAttrDef=(ConfigAttributeDefinition)configAttrEditor.getValue();
                            			return configAttrDef;
                            		}
                            		return null;
                            		
                            	}
                            It seem to me that the implementation above still cannot avoid hitting the database , even you use a cache suggested by Ben for every method invocation (OR what object to cache in this implementation ?).
                            Sure, just use a caching layer like EH-CACHE. Take a look at the implementation of DaoAuthenticationProvider and UserCache for a guide.
                            moon
                            Last edited by yfmoan; Dec 13th, 2005, 06:13 AM.

                            Comment


                            • #15
                              Why are you even writing a database-driven MethodDefinitionSource? I can't see a strong need for database metadata for method invocations - unlike web URIs where I can see a lot of potential value in some applications.

                              Comment

                              Working...
                              X