SEC-1023: PermissionEvaluator based on the Acl module.

This commit is contained in:
Luke Taylor 2008-11-05 03:45:50 +00:00
parent a207acf7cb
commit 1c3b576d91
2 changed files with 171 additions and 0 deletions

View File

@ -0,0 +1,115 @@
package org.springframework.security.acls;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.Authentication;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.objectidentity.ObjectIdentity;
import org.springframework.security.acls.objectidentity.ObjectIdentityRetrievalStrategy;
import org.springframework.security.acls.objectidentity.ObjectIdentityRetrievalStrategyImpl;
import org.springframework.security.acls.sid.Sid;
import org.springframework.security.acls.sid.SidRetrievalStrategy;
import org.springframework.security.acls.sid.SidRetrievalStrategyImpl;
import org.springframework.security.expression.PermissionEvaluator;
/**
* Used by Spring Security's expression-based access control implementation to evaluate permissions for a particular
* object using the ACL module. Similar in behaviour to
* {@link org.springframework.security.vote.AclEntryVoter AclEntryVoter}.
*
* @author Luke Taylor
* @version $Id$
* @since 2.5
*/
public class AclPermissionEvaluator implements PermissionEvaluator {
private final Log logger = LogFactory.getLog(getClass());
private AclService aclService;
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
public AclPermissionEvaluator(AclService aclService) {
this.aclService = aclService;
}
/**
* Determines whether the user has the given permission(s) on the domain object using the ACL
* configuration. If the domain object is null, returns false (this can always be overridden using a null
* check in the expression itself).
*/
public boolean hasPermission(Authentication authentication, Object domainObject, Object permission) {
if (domainObject == null) {
return false;
}
ObjectIdentity objectIdentity = objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
// Obtain the SIDs applicable to the principal
Sid[] sids = sidRetrievalStrategy.getSids(authentication);
Permission[] requiredPermission = resolvePermission(permission);
try {
// Lookup only ACLs for SIDs we're interested in
Acl acl = aclService.readAclById(objectIdentity, sids);
if (acl.isGranted(requiredPermission, sids, false)) {
if (logger.isDebugEnabled()) {
logger.debug("Access is granted");
}
return true;
}
if (logger.isDebugEnabled()) {
logger.debug("Returning false - ACLs returned, but insufficient permissions for this principal");
}
} catch (NotFoundException nfe) {
if (logger.isDebugEnabled()) {
logger.debug("Returning false - no ACLs apply for this principal");
}
}
return false;
}
// TODO: Add permission resolver/PermissionFactory rewrite
Permission[] resolvePermission(Object permission) {
if (permission instanceof Integer) {
return new Permission[] {BasePermission.buildFromMask(((Integer)permission).intValue())};
}
if (permission instanceof Permission) {
return new Permission[] {(Permission)permission};
}
if (permission instanceof Permission[]) {
return (Permission[]) permission;
}
if (permission instanceof String) {
String permString = (String)permission;
Permission p = BasePermission.buildFromName(permString);
if (p == null) {
p = BasePermission.buildFromName(permString.toUpperCase());
}
if (p != null) {
return new Permission[] {p};
}
}
throw new IllegalArgumentException("unsupported permission: " + permission);
}
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
}

View File

@ -0,0 +1,56 @@
package org.springframework.security.acls;
import static org.junit.Assert.*;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.junit.Before;
import org.junit.Test;
import org.springframework.security.Authentication;
import org.springframework.security.acls.objectidentity.ObjectIdentity;
import org.springframework.security.acls.objectidentity.ObjectIdentityRetrievalStrategy;
import org.springframework.security.acls.sid.Sid;
import org.springframework.security.acls.sid.SidRetrievalStrategy;
/**
*
* @author Luke Taylor
* @version $Id$
* @since 2.5
*/
public class AclPermissionEvaluatorTests {
Mockery jmock = new JUnit4Mockery();
Authentication user;
private AclService service;
private ObjectIdentityRetrievalStrategy oidStrategy;
private SidRetrievalStrategy sidStrategy;
@Before
public void setup() throws Exception {
user = jmock.mock(Authentication.class);
service = jmock.mock(AclService.class);
oidStrategy = jmock.mock(ObjectIdentityRetrievalStrategy.class);
sidStrategy = jmock.mock(SidRetrievalStrategy.class);
}
@Test
public void hasPermissionReturnsTrueIfAclGrantsPermission() throws Exception {
AclPermissionEvaluator pe = new AclPermissionEvaluator(service);
final Acl acl = jmock.mock(Acl.class);
pe.setObjectIdentityRetrievalStrategy(oidStrategy);
pe.setSidRetrievalStrategy(sidStrategy);
jmock.checking(new Expectations() {{
ignoring(user);
ignoring(oidStrategy);
ignoring(sidStrategy);
oneOf(service).readAclById(with(any(ObjectIdentity.class)), with(any(Sid[].class)));
will(returnValue(acl));
oneOf(acl).isGranted(with(any(Permission[].class)), with(any(Sid[].class)), with(equal(false)));
will(returnValue(true));
}});
assertTrue(pe.hasPermission(user, new Object(), "read"));
}
}