Prerequisites
Please refer to the Resources section at the end of this article for downloads
There are primarily two use-cases for the current Acegi Plugin's ACL extensions:
- Protecting Method Invocations
- Protecting Domain object instances
1. Protecting Method Invocations
You can protect method invocations by requiring logged in user to be in certain roles(ROLE_xxx). This check ignores all method parameters, and will throw an exception if the current user is not in the required Role.
e.g. method signature:
1:public ReportLog getReportLog(Integer reportId){
2: return Report.get(reportId).log
3:}
You can protect domain object instances (tuples in database) using a variety of fine-grained access controls. Currently Acegi supports three (3) distinct methods out of the box, two (2) of which are currently directly supported by the Grails plugin.
2.1. Applying ACLs to method parameters (CURRENTLY UNSUPPORTED!)
This ACL checks the first parameter of a method for a matching domain class to see if current user has ACL on that object instance (ACL_ENTRY).
e.g. method signature:
1:public void saveReport(Report report){
2: report.save()
3:}
to see if the current user has an ACL granting permission for the domain object
instance in the parameter.
2.2 Filtering collections using ACLs
You can filter the domain objects in a collection returned from a method to see if the user has appropriate ACLs on each object instance in the collection. Items in collection to which the current user does not have access to are automatically removed from the list. (AFTER_ACL_COLLECTION_READ)
e.g. method signature:
1:public List getAllReports(){
2: return Report.list()
3:}
4:
You can check the domain object returned from a method invocation to see if the current user as an appropriate ACL granting permission to that domain object. (AFTER_ACL_READ)
e.g. method signature:
1:public Report getReport(Integer id){
2: return Report.get(id)
3:}
4:
Protecting a Service Class
Let us now look at a service class which has ACL protection turned on:
1:class ReportService{
2:
3: static acegiACL = {
4: Report{
5: getReportLog(['ROLE_USER', 'ROLE_ADMIN'])
6: getAllReports(['ROLE_USER', 'AFTER_ACL_COLLECTION_READ'])
7: getReport(['ROLE_USER', 'AFTER_ACL_READ'])
8: saveReport(['ACL_REPORT_WRITE']) //CURRENTLY UNSUPPORTED!
9: }
10: }
11:
12: boolean transactional = true
13:
14: def getReport(Integer reportId) {
15: return Report.get( reportId )
16: }
17:
18: def getAllReports(){
19: return Report.list()
20: }
21:
22: def getReportLog(Integer reportId){
23: return Report.get(reportId).log
24: }
25:
26: def saveReport(Report report){
27: report.save()
28: }
29:
30:}
NOTE: The 'acegiACL' closure is not currently supported on domain objects.
The 'acegiACL' closure can be explained as follows:
- line 3 - "Report {... "
- refers to the domain object we are protecting. This name is used when applying ACL controls for AFTER_ACL_READ and AFTER_ACL_COLLECTION_READ.
- line 5 - getReportLog(['ROLE_USER', 'ROLE_ADMIN'])
- Only allow users in the ROLE_USER and ROLE_ADMIN roles to call the getReportLog() method
- line 6 - getAllReports(['ROLE_USER', 'AFTER_ACL_COLLECTION_READ'])
- Only allow users in the ROLE_USER role to call the getAllReports() method.
- Additionally filter all returned results checking that user has READ permission on the domain objects.
- line 7 - getReport(['ROLE_USER', 'AFTER_ACL_READ'])
- Only allow users in the ROLE_USER role to call this method.
- Additionally check the returned domain instance to see if the current user has the READ permission on the object.
- line 8 - saveReport(['ACL_REPORT_WRITE']) - (UNSUPPORTED!)
- Check the custom permission to verify that the current user has WRITE permission on domain object instance passed into the method.
- Allow fine-grained ACLs of the type ACL_REPORT_SAVE, by automatically creating instances of AclEntryVoter
- Create a mechanism allowing users to easily hook up their own custom instances of AbstractAclVoter into the ACL mechanism
Resources:
- Acegi Security - http://www.acegisecurity.org/
- Download example application demonstrating ACL integration here.
- Download development version of Grails Acegi Plugin with ACL here.
Update: [7May2008] - This plugin download is NOT the same as the 0.3 version of the plugin available for download from grails.codehaus.org!
12 comments:
Thank you for all your efforts and nice tutorial.
I guess I am missing something though, I am getting the following error:
[17031] errors.GrailsExceptionResolver groovy.lang.MissingPropertyException: No such property: AclObjectIdentity for class: LookupStrategyService
org.codehaus.groovy.runtime.InvokerInvocationException: groovy.lang.MissingPropertyException: No such property: AclObjectIdentity for class: LookupStrategyService
Is there something else I need to do like changing some additional configuration files, etc.? When I check the database created, I do not see any table other than the regular requestmap and roles acegi plugin creates. How does acegi store access control lists?
Kind Regards,
Umut
@Umut:
You will have to run the command:
>grails CreateAclDomains
Please refer to the example application download for more details.
Cheers
Stephan
Hi I get errors on my app and I am not able to run the script provided: grails create-acld-omains, neither CreateAclDomains. Grails says that both are not found. Can you please post the link to the newest one you have?
would you be adding annotation based ACL checks? I've never worked on Acegi/Springs security so I'm not sure if its already there. Wouldn't it be more easier to maintain.
kani: There is already experimental support for the annotations-based approach. Have a look at the Acegi plugin documentation at grails.codehaus.org
Personally I don't like the annotations-based approach, hence my "ACLBuilder" which I feel is more "Groovy" and also makes configuration easier. But this is my humble opinion. Nothing prevents us from providing both approaches.
Stephan
@ramon: Please note that my changes are not in the official plugin yet, so you'll have to download the version linked to in the blog.
Stephan
Hi Stephan. Thanks for the post. This is exactly the info I was looking for. Do you know when your changes are likely to be included in a released version of the plugin? Also, I'm particularly interested in applying ACLs to method parameters. Any idea how long it'll be before that will be supported? I'd offer to help, but I'm just getting to know Spring Security and I haven't done any work on a Grails plugin.
This looks great! Any chance of getting this as a diff or patch against the latest published acegi plugin for grails?
Has ACL been added to the plugin (current version 0.5.1)?
@James May: No, it's on my to-do list and most likely when it happens the version for the plugin will be bumped to 0.6
Stephan, this is exactly what I need for a project I'm finishing now!
Sorry to have to ask this question, but when do you think it will be ready for a public release?
Post a Comment