We've encountered an unexpected lack of bitwise permission checking in spring security. We'd like to confirm if this is the expected behaviour and if so, what the history is and/or rationale for this.
We're using the grails plugin spring-security-acl-1.1.1 which uses spring-security-acl 3.0.7.RELEASE.
A distilled scenario of what we are trying involves an object with ACL such that aclUtilService.readAcl(obj) returns granting roles:
PrincipalSid[sampleuser]; permission: BasePermission[...........................A....=16]
GrantedAuthoritySid[ROLE_RWD]; permission: CumulativePermission[............................D.WR=11]
GrantedAuthoritySid[ROLE_RW]; permission: CumulativePermission[..............................WR=3]
GrantedAuthoritySid[ROLE_R]; permission: BasePermission[...............................R=1]
Subsequently we expect to check for a single permission like WRITE and have it return true. However it appears this is not supported. For example, for a user who has all of the roles defined on the object above, the execution of:
READ?: ${aclUtilService.hasPermission(springSecurityService.authentication, obj, BasePermission.READ)}
WRITE?: ${aclUtilService.hasPermission(springSecurityService.authentication, obj, BasePermission.WRITE)}
DELETE?: ${aclUtilService.hasPermission(springSecurityService.authentication, obj, BasePermission.DELETE)}
READ-WRITE?: ${aclUtilService.hasPermission(springSecurityService.authentication, obj, new BasePermission(BasePermission.READ.getMask() | BasePermission.WRITE.getMask()))}
Returns output:
READ?: true
WRITE?: false
DELETE?: false
READ-WRITE?: true
Whereas we would expect all of these to have returned true. Having looked at the source we can see the permission is ultimately checked in AclImpl, which contains the line
if ((ace.getPermission().getMask() == p.getMask()) && ace.getSid().equals(sid)) {
Which explains why only the exact masks are matching.
Changing only this line is somewhat involved and we have found that in spring-security-acl 3.1 this code was refactored to allow for a permission granting strategy to be defined- https://jira.spring.io/browse/SEC-1166
However the default granting strategy still only checks the exact mask. So:
Thanks for any explanation or guidance.
This surprised me a lot when I was creating the plugin. It seemed very odd to pretend to use bit masking, and in the end limit yourself to only 32 permissions (although that should be enough for most apps). See this JIRA for Ben Alex's explantation: https://jira.spring.io/browse/SEC-1140
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With