SEC-1560: Change AccessControlListTag to use PermissionEvaluator rather than explicit ACL classes.
This commit is contained in:
parent
3541099634
commit
ce19b470e2
|
@ -14,57 +14,33 @@
|
|||
*/
|
||||
package org.springframework.security.taglibs.authz;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.taglibs.TagLibConfig;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.springframework.web.util.ExpressionEvaluationUtils;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.jsp.JspException;
|
||||
import javax.servlet.jsp.PageContext;
|
||||
import javax.servlet.jsp.tagext.Tag;
|
||||
import javax.servlet.jsp.tagext.TagSupport;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.acls.domain.DefaultPermissionFactory;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
|
||||
import org.springframework.security.acls.domain.PermissionFactory;
|
||||
import org.springframework.security.acls.domain.SidRetrievalStrategyImpl;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AclService;
|
||||
import org.springframework.security.acls.model.NotFoundException;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.acls.model.SidRetrievalStrategy;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.taglibs.TagLibConfig;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.springframework.web.util.ExpressionEvaluationUtils;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of {@link Tag} that allows its body through if some authorizations are granted to the request's
|
||||
* principal.
|
||||
* <p>
|
||||
* One or more comma separate numeric are specified via the <tt>hasPermission</tt> attribute.
|
||||
* These permissions are then converted into {@link Permission} instances using the {@link PermissionFactory}
|
||||
* instance obtained from the application context, or a {@link DefaultPermissionFactory} if one isn't found.
|
||||
* The <tt>Permission</tt> instances are then presented as a list
|
||||
* array to the {@link Acl#isGranted(List, List, boolean)} method.
|
||||
* The {@link Sid} presented is determined by the {@link SidRetrievalStrategy}.
|
||||
* One or more comma separate numeric are specified via the {@code hasPermission} attribute. The tag delegates
|
||||
* to the configured {@link PermissionEvaluator} which it obtains from the {@code ApplicationContext}.
|
||||
* <p>
|
||||
* For this class to operate it must be able to access the application context via the
|
||||
* <code>WebApplicationContextUtils</code> and attempt to locate an {@link AclService},
|
||||
* {@link ObjectIdentityRetrievalStrategy} and {@link SidRetrievalStrategy}.
|
||||
* There cannot be more than one of these present. The <tt>AclService</tt> must be provided, but a
|
||||
* {@link SidRetrievalStrategyImpl} and/or an {@link ObjectIdentityRetrievalStrategyImpl} will be created if no
|
||||
* implementations are found in the application context.
|
||||
* {@code WebApplicationContextUtils} and attempt to locate the {@code PermissionEvaluator} instance.
|
||||
* There cannot be more than one of these present for the tag to function.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
|
@ -76,12 +52,9 @@ public class AccessControlListTag extends TagSupport {
|
|||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private AclService aclService;
|
||||
private ApplicationContext applicationContext;
|
||||
private Object domainObject;
|
||||
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy;
|
||||
private SidRetrievalStrategy sidRetrievalStrategy;
|
||||
private PermissionFactory permissionFactory;
|
||||
private PermissionEvaluator permissionEvaluator;
|
||||
private String hasPermission = "";
|
||||
private String var;
|
||||
|
||||
|
@ -97,8 +70,6 @@ public class AccessControlListTag extends TagSupport {
|
|||
final String evaledPermissionsString = ExpressionEvaluationUtils.evaluateString("hasPermission", hasPermission,
|
||||
pageContext);
|
||||
|
||||
List<Permission> requiredPermissions = parsePermissionsString(evaledPermissionsString);
|
||||
|
||||
Object resolvedDomainObject;
|
||||
|
||||
if (domainObject instanceof String) {
|
||||
|
@ -126,21 +97,12 @@ public class AccessControlListTag extends TagSupport {
|
|||
return skipBody();
|
||||
}
|
||||
|
||||
List<Sid> sids = sidRetrievalStrategy.getSids(SecurityContextHolder.getContext().getAuthentication());
|
||||
ObjectIdentity oid = objectIdentityRetrievalStrategy.getObjectIdentity(resolvedDomainObject);
|
||||
|
||||
// Obtain aclEntrys applying to the current Authentication object
|
||||
try {
|
||||
Acl acl = aclService.readAclById(oid, sids);
|
||||
|
||||
if (acl.isGranted(requiredPermissions, sids, false)) {
|
||||
return evalBody();
|
||||
} else {
|
||||
return skipBody();
|
||||
}
|
||||
} catch (NotFoundException nfe) {
|
||||
return skipBody();
|
||||
if (permissionEvaluator.hasPermission(SecurityContextHolder.getContext().getAuthentication(),
|
||||
resolvedDomainObject, evaledPermissionsString)) {
|
||||
return evalBody();
|
||||
}
|
||||
|
||||
return skipBody();
|
||||
}
|
||||
|
||||
private int skipBody() {
|
||||
|
@ -187,25 +149,7 @@ public class AccessControlListTag extends TagSupport {
|
|||
|
||||
this.applicationContext = getContext(pageContext);
|
||||
|
||||
aclService = getBeanOfType(AclService.class);
|
||||
|
||||
sidRetrievalStrategy = getBeanOfType(SidRetrievalStrategy.class);
|
||||
|
||||
if (sidRetrievalStrategy == null) {
|
||||
sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
}
|
||||
|
||||
objectIdentityRetrievalStrategy = getBeanOfType(ObjectIdentityRetrievalStrategy.class);
|
||||
|
||||
if (objectIdentityRetrievalStrategy == null) {
|
||||
objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||
}
|
||||
|
||||
permissionFactory = getBeanOfType(PermissionFactory.class);
|
||||
|
||||
if (permissionFactory == null) {
|
||||
permissionFactory = new DefaultPermissionFactory();
|
||||
}
|
||||
permissionEvaluator = getBeanOfType(PermissionEvaluator.class);
|
||||
}
|
||||
|
||||
private <T> T getBeanOfType(Class<T> type) throws JspException {
|
||||
|
@ -226,24 +170,6 @@ public class AccessControlListTag extends TagSupport {
|
|||
+ "application context - you must have only have one!");
|
||||
}
|
||||
|
||||
private List<Permission> parsePermissionsString(String permissionsString) throws NumberFormatException {
|
||||
final Set<Permission> permissions = new HashSet<Permission>();
|
||||
final StringTokenizer tokenizer;
|
||||
tokenizer = new StringTokenizer(permissionsString, ",", false);
|
||||
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
String permission = tokenizer.nextToken();
|
||||
try {
|
||||
permissions.add(permissionFactory.buildFromMask(Integer.valueOf(permission)));
|
||||
} catch (NumberFormatException nfe) {
|
||||
// Not an integer mask. Try using a name
|
||||
permissions.add(permissionFactory.buildFromName(permission));
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList<Permission>(permissions);
|
||||
}
|
||||
|
||||
public void setDomainObject(Object domainObject) {
|
||||
this.domainObject = domainObject;
|
||||
}
|
||||
|
|
|
@ -1,29 +1,22 @@
|
|||
package org.springframework.security.taglibs.authz;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.jsp.tagext.Tag;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.*;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockPageContext;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AclService;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import javax.servlet.jsp.tagext.Tag;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
|
@ -32,28 +25,21 @@ import org.springframework.web.context.WebApplicationContext;
|
|||
@SuppressWarnings("unchecked")
|
||||
public class AccessControlListTagTests {
|
||||
AccessControlListTag tag;
|
||||
Acl acl;
|
||||
PermissionEvaluator pe;
|
||||
MockPageContext pageContext;
|
||||
Authentication bob = new TestingAuthenticationToken("bob","bobspass","A");
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("bob","bobspass","A"));
|
||||
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||
tag = new AccessControlListTag();
|
||||
WebApplicationContext ctx = mock(WebApplicationContext.class);
|
||||
|
||||
AclService service = mock(AclService.class);
|
||||
ObjectIdentity oid = mock(ObjectIdentity.class);
|
||||
ObjectIdentityRetrievalStrategy oidStrategy = mock(ObjectIdentityRetrievalStrategy.class);
|
||||
when(oidStrategy.getObjectIdentity(anyObject())).thenReturn(oid);
|
||||
acl = mock(Acl.class);
|
||||
pe = mock(PermissionEvaluator.class);
|
||||
|
||||
when(service.readAclById(any(ObjectIdentity.class), anyList())).thenReturn(acl);
|
||||
Map beanMap = new HashMap();
|
||||
beanMap.put("service", service);
|
||||
when(ctx.getBeansOfType(AclService.class)).thenReturn(beanMap);
|
||||
beanMap = new HashMap();
|
||||
beanMap.put("oidStrategy", oidStrategy);
|
||||
when(ctx.getBeansOfType(ObjectIdentityRetrievalStrategy.class)).thenReturn(beanMap);
|
||||
beanMap.put("pe", pe);
|
||||
when(ctx.getBeansOfType(PermissionEvaluator.class)).thenReturn(beanMap);
|
||||
|
||||
MockServletContext servletCtx = new MockServletContext();
|
||||
servletCtx.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ctx);
|
||||
|
@ -68,11 +54,14 @@ public class AccessControlListTagTests {
|
|||
|
||||
@Test
|
||||
public void bodyIsEvaluatedIfAclGrantsAccess() throws Exception {
|
||||
when(acl.isGranted(anyList(), anyList(), eq(false))).thenReturn(true);
|
||||
Object domainObject = new Object();
|
||||
when(pe.hasPermission(bob, domainObject, "READ")).thenReturn(true);
|
||||
|
||||
tag.setDomainObject(new Object());
|
||||
tag.setDomainObject(domainObject);
|
||||
tag.setHasPermission("READ");
|
||||
tag.setVar("allowed");
|
||||
assertSame(domainObject, tag.getDomainObject());
|
||||
assertEquals("READ", tag.getHasPermission());
|
||||
|
||||
assertEquals(Tag.EVAL_BODY_INCLUDE, tag.doStartTag());
|
||||
assertTrue((Boolean)pageContext.getAttribute("allowed"));
|
||||
|
@ -80,14 +69,14 @@ public class AccessControlListTagTests {
|
|||
|
||||
@Test
|
||||
public void bodyIsSkippedIfAclDeniesAccess() throws Exception {
|
||||
when(acl.isGranted(anyList(), anyList(), eq(false))).thenReturn(false);
|
||||
Object domainObject = new Object();
|
||||
when(pe.hasPermission(bob, domainObject, "READ")).thenReturn(false);
|
||||
|
||||
tag.setDomainObject(new Object());
|
||||
tag.setDomainObject(domainObject);
|
||||
tag.setHasPermission("READ");
|
||||
tag.setVar("allowed");
|
||||
|
||||
assertEquals(Tag.SKIP_BODY, tag.doStartTag());
|
||||
assertFalse((Boolean)pageContext.getAttribute("allowed"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue