Author Archive for Phillip Merensky

24
Sep
09

Integration of Spring Security into Grails – plugin approach 3

In this post, as mentioned earlier, I will explain how my spring security 2.0.5 ACL (access control list) enhancement of the acegi security plugin 0.5.1 for Grails can be configured. My work bases on Stephan February’s solution for the 0.3 plugin version and acegi security. Apart from the implementation changes within the plugin, the plugin configuration only has minor changes. This is the reason why it is strongly advised to read Stephan’s blog post before continuing with this article as I will only mention major differences between the configuration of his plugin version and mine.

One difference in my version is the possibility of applying ACLs to method parameters (see 2.1 for an example):

For this to work custom voters have to be defined. A custom definition for the example of Stephan’s blog post looks as follows:

springSecACLVoters = [ //this map must be called 'springSecACLVoters'
			aclReportWriteVoter: [// custom beanName
			domainObjectClass: 'Report', // which type of domainclass will be secured
			roleName: 'ACL_REPORT_WRITE', // under which name the voter should be referenced later? Must start with 'ACL_'
			permissions: [ org.springframework.security.acls.domain.BasePermission.ADMINISTRATION,
			org.springframework.security.acls.domain.BasePermission.WRITE] // which concrete permissions will be checked if 'ACL_REPORT_WRITE' is specified
			],
			aclReportDeleteVoter: [
			domainObjectClass: 'Report',
			roleName: 'ACL_REPORT_DELETE',
			permissions: [ org.springframework.security.acls.domain.BasePermission.DELETE]			
			]
	]

I added comments in the corresponding lines to describe the single options in detail. As you can see more than one voter can be defined as long as the map name is ‘springSecACLVoters’ and the map is defined in SecurityConfig.groovy. Please note that if you do not need method parameter checking with ACLs you can simply omit the map configuration of voters.

Aside from the definition of custom voters and for applying ACLs to method parameters I added three other options to SecurityConfig.groovy:

useAcl = true // defaults to false, optional
aclClassIdentityQuery="SELECT @@IDENTITY" // this query is for MySQL, default is 'identity()' for hsqldb, optional
aclSidIdentityQuery="SELECT @@IDENTITY" // this query is for MySQL, default is 'identity()' for hsqldb, optional

If you want to use ACL extensions in general useAcl must be specified and set to “true”. Furthermore the enhancement uses the default JdbcMutableAclService implementation of Spring. For this reason you must have the possibility to change its identity queries (look here) to match your database. This can be done with the two corresponding options. The code snippet above shows working example values for hsqldb and MySQL.

Apart from feature and configuration changes the infrastructure of the plugin did also undergo a change since Stephan’s version: Because of the move of the ACL domain classes into the plugin domain directory the Gant target “CreateAclDomains” is no longer needed.

Therewith the description of the plugin configuration is complete. Some issues however remain to be done:

  1. Calling of acl security functionality when using ‘run-app’ may raise a class not found exception which will not be raised when ‘run-war’ is used. I have to examine this more precisely and eventually file a bug report.
  2. Test cases should be developed before a possible integration of the code into the main acegi security plugin tree. I am in contact with Burt Beckwith to get this working.
  3. I have to upload the code to the GRAILSPLUGINS-723 JIRA task so that Burt Beckwith can decide on a possible integration into the acegi plugin version control tree. I will do this within the next week as I am very busy at the moment.

I hope this helps somebody
Feedback is greatly appreciated

Regards,
Phillip

Jump to other parts of this series:

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:

19
Sep
09

Integration of Spring Security into Grails – plugin approach 1

This blog post describes problems and challenges when porting Stephan February’s solution from acegi security and acegiSecurityPlugin 0.3 to acegiSecurityPlugin 0.5.1 and Spring Security 2.0.5.

One issue was the fact that the whole API names changed from acegi security to spring security and that few api calls changed. Also the libraries had to be changed to work with Spring Security 2.0.5. In this case the grails maven project of the “Spring Way” mentioned before was of great help because maven’s calculated dependencies could simply be copied to the plugin. In this way all Java method.invocation errors went away magically :-). Regrettably the domain classes of Stephan’s solution could not be used any further because the whole schema had changed from Acegi security to Spring Security. That is why I decided to continue the usage of the standard JDBCMutableAclService of Spring in combination with a simple Spring bean which controls the deletion and creation of schemata with plain SQL commands.

Apart from these issues I learned to work with the Grails plugin and the Spring Security API and digged deeper into interceptor technology, expando meta classes, the Grails Bean Builder DSL and Spring Security as a whole.

I already mentioned that our Image Site makes use of very fine grained permission control for which reason it was not acceptable to us that Stephan’s solution did not support applying ACLs (Access Control Lists) to method parameters. For example this could turn out to be very useful if a user wants to delete an image and the deletion method is able to check whether the user has the correct permission on the given image object. This is the reason why I tried to implement applying ACLs to method parameters. Details of the implementation and arising problems will be subject to my next blog post.

Regards,
Phillip

Jump to other parts of this series:

19
Sep
09

Integration of Spring Security into Grails – Spring approach

In the last post of the security layer we decided to integrate Spring Domain Object Security the ‘Spring Way’ into our Grails application. This means that I tried to integrate the security concept without implementing or enhancing Grails or the acegi security plugin. Testable functionality was provided by the contact sample application of Spring Security. This was achieved by using a plain spring configuration file which was referenced from grails-app/config/spring/resources.xml

As we planned to use MySQL as our datasource several changes had to be done to the default configuration. First I needed to provide a different database schema which luckily could be found on Jim Bernatowicz’ Website. Apart from this the identity queries of Spring’s JdbcMutableAclService had to be adapted like this to support MySQL:

<bean id="aclService" class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
    <constructor-arg ref="dataSource"/>
    <constructor-arg ref="lookupStrategy"/>
    <constructor-arg ref="aclCache"/>
    <property name="classIdentityQuery" value="SELECT @@IDENTITY"/>
    <property name="sidIdentityQuery" value="SELECT @@IDENTITY"/>	
</bean>

Another problem I faced was that grails run:app threw errors when trying to find some security classes. Strange to say grails run:war worked perfectly. As we did not need grails:run-app functionality I decided to postpone this problem.

Apart from these issues this solution worked, but only for Java classes. An integration of Groovy classes into Spring like http://www.javabeat.net/articles/46-integrating-spring-and-groovy-1.html seemed heavy weighted and cumbersome to me. For this reason and with more Spring Security insight I decided to look deeper into the plugin approach of Stephan February and port it to the version 0.5.1 of the acegi-security plugin which will be part of the next blog post.

Regards,
Phillip

Jump to other parts of this series:

19
Sep
09

The Decision

As you probably already know when reading this blog our project consists of building an image managing website based on Grails with fine grained access control.  Therefore we need access control not only on role level but on object level. This means that we have to define access rights for a dynamic set of roles each with a dynamic set of users. UserA e.g. may have ReadRights on ImageA but AdminRights on ImageB and UserB may have ReadRights on ImageB but AdminRights on ImageA. In this case a role based approach needs to define a role for each combination of permission and image. Because normal role based approaches are not developed for millions of roles we needed a different approach.

As we did not have enough time to implement a whole security system by ourself we decided to look into Spring Security which we had in mind because of the acegi security plugin for grails. Spring Security has several advantages which were for us in short:

  • very flexible because security access can be defined on method level
  • LDAP, RemeberMe and OpenID authentication
  • long history (acegi security base) and thus a hopefully stable approach

Because of the use case mentioned in the beginning of this post the basic role based approach in “normal” Spring Security was not enough. Domain object security however seemed to be exactly what we needed.  Some reasons for using domain object security in our case are:

  • For each domain object instance (eg picture number 23) it is possible to define an own ACL (Access Control List) which contains ACEs (Access Control Entries). This way each object instance has its own list of principals (users) which again have its own permissions (read, write, etc.)
  • White and black ACEs are supported (either restrict or enhance permissions)
  • Furthermore inheritance of ACLs is supported
  • Performance -> “one of the main capabilities of the Spring Security ACL module is providing a high-performance way of retrieving ACLs”

The only problem seemed to be that the Acegi Security Plugin for Grails did not support domain object security and that is why we decided to integrate Spring Security the spring-way into grails. How I solved this will be mentioned in the next post.

Regards,

Phillip

Jump to other parts of this series:




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