1
0
mirror of synced 2026-08-05 17:57:15 +00:00

SEC-1015: Removed acl package from core and also related taglib declaration and implementation class (AclTag).

This commit is contained in:
Luke Taylor
2008-11-11 09:21:51 +00:00
parent e5b1073501
commit 0ba690fb0e
48 changed files with 56 additions and 7097 deletions
@@ -1,214 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.taglibs.authz;
import org.springframework.security.Authentication;
import org.springframework.security.acl.AclEntry;
import org.springframework.security.acl.AclManager;
import org.springframework.security.acl.basic.BasicAclEntry;
import org.springframework.security.context.SecurityContextHolder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.util.ExpressionEvaluationUtils;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
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;
/**
* An implementation of {@link javax.servlet.jsp.tagext.Tag} that allows its body through if some authorizations
* are granted to the request's principal.
* <p>
* Only works with permissions that are subclasses of {@link org.springframework.security.acl.basic.BasicAclEntry}.
* <p>
* One or more comma separate integer permissions are specified via the <code>hasPermission</code> attribute.
* The tag will include its body if <b>any</b> of the integer permissions have been granted to the current
* <code>Authentication</code> (obtained from the <code>SecurityContextHolder</code>).
* <p>
* For this class to operate it must be able to access the application context via the
* <code>WebApplicationContextUtils</code> and locate an {@link AclManager}. Application contexts have no need to have
* more than one <code>AclManager</code> (as a provider-based implementation can be used so that it locates a provider
* that is authoritative for the given domain object instance), so the first <code>AclManager</code> located will be
* used.
*
* @author Ben Alex
* @version $Id$
*/
public class AclTag extends TagSupport {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(AclTag.class);
//~ Instance fields ================================================================================================
private Object domainObject;
private String hasPermission = "";
//~ Methods ========================================================================================================
public int doStartTag() throws JspException {
if ((null == hasPermission) || "".equals(hasPermission)) {
return Tag.SKIP_BODY;
}
final String evaledPermissionsString = ExpressionEvaluationUtils.evaluateString("hasPermission", hasPermission,
pageContext);
Integer[] requiredIntegers = null;
try {
requiredIntegers = parseIntegersString(evaledPermissionsString);
} catch (NumberFormatException nfe) {
throw new JspException(nfe);
}
Object resolvedDomainObject = null;
if (domainObject instanceof String) {
resolvedDomainObject = ExpressionEvaluationUtils.evaluate("domainObject", (String) domainObject,
Object.class, pageContext);
} else {
resolvedDomainObject = domainObject;
}
if (resolvedDomainObject == null) {
if (logger.isDebugEnabled()) {
logger.debug("domainObject resolved to null, so including tag body");
}
// Of course they have access to a null object!
return Tag.EVAL_BODY_INCLUDE;
}
if (SecurityContextHolder.getContext().getAuthentication() == null) {
if (logger.isDebugEnabled()) {
logger.debug(
"SecurityContextHolder did not return a non-null Authentication object, so skipping tag body");
}
return Tag.SKIP_BODY;
}
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
ApplicationContext context = getContext(pageContext);
String[] beans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, AclManager.class, false, false);
if (beans.length == 0) {
throw new JspException("No AclManager would found the application context: " + context.toString());
}
AclManager aclManager = (AclManager) context.getBean(beans[0]);
// Obtain aclEntrys applying to the current Authentication object
AclEntry[] acls = aclManager.getAcls(resolvedDomainObject, auth);
if (logger.isDebugEnabled()) {
logger.debug("Authentication: '" + auth + "' has: " + ((acls == null) ? 0 : acls.length)
+ " AclEntrys for domain object: '" + resolvedDomainObject + "' from AclManager: '"
+ aclManager.toString() + "'");
}
if ((acls == null) || (acls.length == 0)) {
return Tag.SKIP_BODY;
}
for (int i = 0; i < acls.length; i++) {
// Locate processable AclEntrys
if (acls[i] instanceof BasicAclEntry) {
BasicAclEntry processableAcl = (BasicAclEntry) acls[i];
// See if principal has any of the required permissions
for (int y = 0; y < requiredIntegers.length; y++) {
if (processableAcl.isPermitted(requiredIntegers[y].intValue())) {
if (logger.isDebugEnabled()) {
logger.debug("Including tag body as found permission: " + requiredIntegers[y]
+ " due to AclEntry: '" + processableAcl + "'");
}
return Tag.EVAL_BODY_INCLUDE;
}
}
}
}
if (logger.isDebugEnabled()) {
logger.debug("No permission, so skipping tag body");
}
return Tag.SKIP_BODY;
}
/**
* Allows test cases to override where application context obtained from.
*
* @param pageContext so the <code>ServletContext</code> can be accessed as required by Spring's
* <code>WebApplicationContextUtils</code>
*
* @return the Spring application context (never <code>null</code>)
*/
protected ApplicationContext getContext(PageContext pageContext) {
ServletContext servletContext = pageContext.getServletContext();
return WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
}
public Object getDomainObject() {
return domainObject;
}
public String getHasPermission() {
return hasPermission;
}
private Integer[] parseIntegersString(String integersString)
throws NumberFormatException {
final Set integers = new HashSet();
final StringTokenizer tokenizer;
tokenizer = new StringTokenizer(integersString, ",", false);
while (tokenizer.hasMoreTokens()) {
String integer = tokenizer.nextToken();
integers.add(new Integer(integer));
}
return (Integer[]) integers.toArray(new Integer[] {});
}
public void setDomainObject(Object domainObject) {
this.domainObject = domainObject;
}
public void setHasPermission(String hasPermission) {
this.hasPermission = hasPermission;
}
}
@@ -17,7 +17,6 @@ package org.springframework.security.taglibs.velocity;
import org.springframework.security.Authentication;
import org.springframework.security.taglibs.authz.AclTag;
import org.springframework.security.taglibs.authz.AuthenticationTag;
import org.springframework.security.taglibs.authz.AuthorizeTag;
@@ -3,53 +3,53 @@
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>security</short-name>
<uri>http://www.springframework.org/security/tags</uri>
<description>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>security</short-name>
<uri>http://www.springframework.org/security/tags</uri>
<description>
Spring Security Authorization Tag Library
$Id$
</description>
$Id$
</description>
<tag>
<name>authorize</name>
<tag-class>org.springframework.security.taglibs.authz.AuthorizeTag</tag-class>
<description>
<tag>
<name>authorize</name>
<tag-class>org.springframework.security.taglibs.authz.AuthorizeTag</tag-class>
<description>
A simple tag to output or not the body of the tag if the principal
has or doesn't have certain authorities.
</description>
</description>
<attribute>
<name>ifNotGranted</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<description>
<attribute>
<name>ifNotGranted</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<description>
A comma separated list of roles which the user must not have
for the body to be output.
</description>
</attribute>
</description>
</attribute>
<attribute>
<name>ifAllGranted</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<description>
<attribute>
<name>ifAllGranted</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<description>
A comma separated list of roles which the user must all
possess for the body to be output.
</description>
</attribute>
</description>
</attribute>
<attribute>
<name>ifAnyGranted</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<description>
<attribute>
<name>ifAnyGranted</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<description>
A comma separated list of roles, one of which the user must
possess for the body to be output.
</description>
</attribute>
</tag>
</description>
</attribute>
</tag>
<tag>
<name>authentication</name>
@@ -88,66 +88,34 @@
</attribute>
</tag>
<tag>
<name>acl</name>
<tag-class>org.springframework.security.taglibs.authz.AclTag</tag-class>
<description>
<tag>
<name>accesscontrollist</name>
<tag-class>org.springframework.security.taglibs.authz.AccessControlListTag</tag-class>
<description>
Allows inclusion of a tag body if the current Authentication
has one of the specified permissions to the presented
domain object instance. This tag uses the first AclManager
it locates via
WebApplicationContextUtils.getRequiredWebApplicationContext(HttpServletContext).
</description>
has one of the specified permissions to the presented
domain object instance.
</description>
<attribute>
<name>hasPermission</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>
<attribute>
<name>hasPermission</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>
A comma separated list of integers, each representing a
required bit mask permission from a subclass of
required bit mask permission from a subclass of
org.springframework.security.acl.basic.AbstractBasicAclEntry.
</description>
</attribute>
<attribute>
<name>domainObject</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>
</attribute>
<attribute>
<name>domainObject</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>
The actual domain object instance for which permissions
are being evaluated.
</description>
</attribute>
</tag>
<tag>
<name>accesscontrollist</name>
<tag-class>org.springframework.security.taglibs.authz.AccessControlListTag</tag-class>
<description>
Allows inclusion of a tag body if the current Authentication
has one of the specified permissions to the presented
domain object instance.
</description>
<attribute>
<name>hasPermission</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>
A comma separated list of integers, each representing a
required bit mask permission from a subclass of
org.springframework.security.acl.basic.AbstractBasicAclEntry.
are being evaluated.
</description>
</attribute>
<attribute>
<name>domainObject</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<description>
The actual domain object instance for which permissions
are being evaluated.
</description>
</attribute>
</tag>
</attribute>
</tag>
</taglib>
@@ -1,179 +0,0 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.taglibs.authz;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.Tag;
import junit.framework.TestCase;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.security.Authentication;
import org.springframework.security.acl.AclEntry;
import org.springframework.security.acl.AclManager;
import org.springframework.security.acl.basic.AclObjectIdentity;
import org.springframework.security.acl.basic.SimpleAclEntry;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.providers.TestingAuthenticationToken;
import org.springframework.security.util.AuthorityUtils;
/**
* Tests {@link AclTag}.
*
* @author Ben Alex
* @version $Id$
*/
public class AclTagTests extends TestCase {
//~ Instance fields ================================================================================================
private final MyAclTag aclTag = new MyAclTag();
//~ Methods ========================================================================================================
protected void tearDown() throws Exception {
SecurityContextHolder.clearContext();
}
public void testInclusionDeniedWhenAclManagerUnawareOfObject() throws JspException {
Authentication auth = new TestingAuthenticationToken("rod", "koala", AuthorityUtils.NO_AUTHORITIES );
SecurityContextHolder.getContext().setAuthentication(auth);
aclTag.setHasPermission(new Long(SimpleAclEntry.ADMINISTRATION).toString());
aclTag.setDomainObject(new Integer(54));
assertEquals(Tag.SKIP_BODY, aclTag.doStartTag());
}
public void testInclusionDeniedWhenNoListOfPermissionsGiven() throws JspException {
Authentication auth = new TestingAuthenticationToken("rod", "koala", AuthorityUtils.NO_AUTHORITIES );
SecurityContextHolder.getContext().setAuthentication(auth);
aclTag.setHasPermission(null);
aclTag.setDomainObject("object1");
assertEquals(Tag.SKIP_BODY, aclTag.doStartTag());
}
public void testInclusionDeniedWhenPrincipalDoesNotHoldAnyPermissions() throws JspException {
Authentication auth = new TestingAuthenticationToken("john", "crow", AuthorityUtils.NO_AUTHORITIES );
SecurityContextHolder.getContext().setAuthentication(auth);
aclTag.setHasPermission(new Integer(SimpleAclEntry.ADMINISTRATION) + "," + new Integer(SimpleAclEntry.READ));
assertEquals(new Integer(SimpleAclEntry.ADMINISTRATION) + "," + new Integer(SimpleAclEntry.READ),
aclTag.getHasPermission());
aclTag.setDomainObject("object1");
assertEquals("object1", aclTag.getDomainObject());
assertEquals(Tag.SKIP_BODY, aclTag.doStartTag());
}
public void testInclusionDeniedWhenPrincipalDoesNotHoldRequiredPermissions() throws JspException {
Authentication auth = new TestingAuthenticationToken("rod", "koala", AuthorityUtils.NO_AUTHORITIES );
SecurityContextHolder.getContext().setAuthentication(auth);
aclTag.setHasPermission(new Integer(SimpleAclEntry.DELETE).toString());
aclTag.setDomainObject("object1");
assertEquals(Tag.SKIP_BODY, aclTag.doStartTag());
}
public void testInclusionDeniedWhenSecurityContextEmpty() throws JspException {
SecurityContextHolder.getContext().setAuthentication(null);
aclTag.setHasPermission(new Long(SimpleAclEntry.ADMINISTRATION).toString());
aclTag.setDomainObject("object1");
assertEquals(Tag.SKIP_BODY, aclTag.doStartTag());
}
public void testInclusionPermittedWhenDomainObjectIsNull() throws JspException {
aclTag.setHasPermission(new Integer(SimpleAclEntry.READ).toString());
aclTag.setDomainObject(null);
assertEquals(Tag.EVAL_BODY_INCLUDE, aclTag.doStartTag());
}
public void testJspExceptionThrownIfHasPermissionNotValidFormat() throws JspException {
Authentication auth = new TestingAuthenticationToken("john", "crow", AuthorityUtils.NO_AUTHORITIES );
SecurityContextHolder.getContext().setAuthentication(auth);
aclTag.setHasPermission("0,5, 6"); // shouldn't be any space
try {
aclTag.doStartTag();
fail("Should have thrown JspException");
} catch (JspException expected) {
assertTrue(true);
}
}
public void testOperationWhenPrincipalHoldsPermissionOfMultipleList() throws JspException {
Authentication auth = new TestingAuthenticationToken("rod", "koala", AuthorityUtils.NO_AUTHORITIES );
SecurityContextHolder.getContext().setAuthentication(auth);
aclTag.setHasPermission(new Integer(SimpleAclEntry.ADMINISTRATION) + "," + new Integer(SimpleAclEntry.READ));
aclTag.setDomainObject("object1");
assertEquals(Tag.EVAL_BODY_INCLUDE, aclTag.doStartTag());
}
public void testOperationWhenPrincipalHoldsPermissionOfSingleList() throws JspException {
Authentication auth = new TestingAuthenticationToken("rod", "koala", AuthorityUtils.NO_AUTHORITIES );
SecurityContextHolder.getContext().setAuthentication(auth);
aclTag.setHasPermission(new Integer(SimpleAclEntry.READ).toString());
aclTag.setDomainObject("object1");
assertEquals(Tag.EVAL_BODY_INCLUDE, aclTag.doStartTag());
}
//~ Inner Classes ==================================================================================================
private class MockAclEntry implements AclEntry {
// just so AclTag iterates some different types of AclEntrys
}
private class MyAclTag extends AclTag {
protected ApplicationContext getContext(PageContext pageContext) {
StaticApplicationContext context = new StaticApplicationContext();
final AclEntry[] acls = new AclEntry[] {
new MockAclEntry(),
new SimpleAclEntry("rod", new MockAclObjectIdentity(), null, SimpleAclEntry.ADMINISTRATION),
new SimpleAclEntry("rod", new MockAclObjectIdentity(), null, SimpleAclEntry.READ)
};
// Create an AclManager
AclManager aclManager = new AclManager() {
String object = "object1";
String principal = "rod";
public AclEntry[] getAcls(Object domainInstance) {
return domainInstance.equals(object) ? acls : null;
}
public AclEntry[] getAcls(Object domainInstance, Authentication authentication) {
return domainInstance.equals(object) && authentication.getPrincipal().equals(principal) ? acls : null;
}
};
// Register the AclManager into our ApplicationContext
context.getBeanFactory().registerSingleton("aclManager", aclManager);
return context;
}
}
private static class MockAclObjectIdentity implements AclObjectIdentity {
}
}