I am using Spring Security with domain Level security (ACL).
I have two domains Company and Book.
class Company {
String name
hasMany = [books: Book]
}
class Book {
String title
belongsTo = [company: Company]
}
I read that an ACL can have a Parent where it inherits its permissions from.
In a service I would have a method like this to set permission for a new book card:
@PreAuthorize("hasRole('ROLE_ADMIN') or hasPermission(#book, admin)")
void addPermission(Book book, String username, Permission permission) {
aclUtilService.addPermission(book, username, permission)
}
This works fine and creates a permission for a new book instance. I also have an update method which checks the permission before the book can be updated.
@PreAuthorize("hasPermission(#book, write) or hasPermission(#book, admin)")
Book update(Book book, Map params = [:]) {
book.properties = params
book.save(flush:true)
return book
}
This works fine as long as the user has the permission for the book. But, I want to user the permission of the parent object (company) to be inherited to the book. When a user has permission to the company I want that it has also permission to all of the company's books.
I see in AclImp that there is a method setParent()
. This works if you do:
AclImpl acl = aclUtilService.readAcl(book)
acl.setParent(aclUtilService.readAcl(book.company))
aclService.updateAcl(acl)
Using the code above will set the parent for book in the database.
How do I use inheriting in Spring Security ACL?
You could do this instead of playing with the parent ACL:
@PreAuthorize("hasPermission(#book.company, write) or hasPermission(#book.company, admin)")
Book update(Book book, Map params = [:]) {
book.properties = params
book.save(flush:true)
return book
}
If you would rather inherit from the parent ACL, make sure the child's AclObjectIdentity
has entriesInheriting
set to true
, for example using the method createAcl
below:
void createAcl(Class clazz, Long id, String sid, AclObjectIdentity parent) {
clazz = ProxyUtils.unproxy(clazz)
AclClass aclClass = AclClass.findOrSaveByClassName(clazz.name)
AclSid ownerSid = AclSid.findOrSaveBySidAndPrincipal(sid, true)
AclObjectIdentity oid = findOrCreateObjectIdentity(aclClass, ownerSid, id, parent, true)
}
AclObjectIdentity findOrCreateObjectIdentity(AclClass aclClass, AclSid ownerSid, Long id, AclObjectIdentity parent, boolean entriesInheriting) {
assert aclClass, "aclClass is required"
assert null != id, "id is required"
AclObjectIdentity oid = AclObjectIdentity.findOrCreateByAclClassAndObjectId(aclClass, id)
if (null == oid.id) {
oid.entriesInheriting = entriesInheriting
oid.owner = ownerSid
oid.parent = parent
oid.save(flush: true, failOnError: true)
}
oid
}
If the ACL is inheriting @PreAuthorize("hasPermission(#child, read)")
will return true if current user has read on parent's ACL