SEC-1023: PermissionEvaluator based on the Acl module.
This commit is contained in:
parent
a207acf7cb
commit
1c3b576d91
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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"));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue