Posts Tagged ‘ACL method invocation security

19
Sep
09

Integration of Spring Security into Grails – plugin approach 2

As mentioned in the last post, subject of this post will be the implementation of ACL method invocation security within the acegi security plugin 0.5.1 . In addition to that I will describe the implementation of domain objects which work with the standard JDBCMutableAclService. The next and last post of this series will present the working plugin version with corresponding documentation.

Let us begin with a description of the ACL method invocation security. The biggest challenge was to provide a solution for user based creation of custom voters. These voters are needed if you want to check method parameters with ACLs. An example method for this may look as follows:

def delete(Image image) {
	// do stuff
}

In this case the image parameter will be checked for existing acls concerning the calling user. If the user does not have correct permissions on the passed image object an access denied exception will be thrown. The configuration of this functionality assumes that the application developer defined a custom voter before, which handles permissions for image objects. A definition of a voter like this in plain Spring Security could look similar to the following example (from contacts sample app):

<!-- An access decision voter that reads ACL_CONTACT_DELETE configuration settings -->
  <bean id="aclContactDeleteVoter" class="org.springframework.security.vote.AclEntryVoter">
    <constructor-arg ref="aclService"/>
    <constructor-arg value="ACL_CONTACT_DELETE"/>
    <constructor-arg>
      <list>
        <ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
        <ref local="org.springframework.security.acls.domain.BasePermission.DELETE"/>
      </list>
    </constructor-arg>
    <property name="processDomainObjectClass" value="sample.contact.Contact"/>
  </bean>

After this definition the voter has to be registered to an access decision manager with the following example configuration (look at aclContactDeleteVoter):

<!-- An access decision manager used by the business objects -->
  <bean id="aclAccessDecisionManager"
    class="org.springframework.security.vote.AffirmativeBased">
    <property name="allowIfAllAbstainDecisions" value="false"/>
    <property name="decisionVoters">
      <list>
        <ref local="aclContactDeleteVoter"/>
      </list>
    </property>
  </bean>

(To make this blog post as compact as possible an example for a concrete usage definition of the voter on a method was omitted. Please look at the contacts sample application of the spring security distribution for details)

As these associations and voters can vary from application to application the plugin developer cannot guess which voters maybe needed in advance. This is not a problem because the acegi plugin takes care of an own configuration file (SecurityConfig.groovy) which can be used to provide user defined configurations. In my case I used a list and map based configuration approach which will be described in detail in the next part of this series.

Another problem however is very challenging. Grails BeanBuilder DSL is very handy when dynamically defining Spring Beans and in a plugin this is done within the doWithSpring closure. An implementation of the access decision manager mentioned above would be similar to this:

aclAccessDecisionManager(org.springframework.security.vote.AffirmativeBased){
      allowIfAllAbstainDecisions=false
      decisionVoters=[//aclentryvoters are added within doWithApplicationContext
        ref("roleVoter")]
}

The omission of the custom voters in this example reveals the problem. To dynamically represent the definition of the aclAccessDecisionManager from the xml example you would have to iterate over the user configurations and dynamically add beans to the list of decision voters.
As far as I know this is impossible because a list definition of decision voters would expect one Java type for a list entry. This means, eg., that ref(“roleVoter”) must be represented as a String in a List of role voters and then injected into the decision voters list of the aclAccessDecisionManager. Regrettably this does not work because a String representation of ref(“roleVoter”) does not reflect the special role of the ref-construct.

Fortunately I found a workaround to this problem in the Spring Security API by following a two phase approach. While inspecting the Spring Security API I discovered that it is possible to change the decision voter definition at runtime . In this way it is possible to first create voters with definite names from the user security configuration. After the creation of the voters in the plugin doWithSpring closure these definite names together with the predefined aclAccessDecisionManager bean can be used to retrieve the corresponding bean instances within the doWithApplicationContext plugin closure. Again after retrieving the bean instances of the voters they can be added to the aclAccessDecisionManager with the help of its public void setDecisionVoters(List newList) method and ACL method invocation security will work :-).

Another issue of the implementation so far was the fact that a custom spring bean was needed to initialize the database schema for the JDBCMutableAclService. This was not very grails like and so I decided to implement domain classes which “create” the schema. For this to work the GORM had to be exactly the same as the manual creation of the tables with plain SQL. To get this working I had to explicitly define custom table names which fortunately is possible in GORM. Additionally optimistic locking which leads to separate version column in the database had to be disabled.

In summary the documentation of the implementation in the last blog posts led to a working acegi security plugin 0.5.1 with ACL support and method invocation security. This is why the last and final blog post will only describe the usage of the plugin enhancements.

Regards,
Phillip

Jump to other parts of this series:




April 2024
M T W T F S S
1234567
891011121314
15161718192021
22232425262728
2930