Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 23bdc7d766 | |||
| d07d97838a | |||
| f5fc94e1be | |||
| a4f13a9ae0 | |||
| 5c308c0215 | |||
| a0f91b2dd2 | |||
| 6cf44b9de0 | |||
| 55e501711d | |||
| d5e6f0b575 | |||
| 76dc21469e | |||
| 22b7c9b905 | |||
| 0cdf202b10 | |||
| a507e3612a | |||
| f5fbda42e5 | |||
| d5b72275e5 | |||
| 08a933f930 | |||
| 54ffc98bb4 | |||
| 1c3d530b60 | |||
| beb0ec4ba9 | |||
| dec2e59fba | |||
| ed7f589998 | |||
| 8f6ddb0f17 | |||
| 62a8aca853 | |||
| 9c6a5135a3 | |||
| 0acf262546 | |||
| 6ad652ae97 | |||
| 068b3d48ec | |||
| d6f6a54455 | |||
| 4361211c21 | |||
| 71adc26b0f | |||
| eb3288ca34 | |||
| f3f4cfe804 | |||
| 40fa884860 | |||
| 3e393c9df6 | |||
| a61aca1abf | |||
| 52d2c904f9 | |||
| 149fd5d8de | |||
| f3f02d8aed | |||
| 781c99f257 | |||
| b77f780993 | |||
| 22964837e9 | |||
| 7566802a08 | |||
| 4c3867718e |
@@ -0,0 +1,7 @@
|
||||
dist
|
||||
target
|
||||
build.properties
|
||||
*.log
|
||||
.clover
|
||||
*.keystore
|
||||
server-work
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
target
|
||||
.gradle
|
||||
build/
|
||||
.idea
|
||||
out/
|
||||
*.ipr
|
||||
*.iml
|
||||
*.iws
|
||||
*.log
|
||||
intellij/
|
||||
.settings
|
||||
.classpath
|
||||
.project
|
||||
.DS_Store
|
||||
atlassian-ide-plugin.xml
|
||||
@@ -0,0 +1,205 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
/*
|
||||
* Copyright 2001-2004 The Apache Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Puppy Crawl//DTD Check Configuration 1.2//EN"
|
||||
"http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
|
||||
|
||||
<!--
|
||||
|
||||
Checkstyle is very configurable. Be sure to read the documentation at
|
||||
http://checkstyle.sf.net (or in your downloaded distribution).
|
||||
|
||||
Most Checks are configurable, be sure to consult the documentation.
|
||||
|
||||
To completely disable a check, just comment it out or delete it from the file.
|
||||
|
||||
Finally, it is worth reading the documentation.
|
||||
|
||||
-->
|
||||
|
||||
<module name="Checker">
|
||||
|
||||
<!-- Checks that a package.html file exists for each package. -->
|
||||
<!-- See http://checkstyle.sf.net/config_javadoc.html#PackageHtml -->
|
||||
<!-- module name="PackageHtml"/ -->
|
||||
|
||||
<!-- Checks whether files end with a new line. -->
|
||||
<!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile -->
|
||||
<module name="NewlineAtEndOfFile"/>
|
||||
|
||||
<!-- Checks that property files contain the same keys. -->
|
||||
<!-- See http://checkstyle.sf.net/config_misc.html#Translation -->
|
||||
<module name="Translation"/>
|
||||
|
||||
|
||||
<module name="TreeWalker">
|
||||
|
||||
<property name="cacheFile" value="${checkstyle.cache.file}"/>
|
||||
|
||||
<!-- Checks for Javadoc comments. -->
|
||||
<!-- See http://checkstyle.sf.net/config_javadoc.html -->
|
||||
<!--
|
||||
<module name="JavadocMethod"/>
|
||||
<module name="JavadocType"/>
|
||||
<module name="JavadocVariable"/>
|
||||
<module name="JavadocStyle"/>
|
||||
-->
|
||||
|
||||
<!-- Checks for Naming Conventions. -->
|
||||
<!-- See http://checkstyle.sf.net/config_naming.html -->
|
||||
<module name="ConstantName">
|
||||
<!-- logger variables break normal constant syntax. We need to allow lower case too -->
|
||||
<property name="format" value="^[a-zA-Z][a-zA-Z0-9]*(_[A-Z0-9]+)*$"/>
|
||||
</module>
|
||||
<module name="LocalFinalVariableName"/>
|
||||
<module name="LocalVariableName"/>
|
||||
<module name="MemberName"/>
|
||||
<module name="MethodName"/>
|
||||
<module name="PackageName"/>
|
||||
<module name="ParameterName"/>
|
||||
<module name="StaticVariableName"/>
|
||||
<module name="TypeName"/>
|
||||
|
||||
|
||||
<!-- Checks for Headers -->
|
||||
<!-- See http://checkstyle.sf.net/config_header.html -->
|
||||
<!-- <module name="Header"> -->
|
||||
<!-- The follow property value demonstrates the ability -->
|
||||
<!-- to have access to ANT properties. In this case it uses -->
|
||||
<!-- the ${basedir} property to allow Checkstyle to be run -->
|
||||
<!-- from any directory within a project. See property -->
|
||||
<!-- expansion, -->
|
||||
<!-- http://checkstyle.sf.net/config.html#properties -->
|
||||
<!-- <property -->
|
||||
<!-- name="headerFile" -->
|
||||
<!-- value="${basedir}/java.header"/> -->
|
||||
<!-- </module> -->
|
||||
|
||||
<!-- Following interprets the header file as regular expressions. -->
|
||||
<!-- <module name="RegexpHeader"/> -->
|
||||
|
||||
|
||||
<!-- Checks for imports -->
|
||||
<!-- See http://checkstyle.sf.net/config_imports.html -->
|
||||
<module name="AvoidStarImport">
|
||||
<property name="excludes" value="javax.servlet,java.util"/>
|
||||
</module>
|
||||
<module name="IllegalImport"/> <!-- defaults to sun.* packages -->
|
||||
<module name="RedundantImport"/>
|
||||
<!--module name="UnusedImports"/ -->
|
||||
|
||||
|
||||
<!-- Checks for Size Violations. -->
|
||||
<!-- See http://checkstyle.sf.net/config_sizes.html -->
|
||||
<module name="FileLength"/>
|
||||
<module name="LineLength">
|
||||
<property name="max" value="125"/>
|
||||
</module>
|
||||
<module name="MethodLength"/>
|
||||
<module name="ParameterNumber"/>
|
||||
|
||||
|
||||
<!-- Checks for whitespace -->
|
||||
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
|
||||
<module name="EmptyForIteratorPad"/>
|
||||
<module name="MethodParamPad"/>
|
||||
<module name="NoWhitespaceAfter"/>
|
||||
<module name="NoWhitespaceBefore"/>
|
||||
<module name="OperatorWrap"/>
|
||||
<module name="ParenPad"/>
|
||||
<module name="TypecastParenPad"/>
|
||||
<module name="TabCharacter"/>
|
||||
<module name="WhitespaceAfter"/>
|
||||
<!--
|
||||
<module name="WhitespaceAround">
|
||||
<property name="allowEmptyMethods" value="true"/>
|
||||
<property name="allowEmptyConstructors" value="true"/>
|
||||
</module>
|
||||
-->
|
||||
|
||||
<!-- Modifier Checks -->
|
||||
<!-- See http://checkstyle.sf.net/config_modifiers.html -->
|
||||
<module name="ModifierOrder"/>
|
||||
<module name="RedundantModifier"/>
|
||||
|
||||
|
||||
<!-- Checks for blocks. You know, those {}'s -->
|
||||
<!-- See http://checkstyle.sf.net/config_blocks.html -->
|
||||
<module name="AvoidNestedBlocks"/>
|
||||
<!-- module name="EmptyBlock"/ -->
|
||||
<module name="LeftCurly"/>
|
||||
<module name="NeedBraces"/>
|
||||
<module name="RightCurly"/>
|
||||
|
||||
|
||||
<!-- Checks for common coding problems -->
|
||||
<!-- See http://checkstyle.sf.net/config_coding.html -->
|
||||
<!-- module name="AvoidInlineConditionals"/ -->
|
||||
<module name="DoubleCheckedLocking"/> <!-- MY FAVOURITE -->
|
||||
<module name="EmptyStatement"/>
|
||||
<!-- module name="EqualsHashCode"/ -->
|
||||
<!--
|
||||
<module name="HiddenField">
|
||||
<property name="ignoreConstructorParameter" value="true"/>
|
||||
<property name="ignoreSetter" value="true"/>
|
||||
</module>
|
||||
-->
|
||||
<module name="IllegalInstantiation"/>
|
||||
<module name="InnerAssignment"/>
|
||||
<!-- module name="MagicNumber"/ -->
|
||||
<module name="MissingSwitchDefault"/>
|
||||
<!--
|
||||
<module name="RedundantThrows">
|
||||
<property name="allowUnchecked" value="true"/>
|
||||
</module>
|
||||
-->
|
||||
<!--
|
||||
<module name="SimplifyBooleanExpression"/>
|
||||
<module name="SimplifyBooleanReturn"/>
|
||||
-->
|
||||
<!-- Checks for class design -->
|
||||
<!-- See http://checkstyle.sf.net/config_design.html -->
|
||||
<!-- module name="DesignForExtension"/ -->
|
||||
<module name="FinalClass"/>
|
||||
<module name="HideUtilityClassConstructor"/>
|
||||
<module name="InterfaceIsType"/>
|
||||
<module name="VisibilityModifier">
|
||||
<!-- logger variables are often protected -->
|
||||
<property name="protectedAllowed" value="true"/>
|
||||
</module>
|
||||
|
||||
|
||||
<!-- Miscellaneous other checks. -->
|
||||
<!-- See http://checkstyle.sf.net/config_misc.html -->
|
||||
<module name="ArrayTypeStyle"/>
|
||||
<!-- module name="FinalParameters"/ -->
|
||||
<!--
|
||||
<module name="GenericIllegalRegexp">
|
||||
<property name="format" value="\s+$"/>
|
||||
<property name="message" value="Line has trailing spaces."/>
|
||||
</module>
|
||||
-->
|
||||
<!-- module name="TrailingComment"/ -->
|
||||
<!-- module name="TodoComment"/ -->
|
||||
<module name="UpperEll"/>
|
||||
|
||||
</module>
|
||||
|
||||
</module>
|
||||
+11
-15
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>spring-security-parent</artifactId>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<version>3.0.0.RC1</version>
|
||||
<version>2.0.8.RELEASE</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
@@ -25,8 +25,11 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>tests</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
@@ -34,7 +37,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<artifactId>spring-mock</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -47,15 +50,8 @@
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>8.3-603.jdbc3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<!--
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
@@ -63,6 +59,6 @@
|
||||
<artifactId>com.springsource.bundlor.maven</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
</build>
|
||||
-->
|
||||
</project>
|
||||
+2
-1
@@ -12,8 +12,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.model;
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
+11
-10
@@ -12,11 +12,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.model;
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
@@ -27,13 +28,13 @@ import java.util.List;
|
||||
* order to avoid needing references to the domain object itself, this
|
||||
* interface handles indirection between a domain object and an ACL object
|
||||
* identity via the {@link
|
||||
* org.springframework.security.acls.model.ObjectIdentity} interface.
|
||||
* org.springframework.security.acls.objectidentity.ObjectIdentity} interface.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Implementing classes may elect to return instances that represent
|
||||
* {@link org.springframework.security.acls.model.Permission} information for either
|
||||
* some OR all {@link org.springframework.security.acls.model.Sid}
|
||||
* {@link org.springframework.security.acls.Permission} information for either
|
||||
* some OR all {@link org.springframework.security.acls.sid.Sid}
|
||||
* instances. Therefore, an instance may NOT necessarily contain ALL <tt>Sid</tt>s
|
||||
* for a given domain object.
|
||||
* </p>
|
||||
@@ -43,7 +44,7 @@ import java.util.List;
|
||||
*/
|
||||
public interface Acl extends Serializable {
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns all of the entries represented by the present <tt>Acl</tt>. Entries associated with
|
||||
* the <tt>Acl</tt> parents are not returned.
|
||||
*
|
||||
@@ -54,7 +55,7 @@ public interface Acl extends Serializable {
|
||||
* part of advanced permission checking.</p>
|
||||
*
|
||||
* <p>Do <em>NOT</em> use this method for making authorization decisions. Instead use {@link
|
||||
* #isGranted(List, List, boolean)}.</p>
|
||||
* #isGranted(Permission[], Sid[], boolean)}.</p>
|
||||
*
|
||||
* <p>This method must operate correctly even if the <tt>Acl</tt> only represents a subset of
|
||||
* <tt>Sid</tt>s. The caller is responsible for correctly handling the result if only a subset of
|
||||
@@ -63,7 +64,7 @@ public interface Acl extends Serializable {
|
||||
* @return the list of entries represented by the <tt>Acl</tt>, or <tt>null</tt> if there are
|
||||
* no entries presently associated with this <tt>Acl</tt>.
|
||||
*/
|
||||
List<AccessControlEntry> getEntries();
|
||||
AccessControlEntry[] getEntries();
|
||||
|
||||
/**
|
||||
* Obtains the domain object this <tt>Acl</tt> provides entries for. This is immutable once an
|
||||
@@ -145,7 +146,7 @@ public interface Acl extends Serializable {
|
||||
* @throws UnloadedSidException thrown if the <tt>Acl</tt> does not have details for one or more of the
|
||||
* <tt>Sid</tt>s passed as arguments
|
||||
*/
|
||||
boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
|
||||
boolean isGranted(Permission[] permission, Sid[] sids, boolean administrativeMode)
|
||||
throws NotFoundException, UnloadedSidException;
|
||||
|
||||
/**
|
||||
@@ -165,5 +166,5 @@ public interface Acl extends Serializable {
|
||||
*
|
||||
* @return <tt>true</tt> if every passed <tt>Sid</tt> is represented by this <tt>Acl</tt> instance
|
||||
*/
|
||||
boolean isSidLoaded(List<Sid> sids);
|
||||
boolean isSidLoaded(Sid[] sids);
|
||||
}
|
||||
+10
-13
@@ -12,9 +12,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.domain;
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
@@ -64,11 +63,17 @@ public abstract class AclFormattingUtils {
|
||||
return new String(replacement);
|
||||
}
|
||||
|
||||
private static String printBinary(int i, char on, char off) {
|
||||
String s = Integer.toString(i, 2);
|
||||
String pattern = Permission.THIRTY_TWO_RESERVED_OFF;
|
||||
String temp2 = pattern.substring(0, pattern.length() - s.length()) + s;
|
||||
|
||||
return temp2.replace('0', off).replace('1', on);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a representation of the active bits in the presented mask, with each active bit being denoted by
|
||||
* character '*'.
|
||||
* <p>
|
||||
* Inactive bits will be denoted by character {@link Permission#RESERVED_OFF}.
|
||||
* character "".<p>Inactive bits will be denoted by character {@link Permission#RESERVED_OFF}.</p>
|
||||
*
|
||||
* @param i the integer bit mask to print the active bits for
|
||||
*
|
||||
@@ -97,12 +102,4 @@ public abstract class AclFormattingUtils {
|
||||
|
||||
return printBinary(mask, Permission.RESERVED_ON, Permission.RESERVED_OFF).replace(Permission.RESERVED_ON, code);
|
||||
}
|
||||
|
||||
private static String printBinary(int i, char on, char off) {
|
||||
String s = Integer.toString(i, 2);
|
||||
String pattern = Permission.THIRTY_TWO_RESERVED_OFF;
|
||||
String temp2 = pattern.substring(0, pattern.length() - s.length()) + s;
|
||||
|
||||
return temp2.replace('0', off).replace('1', on);
|
||||
}
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
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.ObjectIdentityGenerator;
|
||||
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.Authentication;
|
||||
|
||||
/**
|
||||
* 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.acls.AclEntryVoter AclEntryVoter}.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 3.0
|
||||
*/
|
||||
public class AclPermissionEvaluator implements PermissionEvaluator {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private AclService aclService;
|
||||
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||
private ObjectIdentityGenerator objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
|
||||
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
|
||||
|
||||
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);
|
||||
|
||||
return checkPermission(authentication, objectIdentity, permission);
|
||||
}
|
||||
|
||||
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
|
||||
ObjectIdentity objectIdentity = objectIdentityGenerator.createObjectIdentity(targetId, targetType);
|
||||
|
||||
return checkPermission(authentication, objectIdentity, permission);
|
||||
}
|
||||
|
||||
private boolean checkPermission(Authentication authentication, ObjectIdentity oid, Object permission) {
|
||||
// Obtain the SIDs applicable to the principal
|
||||
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
|
||||
List<Permission> requiredPermission = resolvePermission(permission);
|
||||
|
||||
try {
|
||||
// Lookup only ACLs for SIDs we're interested in
|
||||
Acl acl = aclService.readAclById(oid, 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;
|
||||
|
||||
}
|
||||
|
||||
List<Permission> resolvePermission(Object permission) {
|
||||
if (permission instanceof Integer) {
|
||||
return Arrays.asList(permissionFactory.buildFromMask(((Integer)permission).intValue()));
|
||||
}
|
||||
|
||||
if (permission instanceof Permission) {
|
||||
return Arrays.asList((Permission)permission);
|
||||
}
|
||||
|
||||
if (permission instanceof Permission[]) {
|
||||
return Arrays.asList((Permission[])permission);
|
||||
}
|
||||
|
||||
if (permission instanceof String) {
|
||||
String permString = (String)permission;
|
||||
Permission p = null;
|
||||
|
||||
try {
|
||||
p = permissionFactory.buildFromName(permString);
|
||||
} catch(IllegalArgumentException notfound) {
|
||||
p = permissionFactory.buildFromName(permString.toUpperCase());
|
||||
}
|
||||
|
||||
if (p != null) {
|
||||
return Arrays.asList(p);
|
||||
}
|
||||
|
||||
}
|
||||
throw new IllegalArgumentException("Unsupported permission: " + permission);
|
||||
}
|
||||
|
||||
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
|
||||
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
|
||||
}
|
||||
|
||||
public void setObjectIdentityGenerator(ObjectIdentityGenerator objectIdentityGenerator) {
|
||||
this.objectIdentityGenerator = objectIdentityGenerator;
|
||||
}
|
||||
|
||||
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
|
||||
this.sidRetrievalStrategy = sidRetrievalStrategy;
|
||||
}
|
||||
|
||||
public void setPermissionFactory(PermissionFactory permissionFactory) {
|
||||
this.permissionFactory = permissionFactory;
|
||||
}
|
||||
}
|
||||
+15
-13
@@ -12,10 +12,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.model;
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@@ -35,13 +36,12 @@ public interface AclService {
|
||||
*
|
||||
* @return the children (or <tt>null</tt> if none were found)
|
||||
*/
|
||||
List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity);
|
||||
ObjectIdentity[] findChildren(ObjectIdentity parentIdentity);
|
||||
|
||||
/**
|
||||
* Same as {@link #readAclsById(Java.util.List<ObjectIdentity>)} except it returns only a single Acl.
|
||||
* <p>
|
||||
* This method should not be called as it does not leverage the underlying implementation's potential ability to
|
||||
* filter <tt>Acl</tt> entries based on a {@link Sid} parameter.</p>
|
||||
* Same as {@link #readAclsById(ObjectIdentity[])} except it returns only a single Acl.<p>This method
|
||||
* should not be called as it does not leverage the underlaying implementation's potential ability to filter
|
||||
* <tt>Acl</tt> entries based on a {@link Sid} parameter.</p>
|
||||
*
|
||||
* @param object to locate an {@link Acl} for
|
||||
*
|
||||
@@ -52,17 +52,18 @@ public interface AclService {
|
||||
Acl readAclById(ObjectIdentity object) throws NotFoundException;
|
||||
|
||||
/**
|
||||
* Same as {@link #readAclsById(List, List)} except it returns only a single Acl.
|
||||
* Same as {@link #readAclsById(ObjectIdentity[], Sid[])} except it returns only a single Acl.
|
||||
*
|
||||
* @param object to locate an {@link Acl} for
|
||||
* @param sids the security identities for which {@link Acl} information is required
|
||||
* @param sids the security identities for which {@link Acl} information is required
|
||||
* (may be <tt>null</tt> to denote all entries)
|
||||
*
|
||||
* @return the {@link Acl} for the requested {@link ObjectIdentity} (never <tt>null</tt>)
|
||||
*
|
||||
* @throws NotFoundException if an {@link Acl} was not found for the requested {@link ObjectIdentity}
|
||||
*/
|
||||
Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException;
|
||||
Acl readAclById(ObjectIdentity object, Sid[] sids)
|
||||
throws NotFoundException;
|
||||
|
||||
/**
|
||||
* Obtains all the <tt>Acl</tt>s that apply for the passed <tt>Object</tt>s.<p>The returned map is
|
||||
@@ -75,7 +76,7 @@ public interface AclService {
|
||||
*
|
||||
* @throws NotFoundException if an {@link Acl} was not found for each requested {@link ObjectIdentity}
|
||||
*/
|
||||
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects) throws NotFoundException;
|
||||
Map readAclsById(ObjectIdentity[] objects) throws NotFoundException;
|
||||
|
||||
/**
|
||||
* Obtains all the <tt>Acl</tt>s that apply for the passed <tt>Object</tt>s, but only for the
|
||||
@@ -88,12 +89,13 @@ public interface AclService {
|
||||
* not have a map key.</p>
|
||||
*
|
||||
* @param objects the objects to find {@link Acl} information for
|
||||
* @param sids the security identities for which {@link Acl} information is required
|
||||
* @param sids the security identities for which {@link Acl} information is required
|
||||
* (may be <tt>null</tt> to denote all entries)
|
||||
*
|
||||
* @return a map with exactly one element for each {@link ObjectIdentity} passed as an argument (never <tt>null</tt>)
|
||||
*
|
||||
* @throws NotFoundException if an {@link Acl} was not found for each requested {@link ObjectIdentity}
|
||||
*/
|
||||
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) throws NotFoundException;
|
||||
Map readAclsById(ObjectIdentity[] objects, Sid[] sids)
|
||||
throws NotFoundException;
|
||||
}
|
||||
+6
-4
@@ -12,7 +12,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.model;
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import org.springframework.security.SpringSecurityException;
|
||||
|
||||
|
||||
/**
|
||||
@@ -21,10 +23,10 @@ package org.springframework.security.acls.model;
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class AlreadyExistsException extends AclDataAccessException {
|
||||
public class AlreadyExistsException extends SpringSecurityException {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructs an <code>AlreadyExistsException</code> with the specified message.
|
||||
*
|
||||
* @param msg the detail message
|
||||
@@ -33,7 +35,7 @@ public class AlreadyExistsException extends AclDataAccessException {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructs an <code>AlreadyExistsException</code> with the specified message
|
||||
* and root cause.
|
||||
*
|
||||
+1
-2
@@ -12,8 +12,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
package org.springframework.security.acls;
|
||||
|
||||
/**
|
||||
* Represents an ACE that provides auditing information.
|
||||
+2
-1
@@ -12,7 +12,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.model;
|
||||
package org.springframework.security.acls;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
+6
-4
@@ -12,7 +12,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.model;
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import org.springframework.security.SpringSecurityException;
|
||||
|
||||
|
||||
/**
|
||||
@@ -21,10 +23,10 @@ package org.springframework.security.acls.model;
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class ChildrenExistException extends AclDataAccessException {
|
||||
public class ChildrenExistException extends SpringSecurityException {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructs an <code>ChildrenExistException</code> with the specified
|
||||
* message.
|
||||
*
|
||||
@@ -34,7 +36,7 @@ public class ChildrenExistException extends AclDataAccessException {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructs an <code>ChildrenExistException</code> with the specified
|
||||
* message and root cause.
|
||||
*
|
||||
+7
-4
@@ -12,7 +12,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.domain;
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import org.springframework.security.SpringSecurityException;
|
||||
|
||||
|
||||
/**
|
||||
* Thrown if an ACL identity could not be extracted from an object.
|
||||
@@ -20,10 +23,10 @@ package org.springframework.security.acls.domain;
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class IdentityUnavailableException extends RuntimeException {
|
||||
public class IdentityUnavailableException extends SpringSecurityException {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructs an <code>IdentityUnavailableException</code> with the specified message.
|
||||
*
|
||||
* @param msg the detail message
|
||||
@@ -32,7 +35,7 @@ public class IdentityUnavailableException extends RuntimeException {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructs an <code>IdentityUnavailableException</code> with the specified message
|
||||
* and root cause.
|
||||
*
|
||||
+5
-2
@@ -12,17 +12,20 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.model;
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
|
||||
/**
|
||||
* A mutable <tt>Acl</tt>.
|
||||
*
|
||||
* <p>
|
||||
* A mutable ACL must ensure that appropriate security checks are performed
|
||||
* before allowing access to its methods.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
@@ -44,7 +47,7 @@ public interface MutableAcl extends Acl {
|
||||
|
||||
/**
|
||||
* Changes the present owner to a different owner.
|
||||
*
|
||||
*
|
||||
* @param newOwner the new owner (mandatory; cannot be null)
|
||||
*/
|
||||
void setOwner(Sid newOwner);
|
||||
+4
-1
@@ -12,8 +12,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.model;
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
|
||||
|
||||
/**
|
||||
@@ -54,6 +55,8 @@ public interface MutableAclService extends AclService {
|
||||
*
|
||||
* @param acl to modify
|
||||
*
|
||||
* @return DOCUMENT ME!
|
||||
*
|
||||
* @throws NotFoundException if the relevant record could not be found (did you remember to use {@link
|
||||
* #createAcl(ObjectIdentity)} to create the object, rather than creating it with the <code>new</code>
|
||||
* keyword?)
|
||||
+6
-4
@@ -12,7 +12,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.model;
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import org.springframework.security.SpringSecurityException;
|
||||
|
||||
|
||||
/**
|
||||
@@ -21,10 +23,10 @@ package org.springframework.security.acls.model;
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class NotFoundException extends AclDataAccessException {
|
||||
public class NotFoundException extends SpringSecurityException {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructs an <code>NotFoundException</code> with the specified message.
|
||||
*
|
||||
* @param msg the detail message
|
||||
@@ -33,7 +35,7 @@ public class NotFoundException extends AclDataAccessException {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructs an <code>NotFoundException</code> with the specified message
|
||||
* and root cause.
|
||||
*
|
||||
+3
-1
@@ -12,8 +12,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.model;
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
|
||||
/**
|
||||
@@ -22,6 +23,7 @@ package org.springframework.security.acls.model;
|
||||
* <p>
|
||||
* Generally the owner of an ACL is able to call any ACL mutator method, as
|
||||
* well as assign a new owner.
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
+6
-7
@@ -12,12 +12,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.model;
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Represents a permission granted to a <tt>Sid</tt> for a given domain object.
|
||||
* Represents a permission granted to a {@link org.springframework.security.acls.sid.Sid Sid} for a given domain object.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
@@ -46,11 +46,10 @@ public interface Permission extends Serializable {
|
||||
* {@link #RESERVED_OFF} which is used to denote a bit that is off (clear).
|
||||
* Implementations may also elect to use {@link #RESERVED_ON} internally for computation purposes,
|
||||
* although this method may not return any <code>String</code> containing {@link #RESERVED_ON}.
|
||||
* <p>
|
||||
* The returned String must be 32 characters in length.
|
||||
* <p>
|
||||
* This method is only used for user interface and logging purposes. It is not used in any permission
|
||||
* calculations. Therefore, duplication of characters within the output is permitted.
|
||||
* </p>
|
||||
* <p>The returned String must be 32 characters in length.</p>
|
||||
* <p>This method is only used for user interface and logging purposes. It is not used in any permission
|
||||
* calculations. Therefore, duplication of characters within the output is permitted.</p>
|
||||
*
|
||||
* @return a 32-character bit pattern
|
||||
*/
|
||||
+6
-4
@@ -12,7 +12,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.model;
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import org.springframework.security.SpringSecurityException;
|
||||
|
||||
|
||||
/**
|
||||
@@ -22,10 +24,10 @@ package org.springframework.security.acls.model;
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class UnloadedSidException extends AclDataAccessException {
|
||||
public class UnloadedSidException extends SpringSecurityException {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructs an <code>NotFoundException</code> with the specified message.
|
||||
*
|
||||
* @param msg the detail message
|
||||
@@ -34,7 +36,7 @@ public class UnloadedSidException extends AclDataAccessException {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructs an <code>NotFoundException</code> with the specified message
|
||||
* and root cause.
|
||||
*
|
||||
@@ -1,12 +1,15 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.AclFormattingUtils;
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
/**
|
||||
* Provides an abstract superclass for {@link Permission} implementations.
|
||||
*
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @since 2.0.3
|
||||
* @see AbstractRegisteredPermission
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractPermission implements Permission {
|
||||
|
||||
@@ -16,23 +19,7 @@ public abstract class AbstractPermission implements Permission {
|
||||
protected int mask;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
/**
|
||||
* Sets the permission mask and uses the '*' character to represent active bits when represented as a bit
|
||||
* pattern string.
|
||||
*
|
||||
* @param mask the integer bit mask for the permission
|
||||
*/
|
||||
protected AbstractPermission(int mask) {
|
||||
this.mask = mask;
|
||||
this.code = '*';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the permission mask and uses the specified character for active bits.
|
||||
*
|
||||
* @param mask the integer bit mask for the permission
|
||||
* @param code the character to print for each active bit in the mask (see {@link Permission#getPattern()})
|
||||
*/
|
||||
protected AbstractPermission(int mask, char code) {
|
||||
this.mask = mask;
|
||||
this.code = code;
|
||||
@@ -66,7 +53,7 @@ public abstract class AbstractPermission implements Permission {
|
||||
return this.getClass().getSimpleName() + "[" + getPattern() + "=" + mask + "]";
|
||||
}
|
||||
|
||||
public final int hashCode() {
|
||||
return this.mask;
|
||||
}
|
||||
public final int hashCode() {
|
||||
return this.mask;
|
||||
}
|
||||
}
|
||||
|
||||
+38
-38
@@ -14,11 +14,11 @@
|
||||
*/
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -68,45 +68,45 @@ public class AccessControlEntryImpl implements AccessControlEntry, AuditableAcce
|
||||
AccessControlEntryImpl rhs = (AccessControlEntryImpl) arg0;
|
||||
|
||||
if (this.acl == null) {
|
||||
if (rhs.getAcl() != null) {
|
||||
return false;
|
||||
}
|
||||
// Both this.acl and rhs.acl are null and thus equal
|
||||
if (rhs.getAcl() != null) {
|
||||
return false;
|
||||
}
|
||||
// Both this.acl and rhs.acl are null and thus equal
|
||||
} else {
|
||||
// this.acl is non-null
|
||||
if (rhs.getAcl() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Both this.acl and rhs.acl are non-null, so do a comparison
|
||||
if (this.acl.getObjectIdentity() == null) {
|
||||
if (rhs.acl.getObjectIdentity() != null) {
|
||||
return false;
|
||||
}
|
||||
// Both this.acl and rhs.acl are null and thus equal
|
||||
} else {
|
||||
// Both this.acl.objectIdentity and rhs.acl.objectIdentity are non-null
|
||||
if (!this.acl.getObjectIdentity().equals(rhs.getAcl().getObjectIdentity())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// this.acl is non-null
|
||||
if (rhs.getAcl() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Both this.acl and rhs.acl are non-null, so do a comparison
|
||||
if (this.acl.getObjectIdentity() == null) {
|
||||
if (rhs.acl.getObjectIdentity() != null) {
|
||||
return false;
|
||||
}
|
||||
// Both this.acl and rhs.acl are null and thus equal
|
||||
} else {
|
||||
// Both this.acl.objectIdentity and rhs.acl.objectIdentity are non-null
|
||||
if (!this.acl.getObjectIdentity().equals(rhs.getAcl().getObjectIdentity())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.id == null) {
|
||||
if (rhs.id != null) {
|
||||
return false;
|
||||
}
|
||||
// Both this.id and rhs.id are null and thus equal
|
||||
if (rhs.id != null) {
|
||||
return false;
|
||||
}
|
||||
// Both this.id and rhs.id are null and thus equal
|
||||
} else {
|
||||
// this.id is non-null
|
||||
if (rhs.id == null) {
|
||||
return false;
|
||||
}
|
||||
// this.id is non-null
|
||||
if (rhs.id == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Both this.id and rhs.id are non-null
|
||||
if (!this.id.equals(rhs.id)) {
|
||||
return false;
|
||||
}
|
||||
// Both this.id and rhs.id are non-null
|
||||
if (!this.id.equals(rhs.id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((this.auditFailure != rhs.isAuditFailure()) || (this.auditSuccess != rhs.isAuditSuccess())
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.Acl;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
+28
-22
@@ -15,26 +15,27 @@
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
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.context.SecurityContextHolder;
|
||||
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.acls.model.SidRetrievalStrategy;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation of {@link AclAuthorizationStrategy}.
|
||||
* <p>
|
||||
* Permission will be granted provided the current principal is either the owner (as defined by the ACL), has
|
||||
* {@link BasePermission#ADMINISTRATION} (as defined by the ACL and via a {@link Sid} retrieved for the current
|
||||
* principal via {@link #sidRetrievalStrategy}), or if the current principal holds the relevant system-wide
|
||||
* {@link GrantedAuthority} and injected into the constructor.
|
||||
* Default implementation of {@link AclAuthorizationStrategy}.<p>Permission will be granted provided the current
|
||||
* principal is either the owner (as defined by the ACL), has {@link BasePermission#ADMINISTRATION} (as defined by the
|
||||
* ACL and via a {@link Sid} retrieved for the current principal via {@link #sidRetrievalStrategy}), or if the current
|
||||
* principal holds the relevant system-wide {@link GrantedAuthority} and injected into the constructor.</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
@@ -49,7 +50,7 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructor. The only mandatory parameter relates to the system-wide {@link GrantedAuthority} instances that
|
||||
* can be held to always permit ACL changes.
|
||||
*
|
||||
@@ -59,7 +60,8 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||
* index 2 is the authority needed to change other ACL and ACE details) (required)
|
||||
*/
|
||||
public AclAuthorizationStrategyImpl(GrantedAuthority[] auths) {
|
||||
Assert.isTrue(auths != null && auths.length == 3, "GrantedAuthority[] with three elements required");
|
||||
Assert.notEmpty(auths, "GrantedAuthority[] with three elements required");
|
||||
Assert.isTrue(auths.length == 3, "GrantedAuthority[] with three elements required");
|
||||
this.gaTakeOwnership = auths[0];
|
||||
this.gaModifyAuditing = auths[1];
|
||||
this.gaGeneralChanges = auths[2];
|
||||
@@ -98,19 +100,23 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
|
||||
}
|
||||
|
||||
// Iterate this principal's authorities to determine right
|
||||
if (authentication.getAuthorities().contains(requiredAuthority)) {
|
||||
return;
|
||||
GrantedAuthority[] auths = authentication.getAuthorities();
|
||||
|
||||
for (int i = 0; i < auths.length; i++) {
|
||||
if (requiredAuthority.equals(auths[i])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to get permission via ACEs within the ACL
|
||||
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
|
||||
Sid[] sids = sidRetrievalStrategy.getSids(authentication);
|
||||
|
||||
if (acl.isGranted(Arrays.asList(BasePermission.ADMINISTRATION), sids, false)) {
|
||||
if (acl.isGranted(new Permission[] {BasePermission.ADMINISTRATION}, sids, false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new AccessDeniedException(
|
||||
"Principal does not have required ACL permissions to perform requested operation");
|
||||
"Principal does not have required ACL permissions to perform requested operation");
|
||||
}
|
||||
|
||||
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
|
||||
|
||||
@@ -15,19 +15,20 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AuditableAcl;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.NotFoundException;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.OwnershipAcl;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.acls.model.UnloadedSidException;
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AuditableAcl;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.OwnershipAcl;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.UnloadedSidException;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
@@ -35,26 +36,26 @@ import org.springframework.util.Assert;
|
||||
* Base implementation of <code>Acl</code>.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @version $Id
|
||||
*/
|
||||
public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
|
||||
private Acl parentAcl;
|
||||
private transient AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
private transient AuditLogger auditLogger;
|
||||
private List<AccessControlEntry> aces = new ArrayList<AccessControlEntry>();
|
||||
private List aces = new Vector();
|
||||
private ObjectIdentity objectIdentity;
|
||||
private Serializable id;
|
||||
private Sid owner; // OwnershipAcl
|
||||
private List<Sid> loadedSids = null; // includes all SIDs the WHERE clause covered, even if there was no ACE for a SID
|
||||
private Sid[] loadedSids = null; // includes all SIDs the WHERE clause covered, even if there was no ACE for a SID
|
||||
private boolean entriesInheriting = true;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
/**
|
||||
* Minimal constructor, which should be used {@link
|
||||
* org.springframework.security.acls.model.MutableAclService#createAcl(ObjectIdentity)}.
|
||||
* org.springframework.security.acls.MutableAclService#createAcl(ObjectIdentity)}.
|
||||
*
|
||||
* @param objectIdentity the object identity this ACL relates to (required)
|
||||
* @param id the primary key assigned to this ACL (required)
|
||||
@@ -62,7 +63,7 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
* @param auditLogger audit logger (required)
|
||||
*/
|
||||
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
|
||||
AuditLogger auditLogger) {
|
||||
AuditLogger auditLogger) {
|
||||
Assert.notNull(objectIdentity, "Object Identity required");
|
||||
Assert.notNull(id, "Id required");
|
||||
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
||||
@@ -73,7 +74,7 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
this.auditLogger = auditLogger;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Full constructor, which should be used by persistence tools that do not
|
||||
* provide field-level access features.
|
||||
*
|
||||
@@ -89,7 +90,7 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
* @param owner the owner (required)
|
||||
*/
|
||||
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
|
||||
AuditLogger auditLogger, Acl parentAcl, List<Sid> loadedSids, boolean entriesInheriting, Sid owner) {
|
||||
AuditLogger auditLogger, Acl parentAcl, Sid[] loadedSids, boolean entriesInheriting, Sid owner) {
|
||||
Assert.notNull(objectIdentity, "Object Identity required");
|
||||
Assert.notNull(id, "Id required");
|
||||
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
||||
@@ -105,55 +106,35 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Private no-argument constructor for use by reflection-based persistence
|
||||
* tools along with field-level access.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private AclImpl() {}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
private void verifyAceIndexExists(int aceIndex) {
|
||||
if (aceIndex < 0) {
|
||||
throw new NotFoundException("aceIndex must be greater than or equal to zero");
|
||||
}
|
||||
if (aceIndex > this.aces.size()) {
|
||||
throw new NotFoundException("aceIndex must correctly refer to an index of the AccessControlEntry collection");
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteAce(int aceIndex) throws NotFoundException {
|
||||
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
verifyAceIndexExists(aceIndex);
|
||||
|
||||
|
||||
synchronized (aces) {
|
||||
this.aces.remove(aceIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyAceIndexExists(int aceIndex) {
|
||||
if (aceIndex < 0) {
|
||||
throw new NotFoundException("aceIndex must be greater than or equal to zero");
|
||||
}
|
||||
if (aceIndex >= this.aces.size()) {
|
||||
throw new NotFoundException("aceIndex must refer to an index of the AccessControlEntry list. " +
|
||||
"List size is " + aces.size() + ", index was " + aceIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public void insertAce(int atIndexLocation, Permission permission, Sid sid, boolean granting) throws NotFoundException {
|
||||
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.notNull(permission, "Permission required");
|
||||
Assert.notNull(sid, "Sid required");
|
||||
if (atIndexLocation < 0) {
|
||||
throw new NotFoundException("atIndexLocation must be greater than or equal to zero");
|
||||
}
|
||||
if (atIndexLocation > this.aces.size()) {
|
||||
throw new NotFoundException("atIndexLocation must be less than or equal to the size of the AccessControlEntry collection");
|
||||
}
|
||||
|
||||
AccessControlEntryImpl ace = new AccessControlEntryImpl(null, this, sid, permission, granting, false, false);
|
||||
|
||||
synchronized (aces) {
|
||||
this.aces.add(atIndexLocation, ace);
|
||||
}
|
||||
}
|
||||
|
||||
public List<AccessControlEntry> getEntries() {
|
||||
public AccessControlEntry[] getEntries() {
|
||||
// Can safely return AccessControlEntry directly, as they're immutable outside the ACL package
|
||||
return new ArrayList<AccessControlEntry>(aces);
|
||||
return (AccessControlEntry[]) aces.toArray(new AccessControlEntry[] {});
|
||||
}
|
||||
|
||||
public Serializable getId() {
|
||||
@@ -164,6 +145,33 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
return objectIdentity;
|
||||
}
|
||||
|
||||
public Sid getOwner() {
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
public Acl getParentAcl() {
|
||||
return parentAcl;
|
||||
}
|
||||
|
||||
public void insertAce(int atIndexLocation, Permission permission, Sid sid, boolean granting)
|
||||
throws NotFoundException {
|
||||
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.notNull(permission, "Permission required");
|
||||
Assert.notNull(sid, "Sid required");
|
||||
if (atIndexLocation < 0) {
|
||||
throw new NotFoundException("atIndexLocation must be greater than or equal to zero");
|
||||
}
|
||||
if (atIndexLocation > this.aces.size()) {
|
||||
throw new NotFoundException("atIndexLocation must be less than or equal to the size of the AccessControlEntry collection");
|
||||
}
|
||||
|
||||
AccessControlEntryImpl ace = new AccessControlEntryImpl(null, this, sid, permission, granting, false, false);
|
||||
|
||||
synchronized (aces) {
|
||||
this.aces.add(atIndexLocation, ace);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEntriesInheriting() {
|
||||
return entriesInheriting;
|
||||
}
|
||||
@@ -199,8 +207,8 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
* @throws UnloadedSidException if the passed SIDs are unknown to this ACL because the ACL was only loaded for a
|
||||
* subset of SIDs
|
||||
*/
|
||||
public boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
|
||||
throws NotFoundException, UnloadedSidException {
|
||||
public boolean isGranted(Permission[] permission, Sid[] sids, boolean administrativeMode)
|
||||
throws NotFoundException, UnloadedSidException {
|
||||
Assert.notEmpty(permission, "Permissions required");
|
||||
Assert.notEmpty(sids, "SIDs required");
|
||||
|
||||
@@ -210,14 +218,16 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
|
||||
AccessControlEntry firstRejection = null;
|
||||
|
||||
for (Permission p : permission) {
|
||||
for (Sid sid: sids) {
|
||||
for (int i = 0; i < permission.length; i++) {
|
||||
for (int x = 0; x < sids.length; x++) {
|
||||
// Attempt to find exact match for this permission mask and SID
|
||||
Iterator acesIterator = aces.iterator();
|
||||
boolean scanNextSid = true;
|
||||
|
||||
for (AccessControlEntry ace : aces ) {
|
||||
while (acesIterator.hasNext()) {
|
||||
AccessControlEntry ace = (AccessControlEntry) acesIterator.next();
|
||||
|
||||
if ((ace.getPermission().getMask() == p.getMask()) && ace.getSid().equals(sid)) {
|
||||
if ((ace.getPermission().getMask() == permission[i].getMask()) && ace.getSid().equals(sids[x])) {
|
||||
// Found a matching ACE, so its authorization decision will prevail
|
||||
if (ace.isGranting()) {
|
||||
// Success
|
||||
@@ -226,19 +236,19 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
// Failure for this permission, so stop search
|
||||
// We will see if they have a different permission
|
||||
// (this permission is 100% rejected for this SID)
|
||||
if (firstRejection == null) {
|
||||
// Store first rejection for auditing reasons
|
||||
firstRejection = ace;
|
||||
}
|
||||
|
||||
scanNextSid = false; // helps break the loop
|
||||
|
||||
break; // exit "aceIterator" while loop
|
||||
}
|
||||
|
||||
// Failure for this permission, so stop search
|
||||
// We will see if they have a different permission
|
||||
// (this permission is 100% rejected for this SID)
|
||||
if (firstRejection == null) {
|
||||
// Store first rejection for auditing reasons
|
||||
firstRejection = ace;
|
||||
}
|
||||
|
||||
scanNextSid = false; // helps break the loop
|
||||
|
||||
break; // exit aces loop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,19 +278,19 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSidLoaded(List<Sid> sids) {
|
||||
public boolean isSidLoaded(Sid[] sids) {
|
||||
// If loadedSides is null, this indicates all SIDs were loaded
|
||||
// Also return true if the caller didn't specify a SID to find
|
||||
if ((this.loadedSids == null) || (sids == null) || (sids.size() == 0)) {
|
||||
if ((this.loadedSids == null) || (sids == null) || (sids.length == 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// This ACL applies to a SID subset only. Iterate to check it applies.
|
||||
for (Sid sid: sids) {
|
||||
for (int i = 0; i < sids.length; i++) {
|
||||
boolean found = false;
|
||||
|
||||
for (Sid loadedSid : loadedSids) {
|
||||
if (sid.equals(loadedSid)) {
|
||||
for (int y = 0; y < this.loadedSids.length; y++) {
|
||||
if (sids[i].equals(this.loadedSids[y])) {
|
||||
// this SID is OK
|
||||
found = true;
|
||||
|
||||
@@ -307,20 +317,12 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
this.owner = newOwner;
|
||||
}
|
||||
|
||||
public Sid getOwner() {
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
public void setParent(Acl newParent) {
|
||||
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.isTrue(newParent == null || !newParent.equals(this), "Cannot be the parent of yourself");
|
||||
this.parentAcl = newParent;
|
||||
}
|
||||
|
||||
public Acl getParentAcl() {
|
||||
return parentAcl;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("AclImpl[");
|
||||
@@ -328,16 +330,17 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
sb.append("objectIdentity: ").append(this.objectIdentity).append("; ");
|
||||
sb.append("owner: ").append(this.owner).append("; ");
|
||||
|
||||
Iterator iterator = this.aces.iterator();
|
||||
int count = 0;
|
||||
|
||||
for (AccessControlEntry ace : aces) {
|
||||
while (iterator.hasNext()) {
|
||||
count++;
|
||||
|
||||
if (count == 1) {
|
||||
sb.append("\r\n");
|
||||
}
|
||||
|
||||
sb.append(ace).append("\r\n");
|
||||
sb.append(iterator.next().toString()).append("\r\n");
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
@@ -357,7 +360,7 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
throws NotFoundException {
|
||||
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
verifyAceIndexExists(aceIndex);
|
||||
|
||||
|
||||
synchronized (aces) {
|
||||
AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(aceIndex);
|
||||
ace.setPermission(permission);
|
||||
@@ -367,42 +370,42 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
|
||||
public void updateAuditing(int aceIndex, boolean auditSuccess, boolean auditFailure) {
|
||||
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
verifyAceIndexExists(aceIndex);
|
||||
|
||||
|
||||
synchronized (aces) {
|
||||
AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(aceIndex);
|
||||
ace.setAuditSuccess(auditSuccess);
|
||||
ace.setAuditFailure(auditFailure);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof AclImpl) {
|
||||
AclImpl rhs = (AclImpl) obj;
|
||||
if (this.aces.equals(rhs.aces)) {
|
||||
if ((this.parentAcl == null && rhs.parentAcl == null) || (this.parentAcl.equals(rhs.parentAcl))) {
|
||||
if ((this.objectIdentity == null && rhs.objectIdentity == null) || (this.objectIdentity.equals(rhs.objectIdentity))) {
|
||||
if ((this.id == null && rhs.id == null) || (this.id.equals(rhs.id))) {
|
||||
if ((this.owner == null && rhs.owner == null) || this.owner.equals(rhs.owner)) {
|
||||
if (this.entriesInheriting == rhs.entriesInheriting) {
|
||||
if ((this.loadedSids == null && rhs.loadedSids == null)) {
|
||||
return true;
|
||||
}
|
||||
if (this.loadedSids.size() == rhs.loadedSids.size()) {
|
||||
for (int i = 0; i < this.loadedSids.size(); i++) {
|
||||
if (!this.loadedSids.get(i).equals(rhs.loadedSids.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof AclImpl) {
|
||||
AclImpl rhs = (AclImpl) obj;
|
||||
if (this.aces.equals(rhs.aces)) {
|
||||
if ((this.parentAcl == null && rhs.parentAcl == null) || (this.parentAcl.equals(rhs.parentAcl))) {
|
||||
if ((this.objectIdentity == null && rhs.objectIdentity == null) || (this.objectIdentity.equals(rhs.objectIdentity))) {
|
||||
if ((this.id == null && rhs.id == null) || (this.id.equals(rhs.id))) {
|
||||
if ((this.owner == null && rhs.owner == null) || this.owner.equals(rhs.owner)) {
|
||||
if (this.entriesInheriting == rhs.entriesInheriting) {
|
||||
if ((this.loadedSids == null && rhs.loadedSids == null)) {
|
||||
return true;
|
||||
}
|
||||
if (this.loadedSids.length == rhs.loadedSids.length) {
|
||||
for (int i = 0; i < this.loadedSids.length; i++) {
|
||||
if (!this.loadedSids[i].equals(rhs.loadedSids[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
*/
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,17 +14,17 @@
|
||||
*/
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
|
||||
/**
|
||||
* A set of standard permissions.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* You may subclass this class to add additional permissions, or use this class as a guide
|
||||
* for creating your own permission classes.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
@@ -34,12 +34,39 @@ public class BasePermission extends AbstractPermission {
|
||||
public static final Permission CREATE = new BasePermission(1 << 2, 'C'); // 4
|
||||
public static final Permission DELETE = new BasePermission(1 << 3, 'D'); // 8
|
||||
public static final Permission ADMINISTRATION = new BasePermission(1 << 4, 'A'); // 16
|
||||
|
||||
protected static DefaultPermissionFactory defaultPermissionFactory = new DefaultPermissionFactory();
|
||||
|
||||
protected BasePermission(int mask) {
|
||||
super(mask);
|
||||
/**
|
||||
* Registers the public static permissions defined on this class. This is mandatory so
|
||||
* that the static methods will operate correctly.
|
||||
*/
|
||||
static {
|
||||
registerPermissionsFor(BasePermission.class);
|
||||
}
|
||||
|
||||
protected BasePermission(int mask, char code) {
|
||||
super(mask, code);
|
||||
super(mask, code);
|
||||
}
|
||||
}
|
||||
|
||||
protected final static void registerPermissionsFor(Class subClass) {
|
||||
defaultPermissionFactory.registerPublicPermissions(subClass);
|
||||
}
|
||||
|
||||
public final static Permission buildFromMask(int mask) {
|
||||
return defaultPermissionFactory.buildFromMask(mask);
|
||||
}
|
||||
|
||||
public final static Permission[] buildFromMask(int[] masks) {
|
||||
return defaultPermissionFactory.buildFromMask(masks);
|
||||
}
|
||||
|
||||
public final static Permission buildFromName(String name) {
|
||||
return defaultPermissionFactory.buildFromName(name);
|
||||
}
|
||||
|
||||
public final static Permission[] buildFromName(String[] names) {
|
||||
return defaultPermissionFactory.buildFromName(names);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,8 +14,8 @@
|
||||
*/
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.model.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.AuditableAccessControlEntry;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
+3
-2
@@ -14,7 +14,8 @@
|
||||
*/
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.AclFormattingUtils;
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
|
||||
/**
|
||||
@@ -30,7 +31,7 @@ public class CumulativePermission extends AbstractPermission {
|
||||
private String pattern = THIRTY_TWO_RESERVED_OFF;
|
||||
|
||||
public CumulativePermission() {
|
||||
super(0, ' ');
|
||||
super(0, ' ');
|
||||
}
|
||||
|
||||
public CumulativePermission clear(Permission permission) {
|
||||
|
||||
+65
-84
@@ -1,68 +1,42 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.jdbc.LookupStrategy;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link PermissionFactory}.
|
||||
*
|
||||
* <p>
|
||||
* Used as a strategy by classes which wish to map integer masks and permission names to <tt>Permission</tt>
|
||||
* instances for use with the ACL implementation.
|
||||
* <p>
|
||||
* Maintains a registry of permission names and masks to <tt>Permission</tt> instances.
|
||||
*
|
||||
* Generally this class will be used by a {@link Permission} instance, as opposed to being dependency
|
||||
* injected into a {@link LookupStrategy} or similar. Nevertheless, the latter mode of operation is
|
||||
* fully supported (in which case your {@link Permission} implementations probably should extend
|
||||
* {@link AbstractPermission} instead of {@link AbstractRegisteredPermission}).
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
* @since 2.0.3
|
||||
*
|
||||
*/
|
||||
public class DefaultPermissionFactory implements PermissionFactory {
|
||||
private final Map<Integer, Permission> registeredPermissionsByInteger = new HashMap<Integer, Permission>();
|
||||
private final Map<String, Permission> registeredPermissionsByName = new HashMap<String, Permission>();
|
||||
private Map registeredPermissionsByInteger = new HashMap();
|
||||
private Map registeredPermissionsByName = new HashMap();
|
||||
|
||||
/**
|
||||
* Registers the <tt>Permission</tt> fields from the <tt>BasePermission</tt> class.
|
||||
*/
|
||||
public DefaultPermissionFactory() {
|
||||
registerPublicPermissions(BasePermission.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the <tt>Permission</tt> fields from the supplied class.
|
||||
*/
|
||||
public DefaultPermissionFactory(Class<? extends Permission> permissionClass) {
|
||||
registerPublicPermissions(permissionClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a map of named <tt>Permission</tt> instances.
|
||||
*
|
||||
* @param namedPermissions the map of <tt>Permission</tt>s, keyed by name.
|
||||
*/
|
||||
public DefaultPermissionFactory(Map<String, ? extends Permission> namedPermissions) {
|
||||
for (String name : namedPermissions.keySet()) {
|
||||
registerPermission(namedPermissions.get(name), name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the public static fields of type {@link Permission} for a give class.
|
||||
* <p>
|
||||
* These permissions will be registered under the name of the field. See {@link BasePermission}
|
||||
* for an example.
|
||||
*
|
||||
* Permit registration of a {@link DefaultPermissionFactory} class. The class must provide
|
||||
* public static fields of type {@link Permission} to represent the possible permissions.
|
||||
*
|
||||
* @param clazz a {@link Permission} class with public static fields to register
|
||||
*/
|
||||
protected void registerPublicPermissions(Class<? extends Permission> clazz) {
|
||||
public void registerPublicPermissions(Class clazz) {
|
||||
Assert.notNull(clazz, "Class required");
|
||||
|
||||
Field[] fields = clazz.getFields();
|
||||
Assert.isAssignable(Permission.class, clazz);
|
||||
|
||||
Field[] fields = clazz.getFields();
|
||||
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
try {
|
||||
@@ -72,32 +46,32 @@ public class DefaultPermissionFactory implements PermissionFactory {
|
||||
// Found a Permission static field
|
||||
Permission perm = (Permission) fieldValue;
|
||||
String permissionName = fields[i].getName();
|
||||
|
||||
|
||||
registerPermission(perm, permissionName);
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
protected void registerPermission(Permission perm, String permissionName) {
|
||||
Assert.notNull(perm, "Permission required");
|
||||
Assert.hasText(permissionName, "Permission name required");
|
||||
|
||||
Integer mask = new Integer(perm.getMask());
|
||||
|
||||
// Ensure no existing Permission uses this integer or code
|
||||
Assert.isTrue(!registeredPermissionsByInteger.containsKey(mask), "An existing Permission already provides mask " + mask);
|
||||
Assert.isTrue(!registeredPermissionsByName.containsKey(permissionName), "An existing Permission already provides name '" + permissionName + "'");
|
||||
|
||||
// Register the new Permission
|
||||
registeredPermissionsByInteger.put(mask, perm);
|
||||
registeredPermissionsByName.put(permissionName, perm);
|
||||
}
|
||||
public void registerPermission(Permission perm, String permissionName) {
|
||||
Assert.notNull(perm, "Permission required");
|
||||
Assert.hasText(permissionName, "Permission name required");
|
||||
|
||||
Integer mask = new Integer(perm.getMask());
|
||||
|
||||
// Ensure no existing Permission uses this integer or code
|
||||
Assert.isTrue(!registeredPermissionsByInteger.containsKey(mask), "An existing Permission already provides mask " + mask);
|
||||
Assert.isTrue(!registeredPermissionsByName.containsKey(permissionName), "An existing Permission already provides name '" + permissionName + "'");
|
||||
|
||||
// Register the new Permission
|
||||
registeredPermissionsByInteger.put(mask, perm);
|
||||
registeredPermissionsByName.put(permissionName, perm);
|
||||
}
|
||||
|
||||
public Permission buildFromMask(int mask) {
|
||||
if (registeredPermissionsByInteger.containsKey(Integer.valueOf(mask))) {
|
||||
// The requested mask has an exact match against a statically-defined Permission, so return it
|
||||
return registeredPermissionsByInteger.get(new Integer(mask));
|
||||
if (registeredPermissionsByInteger.containsKey(new Integer(mask))) {
|
||||
// The requested mask has an exactly match against a statically-defined Permission, so return it
|
||||
return (Permission) registeredPermissionsByInteger.get(new Integer(mask));
|
||||
}
|
||||
|
||||
// To get this far, we have to use a CumulativePermission
|
||||
@@ -107,11 +81,8 @@ public class DefaultPermissionFactory implements PermissionFactory {
|
||||
int permissionToCheck = 1 << i;
|
||||
|
||||
if ((mask & permissionToCheck) == permissionToCheck) {
|
||||
Permission p = registeredPermissionsByInteger.get(Integer.valueOf(permissionToCheck));
|
||||
|
||||
if (p == null) {
|
||||
throw new IllegalStateException("Mask '" + permissionToCheck + "' does not have a corresponding static Permission");
|
||||
}
|
||||
Permission p = (Permission) registeredPermissionsByInteger.get(new Integer(permissionToCheck));
|
||||
Assert.state(p != null, "Mask " + permissionToCheck + " does not have a corresponding static Permission");
|
||||
permission.set(p);
|
||||
}
|
||||
}
|
||||
@@ -119,28 +90,38 @@ public class DefaultPermissionFactory implements PermissionFactory {
|
||||
return permission;
|
||||
}
|
||||
|
||||
public Permission buildFromName(String name) {
|
||||
Permission p = registeredPermissionsByName.get(name);
|
||||
|
||||
if (p == null) {
|
||||
throw new IllegalArgumentException("Unknown permission '" + name + "'");
|
||||
public Permission[] buildFromMask(int[] masks) {
|
||||
if ((masks == null) || (masks.length == 0)) {
|
||||
return new Permission[0];
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
Permission[] permissions = new Permission[masks.length];
|
||||
|
||||
public List<Permission> buildFromNames(List<String> names) {
|
||||
if ((names == null) || (names.size() == 0)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Permission> permissions = new ArrayList<Permission>(names.size());
|
||||
|
||||
for (String name : names) {
|
||||
permissions.add(buildFromName(name));
|
||||
for (int i = 0; i < masks.length; i++) {
|
||||
permissions[i] = buildFromMask(masks[i]);
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
public Permission buildFromName(String name) {
|
||||
Assert.isTrue(registeredPermissionsByName.containsKey(name), "Unknown permission '" + name + "'");
|
||||
|
||||
return (Permission) registeredPermissionsByName.get(name);
|
||||
}
|
||||
|
||||
public Permission[] buildFromName(String[] names) {
|
||||
if ((names == null) || (names.length == 0)) {
|
||||
return new Permission[0];
|
||||
}
|
||||
|
||||
Permission[] permissions = new Permission[names.length];
|
||||
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
permissions[i] = buildFromName(names[i]);
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,31 +1,24 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
/**
|
||||
* Provides a simple mechanism to retrieve {@link Permission} instances from integer masks.
|
||||
*
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @since 2.0.3
|
||||
*
|
||||
*
|
||||
*/
|
||||
public interface PermissionFactory {
|
||||
|
||||
/**
|
||||
* Dynamically creates a <code>CumulativePermission</code> or <code>BasePermission</code> representing the
|
||||
* active bits in the passed mask.
|
||||
*
|
||||
* @param mask to build
|
||||
*
|
||||
* @return a Permission representing the requested object
|
||||
*/
|
||||
Permission buildFromMask(int mask);
|
||||
/**
|
||||
* Dynamically creates a <code>CumulativePermission</code> or <code>BasePermission</code> representing the
|
||||
* active bits in the passed mask.
|
||||
*
|
||||
* @param mask to build
|
||||
*
|
||||
* @return a Permission representing the requested object
|
||||
*/
|
||||
public abstract Permission buildFromMask(int mask);
|
||||
|
||||
|
||||
Permission buildFromName(String name);
|
||||
|
||||
|
||||
List<Permission> buildFromNames(List<String> names);
|
||||
}
|
||||
}
|
||||
-66
@@ -1,66 +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.acls.domain;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.acls.model.SidRetrievalStrategy;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Basic implementation of {@link SidRetrievalStrategy} that creates a {@link Sid} for the principal, as well as
|
||||
* every granted authority the principal holds. Can optionally have a <tt>RoleHierarchy</tt> injected in order to
|
||||
* determine the extended list of authorities that the principal is assigned.
|
||||
* <p>
|
||||
* The returned array will always contain the {@link PrincipalSid} before any {@link GrantedAuthoritySid} elements.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SidRetrievalStrategyImpl implements SidRetrievalStrategy {
|
||||
|
||||
private RoleHierarchy roleHierarchy = new NullRoleHierarchy();
|
||||
|
||||
public SidRetrievalStrategyImpl() {
|
||||
}
|
||||
|
||||
public SidRetrievalStrategyImpl(RoleHierarchy roleHierarchy) {
|
||||
Assert.notNull(roleHierarchy, "RoleHierarchy must not be null");
|
||||
this.roleHierarchy = roleHierarchy;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public List<Sid> getSids(Authentication authentication) {
|
||||
Collection<GrantedAuthority> authorities = roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
|
||||
List<Sid> sids = new ArrayList<Sid>(authorities.size() + 1);
|
||||
|
||||
sids.add(new PrincipalSid(authentication));
|
||||
|
||||
for (GrantedAuthority authority : authorities) {
|
||||
sids.add(new GrantedAuthoritySid(authority));
|
||||
}
|
||||
|
||||
return sids;
|
||||
}
|
||||
}
|
||||
+3
-4
@@ -12,9 +12,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.model;
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import org.springframework.security.acls.jdbc.JdbcAclService;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@@ -38,6 +39,4 @@ public interface AclCache {
|
||||
MutableAcl getFromCache(Serializable pk);
|
||||
|
||||
void putInCache(MutableAcl acl);
|
||||
|
||||
void clearCache();
|
||||
}
|
||||
+301
-361
@@ -14,7 +14,6 @@
|
||||
*/
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
@@ -26,6 +25,7 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@@ -33,96 +33,47 @@ import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.PreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.UnloadedSidException;
|
||||
import org.springframework.security.acls.domain.AccessControlEntryImpl;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
|
||||
import org.springframework.security.acls.domain.AclImpl;
|
||||
import org.springframework.security.acls.domain.AuditLogger;
|
||||
import org.springframework.security.acls.domain.DefaultPermissionFactory;
|
||||
import org.springframework.security.acls.domain.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.domain.PermissionFactory;
|
||||
import org.springframework.security.acls.domain.PrincipalSid;
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AclCache;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.NotFoundException;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.acls.model.UnloadedSidException;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.sid.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
* Performs lookups in a manner that is compatible with ANSI SQL.
|
||||
* <p>
|
||||
* NB: This implementation does attempt to provide reasonably optimised lookups - within the constraints of a normalised
|
||||
* database and standard ANSI SQL features. If you are willing to sacrifice either of these constraints
|
||||
* (e.g. use a particular database feature such as hierarchical queries or materalized views, or reduce normalisation)
|
||||
* you are likely to achieve better performance. In such situations you will need to provide your own custom
|
||||
* <code>LookupStrategy</code>. This class does not support subclassing, as it is likely to change in future releases
|
||||
* and therefore subclassing is unsupported.
|
||||
* <p>
|
||||
* There are two SQL queries executed, one in the <tt>lookupPrimaryKeys</tt> method and one in
|
||||
* <tt>lookupObjectIdentities</tt>. These are built from the same select and "order by" clause, using a different
|
||||
* where clause in each case. In order to use custom schema or column names, each of these SQL clauses can be
|
||||
* customized, but they must be consistent with each other and with the expected result set
|
||||
* generated by the the default values.
|
||||
* Performs lookups in a manner that is compatible with ANSI SQL.<p>NB: This implementation does attempt to provide
|
||||
* reasonably optimised lookups - within the constraints of a normalised database and standard ANSI SQL features. If
|
||||
* you are willing to sacrifice either of these constraints (eg use a particular database feature such as hierarchical
|
||||
* queries or materalized views, or reduce normalisation) you are likely to achieve better performance. In such
|
||||
* situations you will need to provide your own custom <code>LookupStrategy</code>. This class does not support
|
||||
* subclassing, as it is likely to change in future releases and therefore subclassing is unsupported.</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public final class BasicLookupStrategy implements LookupStrategy {
|
||||
|
||||
public final static String DEFAULT_SELECT_CLAUSE = "select acl_object_identity.object_id_identity, "
|
||||
+ "acl_entry.ace_order, "
|
||||
+ "acl_object_identity.id as acl_id, "
|
||||
+ "acl_object_identity.parent_object, "
|
||||
+ "acl_object_identity.entries_inheriting, "
|
||||
+ "acl_entry.id as ace_id, "
|
||||
+ "acl_entry.mask, "
|
||||
+ "acl_entry.granting, "
|
||||
+ "acl_entry.audit_success, "
|
||||
+ "acl_entry.audit_failure, "
|
||||
+ "acl_sid.principal as ace_principal, "
|
||||
+ "acl_sid.sid as ace_sid, "
|
||||
+ "acli_sid.principal as acl_principal, "
|
||||
+ "acli_sid.sid as acl_sid, "
|
||||
+ "acl_class.class "
|
||||
+ "from acl_object_identity "
|
||||
+ "left join acl_sid acli_sid on acli_sid.id = acl_object_identity.owner_sid "
|
||||
+ "left join acl_class on acl_class.id = acl_object_identity.object_id_class "
|
||||
+ "left join acl_entry on acl_object_identity.id = acl_entry.acl_object_identity "
|
||||
+ "left join acl_sid on acl_entry.sid = acl_sid.id "
|
||||
+ "where ( ";
|
||||
|
||||
private final static String DEFAULT_LOOKUP_KEYS_WHERE_CLAUSE = "(acl_object_identity.id = ?)";
|
||||
|
||||
private final static String DEFAULT_LOOKUP_IDENTITIES_WHERE_CLAUSE = "(acl_object_identity.object_id_identity = ? and acl_class.class = ?)";
|
||||
|
||||
public final static String DEFAULT_ORDER_BY_CLAUSE = ") order by acl_object_identity.object_id_identity"
|
||||
+ " asc, acl_entry.ace_order asc";
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private AclAuthorizationStrategy aclAuthorizationStrategy;
|
||||
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
|
||||
private AclCache aclCache;
|
||||
private AuditLogger auditLogger;
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
private int batchSize = 50;
|
||||
|
||||
private final Field fieldAces = FieldUtils.getField(AclImpl.class, "aces");
|
||||
private final Field fieldAcl = FieldUtils.getField(AccessControlEntryImpl.class, "acl");
|
||||
|
||||
// SQL Customization fields
|
||||
private String selectClause = DEFAULT_SELECT_CLAUSE;
|
||||
private String lookupPrimaryKeysWhereClause = DEFAULT_LOOKUP_KEYS_WHERE_CLAUSE;
|
||||
private String lookupObjectIdentitiesWhereClause = DEFAULT_LOOKUP_IDENTITIES_WHERE_CLAUSE;
|
||||
private String orderByClause = DEFAULT_ORDER_BY_CLAUSE;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
/**
|
||||
@@ -138,38 +89,56 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
Assert.notNull(aclCache, "AclCache required");
|
||||
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
|
||||
Assert.notNull(auditLogger, "AuditLogger required");
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.aclCache = aclCache;
|
||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
||||
this.auditLogger = auditLogger;
|
||||
fieldAces.setAccessible(true);
|
||||
fieldAcl.setAccessible(true);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
private String computeRepeatingSql(String repeatingSql, int requiredRepetitions) {
|
||||
assert requiredRepetitions > 0 : "requiredRepetitions must be > 0";
|
||||
private static String computeRepeatingSql(String repeatingSql, int requiredRepetitions) {
|
||||
Assert.isTrue(requiredRepetitions >= 1, "Must be => 1");
|
||||
|
||||
final String startSql = selectClause;
|
||||
String startSql = "select acl_object_identity.object_id_identity, "
|
||||
+ "acl_entry.ace_order, "
|
||||
+ "acl_object_identity.id as acl_id, "
|
||||
+ "acl_object_identity.parent_object, "
|
||||
+ "acl_object_identity.entries_inheriting, "
|
||||
+ "acl_entry.id as ace_id, "
|
||||
+ "acl_entry.mask, "
|
||||
+ "acl_entry.granting, "
|
||||
+ "acl_entry.audit_success, "
|
||||
+ "acl_entry.audit_failure, "
|
||||
+ "acl_sid.principal as ace_principal, "
|
||||
+ "acl_sid.sid as ace_sid, "
|
||||
+ "acli_sid.principal as acl_principal, "
|
||||
+ "acli_sid.sid as acl_sid, "
|
||||
+ "acl_class.class "
|
||||
+ "from acl_object_identity "
|
||||
+ "left join acl_sid acli_sid on acli_sid.id = acl_object_identity.owner_sid "
|
||||
+ "left join acl_class on acl_class.id = acl_object_identity.object_id_class "
|
||||
+ "left join acl_entry on acl_object_identity.id = acl_entry.acl_object_identity "
|
||||
+ "left join acl_sid on acl_entry.sid = acl_sid.id "
|
||||
+ "where ( ";
|
||||
|
||||
final String endSql = orderByClause;
|
||||
String endSql = ") order by acl_object_identity.object_id_identity"
|
||||
+ " asc, acl_entry.ace_order asc";
|
||||
|
||||
StringBuilder sqlStringBldr =
|
||||
new StringBuilder(startSql.length() + endSql.length() + requiredRepetitions * (repeatingSql.length() + 4));
|
||||
sqlStringBldr.append(startSql);
|
||||
StringBuffer sqlStringBuffer = new StringBuffer();
|
||||
sqlStringBuffer.append(startSql);
|
||||
|
||||
for (int i = 1; i <= requiredRepetitions; i++) {
|
||||
sqlStringBldr.append(repeatingSql);
|
||||
sqlStringBuffer.append(repeatingSql);
|
||||
|
||||
if (i != requiredRepetitions) {
|
||||
sqlStringBldr.append(" or ");
|
||||
sqlStringBuffer.append(" or ");
|
||||
}
|
||||
}
|
||||
|
||||
sqlStringBldr.append(endSql);
|
||||
sqlStringBuffer.append(endSql);
|
||||
|
||||
return sqlStringBldr.toString();
|
||||
return sqlStringBuffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,8 +148,11 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
* @param inputMap the unconverted <code>AclImpl</code>s
|
||||
* @param currentIdentity the current<code>Acl</code> that we wish to convert (this may be
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IllegalStateException DOCUMENT ME!
|
||||
*/
|
||||
private AclImpl convert(Map<Long,AclImpl> inputMap, Long currentIdentity) {
|
||||
private AclImpl convert(Map inputMap, Long currentIdentity) {
|
||||
Assert.notEmpty(inputMap, "InputMap required");
|
||||
Assert.notNull(currentIdentity, "CurrentIdentity required");
|
||||
|
||||
@@ -203,191 +175,151 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
auditLogger, parent, null, inputAcl.isEntriesInheriting(), inputAcl.getOwner());
|
||||
|
||||
// Copy the "aces" from the input to the destination
|
||||
|
||||
// Obtain the "aces" from the input ACL
|
||||
List<AccessControlEntryImpl> aces = readAces(inputAcl);
|
||||
|
||||
// Create a list in which to store the "aces" for the "result" AclImpl instance
|
||||
List<AccessControlEntryImpl> acesNew = new ArrayList<AccessControlEntryImpl>();
|
||||
|
||||
// Iterate over the "aces" input and replace each nested AccessControlEntryImpl.getAcl() with the new "result" AclImpl instance
|
||||
// This ensures StubAclParent instances are removed, as per SEC-951
|
||||
for (AccessControlEntryImpl ace : aces) {
|
||||
setAclOnAce(ace, result);
|
||||
acesNew.add(ace);
|
||||
}
|
||||
|
||||
// Finally, now that the "aces" have been converted to have the "result" AclImpl instance, modify the "result" AclImpl instance
|
||||
setAces(result, acesNew);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<AccessControlEntryImpl> readAces(AclImpl acl) {
|
||||
Field fieldAces = FieldUtils.getField(AclImpl.class, "aces");
|
||||
Field fieldAcl = FieldUtils.getField(AccessControlEntryImpl.class, "acl");
|
||||
|
||||
try {
|
||||
return (List<AccessControlEntryImpl>) fieldAces.get(acl);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException("Could not obtain AclImpl.aces field", e);
|
||||
}
|
||||
}
|
||||
fieldAces.setAccessible(true);
|
||||
fieldAcl.setAccessible(true);
|
||||
|
||||
private void setAclOnAce(AccessControlEntryImpl ace, AclImpl acl) {
|
||||
try {
|
||||
fieldAcl.set(ace, acl);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException("Could not or set AclImpl on AccessControlEntryImpl fields", e);
|
||||
}
|
||||
}
|
||||
// Obtain the "aces" from the input ACL
|
||||
Iterator i = ((List) fieldAces.get(inputAcl)).iterator();
|
||||
|
||||
private void setAces(AclImpl acl, List<AccessControlEntryImpl> aces) {
|
||||
try {
|
||||
fieldAces.set(acl, aces);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException("Could not set AclImpl entries", e);
|
||||
}
|
||||
}
|
||||
// Create a list in which to store the "aces" for the "result" AclImpl instance
|
||||
List acesNew = new ArrayList();
|
||||
|
||||
/**
|
||||
* Locates the primary key IDs specified in "findNow", adding AclImpl instances with StubAclParents to the
|
||||
* "acls" Map.
|
||||
*
|
||||
* @param acls the AclImpls (with StubAclParents)
|
||||
* @param findNow Long-based primary keys to retrieve
|
||||
* @param sids
|
||||
*/
|
||||
private void lookupPrimaryKeys(final Map<Serializable, Acl> acls, final Set<Long> findNow, final List<Sid> sids) {
|
||||
Assert.notNull(acls, "ACLs are required");
|
||||
Assert.notEmpty(findNow, "Items to find now required");
|
||||
|
||||
String sql = computeRepeatingSql(lookupPrimaryKeysWhereClause, findNow.size());
|
||||
|
||||
Set<Long> parentsToLookup = jdbcTemplate.query(sql,
|
||||
new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
int i = 0;
|
||||
|
||||
for (Long toFind : findNow) {
|
||||
i++;
|
||||
ps.setLong(i, toFind);
|
||||
}
|
||||
}
|
||||
}, new ProcessResultSet(acls, sids));
|
||||
|
||||
// Lookup the parents, now that our JdbcTemplate has released the database connection (SEC-547)
|
||||
if (parentsToLookup.size() > 0) {
|
||||
lookupPrimaryKeys(acls, parentsToLookup, sids);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main method.
|
||||
* <p>
|
||||
* WARNING: This implementation completely disregards the "sids" argument! Every item in the cache is expected to
|
||||
* contain all SIDs. If you have serious performance needs (e.g. a very large number of
|
||||
* SIDs per object identity), you'll probably want to develop a custom {@link LookupStrategy} implementation
|
||||
* instead.
|
||||
* <p>
|
||||
* The implementation works in batch sizes specified by {@link #batchSize}.
|
||||
*
|
||||
* @param objects the identities to lookup (required)
|
||||
* @param sids the SIDs for which identities are required (ignored by this implementation)
|
||||
*
|
||||
* @return a <tt>Map</tt> where keys represent the {@link ObjectIdentity} of the located {@link Acl} and values
|
||||
* are the located {@link Acl} (never <tt>null</tt> although some entries may be missing; this method
|
||||
* should not throw {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used
|
||||
* to automatically create entries if required)
|
||||
*/
|
||||
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) {
|
||||
Assert.isTrue(batchSize >= 1, "BatchSize must be >= 1");
|
||||
Assert.notEmpty(objects, "Objects to lookup required");
|
||||
|
||||
// Map<ObjectIdentity,Acl>
|
||||
Map<ObjectIdentity, Acl> result = new HashMap<ObjectIdentity, Acl>(); // contains FULLY loaded Acl objects
|
||||
|
||||
Set<ObjectIdentity> currentBatchToLoad = new HashSet<ObjectIdentity>(); // contains ObjectIdentitys
|
||||
|
||||
for (int i = 0; i < objects.size(); i++) {
|
||||
boolean aclFound = false;
|
||||
|
||||
// Check we don't already have this ACL in the results
|
||||
if (result.containsKey(objects.get(i))) {
|
||||
aclFound = true;
|
||||
}
|
||||
|
||||
// Check cache for the present ACL entry
|
||||
if (!aclFound) {
|
||||
Acl acl = aclCache.getFromCache(objects.get(i));
|
||||
|
||||
// Ensure any cached element supports all the requested SIDs
|
||||
// (they should always, as our base impl doesn't filter on SID)
|
||||
if (acl != null) {
|
||||
if (acl.isSidLoaded(sids)) {
|
||||
result.put(acl.getObjectIdentity(), acl);
|
||||
aclFound = true;
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"Error: SID-filtered element detected when implementation does not perform SID filtering "
|
||||
+ "- have you added something to the cache manually?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load the ACL from the database
|
||||
if (!aclFound) {
|
||||
currentBatchToLoad.add(objects.get(i));
|
||||
}
|
||||
|
||||
// Is it time to load from JDBC the currentBatchToLoad?
|
||||
if ((currentBatchToLoad.size() == this.batchSize) || ((i + 1) == objects.size())) {
|
||||
if (currentBatchToLoad.size() > 0) {
|
||||
Map<ObjectIdentity, Acl> loadedBatch = lookupObjectIdentities(currentBatchToLoad.toArray(new ObjectIdentity[] {}), sids);
|
||||
|
||||
// Add loaded batch (all elements 100% initialized) to results
|
||||
result.putAll(loadedBatch);
|
||||
|
||||
// Add the loaded batch to the cache
|
||||
Iterator<Acl> loadedAclIterator = loadedBatch.values().iterator();
|
||||
|
||||
while (loadedAclIterator.hasNext()) {
|
||||
aclCache.putInCache((AclImpl) loadedAclIterator.next());
|
||||
}
|
||||
|
||||
currentBatchToLoad.clear();
|
||||
}
|
||||
// Iterate over the "aces" input and replace each nested AccessControlEntryImpl.getAcl() with the new "result" AclImpl instance
|
||||
// This ensures StubAclParent instances are removed, as per SEC-951
|
||||
while(i.hasNext()) {
|
||||
AccessControlEntryImpl ace = (AccessControlEntryImpl) i.next();
|
||||
fieldAcl.set(ace, result);
|
||||
acesNew.add(ace);
|
||||
}
|
||||
|
||||
// Finally, now that the "aces" have been converted to have the "result" AclImpl instance, modify the "result" AclImpl instance
|
||||
fieldAces.set(result, acesNew);
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException("Could not obtain or set AclImpl or AccessControlEntryImpl fields");
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a batch of <code>ObjectIdentity</code>s directly from the database.
|
||||
* <p>
|
||||
* The caller is responsible for optimization issues, such as selecting the identities to lookup, ensuring the
|
||||
* cache doesn't contain them already, and adding the returned elements to the cache etc.
|
||||
* <p>
|
||||
* This subclass is required to return fully valid <code>Acl</code>s, including properly-configured
|
||||
* parent ACLs.
|
||||
* Accepts the current <code>ResultSet</code> row, and converts it into an <code>AclImpl</code> that
|
||||
* contains a <code>StubAclParent</code>
|
||||
*
|
||||
* @param acls the Map we should add the converted Acl to
|
||||
* @param rs the ResultSet focused on a current row
|
||||
*
|
||||
* @throws SQLException if something goes wrong converting values
|
||||
* @throws IllegalStateException DOCUMENT ME!
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<ObjectIdentity, Acl> lookupObjectIdentities(final ObjectIdentity[] objectIdentities, List<Sid> sids) {
|
||||
private void convertCurrentResultIntoObject(Map acls, ResultSet rs)
|
||||
throws SQLException {
|
||||
Long id = new Long(rs.getLong("acl_id"));
|
||||
|
||||
// If we already have an ACL for this ID, just create the ACE
|
||||
AclImpl acl = (AclImpl) acls.get(id);
|
||||
|
||||
if (acl == null) {
|
||||
// Make an AclImpl and pop it into the Map
|
||||
ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString("class"),
|
||||
new Long(rs.getLong("object_id_identity")));
|
||||
|
||||
Acl parentAcl = null;
|
||||
long parentAclId = rs.getLong("parent_object");
|
||||
|
||||
if (parentAclId != 0) {
|
||||
parentAcl = new StubAclParent(new Long(parentAclId));
|
||||
}
|
||||
|
||||
boolean entriesInheriting = rs.getBoolean("entries_inheriting");
|
||||
Sid owner;
|
||||
|
||||
if (rs.getBoolean("acl_principal")) {
|
||||
owner = new PrincipalSid(rs.getString("acl_sid"));
|
||||
} else {
|
||||
owner = new GrantedAuthoritySid(rs.getString("acl_sid"));
|
||||
}
|
||||
|
||||
acl = new AclImpl(objectIdentity, id, aclAuthorizationStrategy, auditLogger, parentAcl, null,
|
||||
entriesInheriting, owner);
|
||||
acls.put(id, acl);
|
||||
}
|
||||
|
||||
// Add an extra ACE to the ACL (ORDER BY maintains the ACE list order)
|
||||
// It is permissable to have no ACEs in an ACL (which is detected by a null ACE_SID)
|
||||
if (rs.getString("ace_sid") != null) {
|
||||
Long aceId = new Long(rs.getLong("ace_id"));
|
||||
Sid recipient;
|
||||
|
||||
if (rs.getBoolean("ace_principal")) {
|
||||
recipient = new PrincipalSid(rs.getString("ace_sid"));
|
||||
} else {
|
||||
recipient = new GrantedAuthoritySid(rs.getString("ace_sid"));
|
||||
}
|
||||
|
||||
int mask = rs.getInt("mask");
|
||||
Permission permission = convertMaskIntoPermission(mask);
|
||||
boolean granting = rs.getBoolean("granting");
|
||||
boolean auditSuccess = rs.getBoolean("audit_success");
|
||||
boolean auditFailure = rs.getBoolean("audit_failure");
|
||||
|
||||
AccessControlEntryImpl ace = new AccessControlEntryImpl(aceId, acl, recipient, permission, granting,
|
||||
auditSuccess, auditFailure);
|
||||
|
||||
Field acesField = FieldUtils.getField(AclImpl.class, "aces");
|
||||
List aces;
|
||||
|
||||
try {
|
||||
acesField.setAccessible(true);
|
||||
aces = (List) acesField.get(acl);
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException("Could not obtain AclImpl.ace field: cause[" + ex.getMessage() + "]");
|
||||
}
|
||||
|
||||
// Add the ACE if it doesn't already exist in the ACL.aces field
|
||||
if (!aces.contains(ace)) {
|
||||
aces.add(ace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Permission convertMaskIntoPermission(int mask) {
|
||||
return BasePermission.buildFromMask(mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a batch of <code>ObjectIdentity</code>s directly from the database.<p>The caller is responsible
|
||||
* for optimization issues, such as selecting the identities to lookup, ensuring the cache doesn't contain them
|
||||
* already, and adding the returned elements to the cache etc.</p>
|
||||
* <p>This subclass is required to return fully valid <code>Acl</code>s, including properly-configured
|
||||
* parent ACLs.</p>
|
||||
*
|
||||
* @param objectIdentities DOCUMENT ME!
|
||||
* @param sids DOCUMENT ME!
|
||||
*
|
||||
* @return DOCUMENT ME!
|
||||
*/
|
||||
private Map lookupObjectIdentities(final ObjectIdentity[] objectIdentities, Sid[] sids) {
|
||||
Assert.notEmpty(objectIdentities, "Must provide identities to lookup");
|
||||
|
||||
final Map acls = new HashMap(); // contains Acls with StubAclParents
|
||||
|
||||
// Make the "acls" map contain all requested objectIdentities
|
||||
// (including markers to each parent in the hierarchy)
|
||||
String sql = computeRepeatingSql(lookupObjectIdentitiesWhereClause ,
|
||||
String sql = computeRepeatingSql("(acl_object_identity.object_id_identity = ? and acl_class.class = ?)",
|
||||
objectIdentities.length);
|
||||
|
||||
Set parentsToLookup = (Set) jdbcTemplate.query(sql,
|
||||
new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
public void setValues(PreparedStatement ps)
|
||||
throws SQLException {
|
||||
for (int i = 0; i < objectIdentities.length; i++) {
|
||||
// Determine prepared statement values for this iteration
|
||||
String javaType = objectIdentities[i].getType();
|
||||
String javaType = objectIdentities[i].getJavaType().getName();
|
||||
|
||||
// No need to check for nulls, as guaranteed non-null by ObjectIdentity.getIdentifier() interface contract
|
||||
String identifier = objectIdentities[i].getIdentifier().toString();
|
||||
@@ -399,14 +331,14 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
}
|
||||
}
|
||||
}, new ProcessResultSet(acls, sids));
|
||||
|
||||
|
||||
// Lookup the parents, now that our JdbcTemplate has released the database connection (SEC-547)
|
||||
if (parentsToLookup.size() > 0) {
|
||||
lookupPrimaryKeys(acls, parentsToLookup, sids);
|
||||
lookupPrimaryKeys(acls, parentsToLookup, sids);
|
||||
}
|
||||
|
||||
// Finally, convert our "acls" containing StubAclParents into true Acls
|
||||
Map<ObjectIdentity, Acl> resultMap = new HashMap<ObjectIdentity, Acl>();
|
||||
Map resultMap = new HashMap();
|
||||
Iterator iter = acls.values().iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
@@ -421,48 +353,129 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the primary key IDs specified in "findNow", adding AclImpl instances with StubAclParents to the
|
||||
* "acls" Map.
|
||||
*
|
||||
* @param acls the AclImpls (with StubAclParents)
|
||||
* @param findNow Long-based primary keys to retrieve
|
||||
* @param sids DOCUMENT ME!
|
||||
*/
|
||||
private void lookupPrimaryKeys(final Map acls, final Set findNow, final Sid[] sids) {
|
||||
Assert.notNull(acls, "ACLs are required");
|
||||
Assert.notEmpty(findNow, "Items to find now required");
|
||||
|
||||
String sql = computeRepeatingSql("(acl_object_identity.id = ?)", findNow.size());
|
||||
|
||||
Set parentsToLookup = (Set) jdbcTemplate.query(sql,
|
||||
new PreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps)
|
||||
throws SQLException {
|
||||
Iterator iter = findNow.iterator();
|
||||
int i = 0;
|
||||
|
||||
while (iter.hasNext()) {
|
||||
i++;
|
||||
ps.setLong(i, ((Long) iter.next()).longValue());
|
||||
}
|
||||
}
|
||||
}, new ProcessResultSet(acls, sids));
|
||||
|
||||
// Lookup the parents, now that our JdbcTemplate has released the database connection (SEC-547)
|
||||
if (parentsToLookup.size() > 0) {
|
||||
lookupPrimaryKeys(acls, parentsToLookup, sids);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main method.<p>WARNING: This implementation completely disregards the "sids" argument! Every item
|
||||
* in the cache is expected to contain all SIDs. If you have serious performance needs (eg a very large number of
|
||||
* SIDs per object identity), you'll probably want to develop a custom {@link LookupStrategy} implementation
|
||||
* instead.</p>
|
||||
* <p>The implementation works in batch sizes specfied by {@link #batchSize}.</p>
|
||||
*
|
||||
* @param objects the identities to lookup (required)
|
||||
* @param sids the SIDs for which identities are required (ignored by this implementation)
|
||||
*
|
||||
* @return a <tt>Map</tt> where keys represent the {@link ObjectIdentity} of the located {@link Acl} and values
|
||||
* are the located {@link Acl} (never <tt>null</tt> although some entries may be missing; this method
|
||||
* should not throw {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used
|
||||
* to automatically create entries if required)
|
||||
*/
|
||||
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids) {
|
||||
Assert.isTrue(batchSize >= 1, "BatchSize must be >= 1");
|
||||
Assert.notEmpty(objects, "Objects to lookup required");
|
||||
|
||||
// Map<ObjectIdentity,Acl>
|
||||
Map result = new HashMap(); // contains FULLY loaded Acl objects
|
||||
|
||||
Set currentBatchToLoad = new HashSet(); // contains ObjectIdentitys
|
||||
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
boolean aclFound = false;
|
||||
|
||||
// Check we don't already have this ACL in the results
|
||||
if (result.containsKey(objects[i])) {
|
||||
aclFound = true;
|
||||
}
|
||||
|
||||
// Check cache for the present ACL entry
|
||||
if (!aclFound) {
|
||||
Acl acl = aclCache.getFromCache(objects[i]);
|
||||
|
||||
// Ensure any cached element supports all the requested SIDs
|
||||
// (they should always, as our base impl doesn't filter on SID)
|
||||
if (acl != null) {
|
||||
if (acl.isSidLoaded(sids)) {
|
||||
result.put(acl.getObjectIdentity(), acl);
|
||||
aclFound = true;
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"Error: SID-filtered element detected when implementation does not perform SID filtering "
|
||||
+ "- have you added something to the cache manually?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load the ACL from the database
|
||||
if (!aclFound) {
|
||||
currentBatchToLoad.add(objects[i]);
|
||||
}
|
||||
|
||||
// Is it time to load from JDBC the currentBatchToLoad?
|
||||
if ((currentBatchToLoad.size() == this.batchSize) || ((i + 1) == objects.length)) {
|
||||
if (currentBatchToLoad.size() > 0) {
|
||||
Map loadedBatch = lookupObjectIdentities((ObjectIdentity[]) currentBatchToLoad.toArray(new ObjectIdentity[] {}), sids);
|
||||
|
||||
// Add loaded batch (all elements 100% initialized) to results
|
||||
result.putAll(loadedBatch);
|
||||
|
||||
// Add the loaded batch to the cache
|
||||
Iterator loadedAclIterator = loadedBatch.values().iterator();
|
||||
|
||||
while (loadedAclIterator.hasNext()) {
|
||||
aclCache.putInCache((AclImpl) loadedAclIterator.next());
|
||||
}
|
||||
|
||||
currentBatchToLoad.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setBatchSize(int batchSize) {
|
||||
this.batchSize = batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SQL for the select clause. If customizing in order to modify
|
||||
* column names, schema etc, the other SQL customization fields must also be set to match.
|
||||
*
|
||||
* @param selectClause the select clause, which defaults to {@link #DEFAULT_SELECT_CLAUSE}.
|
||||
*/
|
||||
public void setSelectClause(String selectClause) {
|
||||
this.selectClause = selectClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SQL for the where clause used in the <tt>lookupPrimaryKey</tt> method.
|
||||
*/
|
||||
public void setLookupPrimaryKeysWhereClause(String lookupPrimaryKeysWhereClause) {
|
||||
this.lookupPrimaryKeysWhereClause = lookupPrimaryKeysWhereClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SQL for the where clause used in the <tt>lookupObjectIdentities</tt> method.
|
||||
*/
|
||||
public void setLookupObjectIdentitiesWhereClause(String lookupObjectIdentitiesWhereClause) {
|
||||
this.lookupObjectIdentitiesWhereClause = lookupObjectIdentitiesWhereClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SQL for the "order by" clause used in both queries.
|
||||
*/
|
||||
public void setOrderByClause(String orderByClause) {
|
||||
this.orderByClause = orderByClause;
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class ProcessResultSet implements ResultSetExtractor<Set<Long>> {
|
||||
private Map<Serializable, Acl> acls;
|
||||
private List<Sid> sids;
|
||||
private class ProcessResultSet implements ResultSetExtractor {
|
||||
private Map acls;
|
||||
private Sid[] sids;
|
||||
|
||||
public ProcessResultSet(Map<Serializable, Acl> acls, List<Sid> sids) {
|
||||
public ProcessResultSet(Map acls, Sid[] sids) {
|
||||
Assert.notNull(acls, "ACLs cannot be null");
|
||||
this.acls = acls;
|
||||
this.sids = sids; // can be null
|
||||
@@ -479,8 +492,8 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
* @throws SQLException
|
||||
* @throws DataAccessException
|
||||
*/
|
||||
public Set<Long> extractData(ResultSet rs) throws SQLException, DataAccessException {
|
||||
Set<Long> parentIdsToLookup = new HashSet<Long>(); // Set of parent_id Longs
|
||||
public Object extractData(ResultSet rs) throws SQLException, DataAccessException {
|
||||
Set parentIdsToLookup = new HashSet(); // Set of parent_id Longs
|
||||
|
||||
while (rs.next()) {
|
||||
// Convert current row into an Acl (albeit with a StubAclParent)
|
||||
@@ -508,82 +521,9 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
// Return the parents left to lookup to the caller
|
||||
// Return the parents left to lookup to the calller
|
||||
return parentIdsToLookup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts the current <code>ResultSet</code> row, and converts it into an <code>AclImpl</code> that
|
||||
* contains a <code>StubAclParent</code>
|
||||
*
|
||||
* @param acls the Map we should add the converted Acl to
|
||||
* @param rs the ResultSet focused on a current row
|
||||
*
|
||||
* @throws SQLException if something goes wrong converting values
|
||||
*/
|
||||
private void convertCurrentResultIntoObject(Map<Serializable, Acl> acls, ResultSet rs) throws SQLException {
|
||||
Long id = new Long(rs.getLong("acl_id"));
|
||||
|
||||
// If we already have an ACL for this ID, just create the ACE
|
||||
Acl acl = acls.get(id);
|
||||
|
||||
if (acl == null) {
|
||||
// Make an AclImpl and pop it into the Map
|
||||
ObjectIdentity objectIdentity = new ObjectIdentityImpl(rs.getString("class"),
|
||||
Long.valueOf(rs.getLong("object_id_identity")));
|
||||
|
||||
Acl parentAcl = null;
|
||||
long parentAclId = rs.getLong("parent_object");
|
||||
|
||||
if (parentAclId != 0) {
|
||||
parentAcl = new StubAclParent(Long.valueOf(parentAclId));
|
||||
}
|
||||
|
||||
boolean entriesInheriting = rs.getBoolean("entries_inheriting");
|
||||
Sid owner;
|
||||
|
||||
if (rs.getBoolean("acl_principal")) {
|
||||
owner = new PrincipalSid(rs.getString("acl_sid"));
|
||||
} else {
|
||||
owner = new GrantedAuthoritySid(rs.getString("acl_sid"));
|
||||
}
|
||||
|
||||
acl = new AclImpl(objectIdentity, id, aclAuthorizationStrategy, auditLogger, parentAcl, null,
|
||||
entriesInheriting, owner);
|
||||
|
||||
acls.put(id, acl);
|
||||
}
|
||||
|
||||
// Add an extra ACE to the ACL (ORDER BY maintains the ACE list order)
|
||||
// It is permissible to have no ACEs in an ACL (which is detected by a null ACE_SID)
|
||||
if (rs.getString("ace_sid") != null) {
|
||||
Long aceId = new Long(rs.getLong("ace_id"));
|
||||
Sid recipient;
|
||||
|
||||
if (rs.getBoolean("ace_principal")) {
|
||||
recipient = new PrincipalSid(rs.getString("ace_sid"));
|
||||
} else {
|
||||
recipient = new GrantedAuthoritySid(rs.getString("ace_sid"));
|
||||
}
|
||||
|
||||
int mask = rs.getInt("mask");
|
||||
Permission permission = permissionFactory.buildFromMask(mask);
|
||||
boolean granting = rs.getBoolean("granting");
|
||||
boolean auditSuccess = rs.getBoolean("audit_success");
|
||||
boolean auditFailure = rs.getBoolean("audit_failure");
|
||||
|
||||
AccessControlEntryImpl ace = new AccessControlEntryImpl(aceId, acl, recipient, permission, granting,
|
||||
auditSuccess, auditFailure);
|
||||
|
||||
//Field acesField = FieldUtils.getField(AclImpl.class, "aces");
|
||||
List<AccessControlEntryImpl> aces = readAces((AclImpl)acl);
|
||||
|
||||
// Add the ACE if it doesn't already exist in the ACL.aces field
|
||||
if (!aces.contains(ace)) {
|
||||
aces.add(ace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class StubAclParent implements Acl {
|
||||
@@ -593,7 +533,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public List<AccessControlEntry> getEntries() {
|
||||
public AccessControlEntry[] getEntries() {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
|
||||
@@ -617,12 +557,12 @@ public final class BasicLookupStrategy implements LookupStrategy {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
|
||||
public boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
|
||||
public boolean isGranted(Permission[] permission, Sid[] sids, boolean administrativeMode)
|
||||
throws NotFoundException, UnloadedSidException {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
|
||||
public boolean isSidLoaded(List<Sid> sids) {
|
||||
public boolean isSidLoaded(Sid[] sids) {
|
||||
throw new UnsupportedOperationException("Stub only");
|
||||
}
|
||||
}
|
||||
|
||||
+17
-23
@@ -12,7 +12,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.domain;
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@@ -20,16 +20,18 @@ import net.sf.ehcache.CacheException;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.Element;
|
||||
|
||||
import org.springframework.security.acls.model.AclCache;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
|
||||
import org.springframework.security.acls.domain.AclImpl;
|
||||
import org.springframework.security.acls.domain.AuditLogger;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Simple implementation of {@link AclCache} that delegates to EH-CACHE.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Designed to handle the transient fields in {@link AclImpl}. Note that this implementation assumes all
|
||||
* {@link AclImpl} instances share the same {@link AuditLogger} and {@link AclAuthorizationStrategy} instance.
|
||||
@@ -92,7 +94,7 @@ public class EhCacheBasedAclCache implements AclCache {
|
||||
return initializeTransientFields((MutableAcl)element.getValue());
|
||||
}
|
||||
|
||||
public MutableAcl getFromCache(Serializable pk) {
|
||||
public MutableAcl getFromCache(Serializable pk) {
|
||||
Assert.notNull(pk, "Primary key (identifier) required");
|
||||
|
||||
Element element = null;
|
||||
@@ -115,11 +117,11 @@ public class EhCacheBasedAclCache implements AclCache {
|
||||
|
||||
if (this.aclAuthorizationStrategy == null) {
|
||||
if (acl instanceof AclImpl) {
|
||||
this.aclAuthorizationStrategy = (AclAuthorizationStrategy) FieldUtils.getProtectedFieldValue("aclAuthorizationStrategy", acl);
|
||||
this.auditLogger = (AuditLogger) FieldUtils.getProtectedFieldValue("auditLogger", acl);
|
||||
this.aclAuthorizationStrategy = (AclAuthorizationStrategy) FieldUtils.getProtectedFieldValue("aclAuthorizationStrategy", acl);
|
||||
this.auditLogger = (AuditLogger) FieldUtils.getProtectedFieldValue("auditLogger", acl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((acl.getParentAcl() != null) && (acl.getParentAcl() instanceof MutableAcl)) {
|
||||
putInCache((MutableAcl) acl.getParentAcl());
|
||||
}
|
||||
@@ -129,18 +131,10 @@ public class EhCacheBasedAclCache implements AclCache {
|
||||
}
|
||||
|
||||
private MutableAcl initializeTransientFields(MutableAcl value) {
|
||||
if (value instanceof AclImpl) {
|
||||
FieldUtils.setProtectedFieldValue("aclAuthorizationStrategy", value, this.aclAuthorizationStrategy);
|
||||
FieldUtils.setProtectedFieldValue("auditLogger", value, this.auditLogger);
|
||||
}
|
||||
|
||||
if (value.getParentAcl() != null) {
|
||||
initializeTransientFields((MutableAcl) value.getParentAcl());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public void clearCache() {
|
||||
cache.removeAll();
|
||||
}
|
||||
if (value instanceof AclImpl) {
|
||||
FieldUtils.setProtectedFieldValue("aclAuthorizationStrategy", value, this.aclAuthorizationStrategy);
|
||||
FieldUtils.setProtectedFieldValue("auditLogger", value, this.auditLogger);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -14,31 +14,35 @@
|
||||
*/
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AclService;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
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.Sid;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Simple JDBC-based implementation of <code>AclService</code>.
|
||||
* <p>
|
||||
* Requires the "dirty" flags in {@link org.springframework.security.acls.domain.AclImpl} and
|
||||
* Requires the "dirty" flags in {@link org.springframework.security.acls.domain.AclImpl} and
|
||||
* {@link org.springframework.security.acls.domain.AccessControlEntryImpl} to be set, so that the implementation can
|
||||
* detect changed parameters easily.
|
||||
*
|
||||
@@ -49,7 +53,7 @@ public class JdbcAclService implements AclService {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
protected static final Log log = LogFactory.getLog(JdbcAclService.class);
|
||||
private static final String DEFAULT_SELECT_ACL_WITH_PARENT_SQL = "select obj.object_id_identity as obj_id, class.class as class "
|
||||
private static final String selectAclObjectWithParent = "select obj.object_id_identity as obj_id, class.class as class "
|
||||
+ "from acl_object_identity obj, acl_object_identity parent, acl_class class "
|
||||
+ "where obj.parent_object = parent.id and obj.object_id_class = class.id "
|
||||
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
|
||||
@@ -59,7 +63,6 @@ public class JdbcAclService implements AclService {
|
||||
|
||||
protected JdbcTemplate jdbcTemplate;
|
||||
private LookupStrategy lookupStrategy;
|
||||
private String findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
@@ -72,11 +75,12 @@ public class JdbcAclService implements AclService {
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
|
||||
Object[] args = {parentIdentity.getIdentifier(), parentIdentity.getType()};
|
||||
List<ObjectIdentity> objects = jdbcTemplate.query(findChildrenSql, args,
|
||||
new RowMapper<ObjectIdentity>() {
|
||||
public ObjectIdentity mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
public ObjectIdentity[] findChildren(ObjectIdentity parentIdentity) {
|
||||
Object[] args = {parentIdentity.getIdentifier(), parentIdentity.getJavaType().getName()};
|
||||
List objects = jdbcTemplate.query(selectAclObjectWithParent, args,
|
||||
new RowMapper() {
|
||||
public Object mapRow(ResultSet rs, int rowNum)
|
||||
throws SQLException {
|
||||
String javaType = rs.getString("class");
|
||||
Long identifier = new Long(rs.getLong("obj_id"));
|
||||
|
||||
@@ -85,14 +89,14 @@ public class JdbcAclService implements AclService {
|
||||
});
|
||||
|
||||
if (objects.size() == 0) {
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
return objects;
|
||||
|
||||
return (ObjectIdentityImpl[]) objects.toArray(new ObjectIdentityImpl[objects.size()]);
|
||||
}
|
||||
|
||||
public Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException {
|
||||
Map<ObjectIdentity, Acl> map = readAclsById(Arrays.asList(object), sids);
|
||||
public Acl readAclById(ObjectIdentity object, Sid[] sids) throws NotFoundException {
|
||||
Map map = readAclsById(new ObjectIdentity[] {object}, sids);
|
||||
Assert.isTrue(map.containsKey(object), "There should have been an Acl entry for ObjectIdentity " + object);
|
||||
|
||||
return (Acl) map.get(object);
|
||||
@@ -102,30 +106,21 @@ public class JdbcAclService implements AclService {
|
||||
return readAclById(object, null);
|
||||
}
|
||||
|
||||
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects) throws NotFoundException {
|
||||
public Map readAclsById(ObjectIdentity[] objects) throws NotFoundException {
|
||||
return readAclsById(objects, null);
|
||||
}
|
||||
|
||||
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) throws NotFoundException {
|
||||
Map<ObjectIdentity, Acl> result = lookupStrategy.readAclsById(objects, sids);
|
||||
|
||||
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids) throws NotFoundException {
|
||||
Map result = lookupStrategy.readAclsById(objects, sids);
|
||||
|
||||
// Check every requested object identity was found (throw NotFoundException if needed)
|
||||
for (int i = 0; i < objects.size(); i++) {
|
||||
if (!result.containsKey(objects.get(i))) {
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
if (!result.containsKey(objects[i])) {
|
||||
throw new NotFoundException("Unable to find ACL information for object identity '"
|
||||
+ objects.get(i) + "'");
|
||||
+ objects[i].toString() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows customization of the SQL query used to find child object identities.
|
||||
*
|
||||
* @param findChildrenSql
|
||||
*/
|
||||
public void setFindChildrenQuery(String findChildrenSql) {
|
||||
this.findChildrenSql = findChildrenSql;
|
||||
}
|
||||
}
|
||||
|
||||
+122
-158
@@ -14,45 +14,44 @@
|
||||
*/
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AlreadyExistsException;
|
||||
import org.springframework.security.acls.ChildrenExistException;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.MutableAclService;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.domain.AccessControlEntryImpl;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.sid.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||
import org.springframework.security.acls.domain.AccessControlEntryImpl;
|
||||
import org.springframework.security.acls.domain.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.domain.PrincipalSid;
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AclCache;
|
||||
import org.springframework.security.acls.model.AlreadyExistsException;
|
||||
import org.springframework.security.acls.model.ChildrenExistException;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.MutableAclService;
|
||||
import org.springframework.security.acls.model.NotFoundException;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Provides a base JDBC implementation of {@link MutableAclService}.
|
||||
* <p>
|
||||
* The default settings are for HSQLDB. If you are using a different database you
|
||||
* will probably need to set the {@link #setSidIdentityQuery(String) sidIdentityQuery} and
|
||||
* {@link #setClassIdentityQuery(String) classIdentityQuery} properties appropriately. The other queries,
|
||||
* SQL inserts and updates can also be customized to accomodate schema variations, but must produce results
|
||||
* consistent with those expected by the defaults.
|
||||
* <p>
|
||||
* See the appendix of the Spring Security reference manual for more information on the expected schema
|
||||
* and how it is used. Information on using PostgreSQL is also included.
|
||||
* Provides a base implementation of {@link MutableAclService}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Johannes Zlattinger
|
||||
@@ -61,12 +60,12 @@ import org.springframework.util.Assert;
|
||||
public class JdbcMutableAclService extends JdbcAclService implements MutableAclService {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private boolean foreignKeysInDatabase = true;
|
||||
private boolean foreignKeysInDatabase = true;
|
||||
private AclCache aclCache;
|
||||
private String deleteEntryByObjectIdentityForeignKey = "delete from acl_entry where acl_object_identity=?";
|
||||
private String deleteObjectIdentityByPrimaryKey = "delete from acl_object_identity where id=?";
|
||||
private String classIdentityQuery = "call identity()";
|
||||
private String sidIdentityQuery = "call identity()";
|
||||
private String classIdentityQuery = "call identity()"; // should be overridden for postgres : select currval('acl_class_seq')
|
||||
private String sidIdentityQuery = "call identity()"; // should be overridden for postgres : select currval('acl_siq_seq')
|
||||
private String insertClass = "insert into acl_class (class) values (?)";
|
||||
private String insertEntry = "insert into acl_entry "
|
||||
+ "(acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure)"
|
||||
@@ -92,7 +91,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public MutableAcl createAcl(ObjectIdentity objectIdentity) throws AlreadyExistsException {
|
||||
public MutableAcl createAcl(ObjectIdentity objectIdentity)
|
||||
throws AlreadyExistsException {
|
||||
Assert.notNull(objectIdentity, "Object Identity required");
|
||||
|
||||
// Check this object identity hasn't already been persisted
|
||||
@@ -123,12 +123,14 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
jdbcTemplate.batchUpdate(insertEntry,
|
||||
new BatchPreparedStatementSetter() {
|
||||
public int getBatchSize() {
|
||||
return acl.getEntries().size();
|
||||
return acl.getEntries().length;
|
||||
}
|
||||
|
||||
public void setValues(PreparedStatement stmt, int i) throws SQLException {
|
||||
AccessControlEntry entry_ = acl.getEntries().get(i);
|
||||
public void setValues(PreparedStatement stmt, int i)
|
||||
throws SQLException {
|
||||
AccessControlEntry entry_ = (AccessControlEntry) Array.get(acl.getEntries(), i);
|
||||
Assert.isTrue(entry_ instanceof AccessControlEntryImpl, "Unknown ACE class");
|
||||
|
||||
AccessControlEntryImpl entry = (AccessControlEntryImpl) entry_;
|
||||
|
||||
stmt.setLong(1, ((Long) acl.getId()).longValue());
|
||||
@@ -151,8 +153,9 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
*/
|
||||
protected void createObjectIdentity(ObjectIdentity object, Sid owner) {
|
||||
Long sidId = createOrRetrieveSidPrimaryKey(owner, true);
|
||||
Long classId = createOrRetrieveClassPrimaryKey(object.getType(), true);
|
||||
jdbcTemplate.update(insertObjectIdentity, classId, object.getIdentifier(), sidId, Boolean.TRUE);
|
||||
Long classId = createOrRetrieveClassPrimaryKey(object.getJavaType(), true);
|
||||
jdbcTemplate.update(insertObjectIdentity,
|
||||
new Object[] {classId, object.getIdentifier().toString(), sidId, new Boolean(true)});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,21 +167,23 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
*
|
||||
* @return the primary key or null if not found
|
||||
*/
|
||||
protected Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate) {
|
||||
List<Long> classIds = jdbcTemplate.queryForList(selectClassPrimaryKey, new Object[] {type}, Long.class);
|
||||
protected Long createOrRetrieveClassPrimaryKey(Class clazz, boolean allowCreate) {
|
||||
List classIds = jdbcTemplate.queryForList(selectClassPrimaryKey, new Object[] {clazz.getName()}, Long.class);
|
||||
Long classId = null;
|
||||
|
||||
if (!classIds.isEmpty()) {
|
||||
return classIds.get(0);
|
||||
if (classIds.isEmpty()) {
|
||||
if (allowCreate) {
|
||||
classId = null;
|
||||
jdbcTemplate.update(insertClass, new Object[] {clazz.getName()});
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
|
||||
"Transaction must be running");
|
||||
classId = new Long(jdbcTemplate.queryForLong(classIdentityQuery));
|
||||
}
|
||||
} else {
|
||||
classId = (Long) classIds.iterator().next();
|
||||
}
|
||||
|
||||
if (allowCreate) {
|
||||
jdbcTemplate.update(insertClass, type);
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
|
||||
"Transaction must be running");
|
||||
return new Long(jdbcTemplate.queryForLong(classIdentityQuery));
|
||||
}
|
||||
|
||||
return null;
|
||||
return classId;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,64 +195,68 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
*
|
||||
* @return the primary key or null if not found
|
||||
*
|
||||
* @throws IllegalArgumentException if the <tt>Sid</tt> is not a recognized implementation.
|
||||
* @throws IllegalArgumentException DOCUMENT ME!
|
||||
*/
|
||||
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
|
||||
Assert.notNull(sid, "Sid required");
|
||||
|
||||
String sidName = null;
|
||||
boolean sidIsPrincipal = true;
|
||||
boolean principal = true;
|
||||
|
||||
if (sid instanceof PrincipalSid) {
|
||||
sidName = ((PrincipalSid) sid).getPrincipal();
|
||||
} else if (sid instanceof GrantedAuthoritySid) {
|
||||
sidName = ((GrantedAuthoritySid) sid).getGrantedAuthority();
|
||||
sidIsPrincipal = false;
|
||||
principal = false;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported implementation of Sid");
|
||||
}
|
||||
|
||||
List<Long> sidIds = jdbcTemplate.queryForList(selectSidPrimaryKey,
|
||||
new Object[] {Boolean.valueOf(sidIsPrincipal), sidName}, Long.class);
|
||||
List sidIds = jdbcTemplate.queryForList(selectSidPrimaryKey, new Object[] {new Boolean(principal), sidName},
|
||||
Long.class);
|
||||
Long sidId = null;
|
||||
|
||||
if (!sidIds.isEmpty()) {
|
||||
return sidIds.get(0);
|
||||
if (sidIds.isEmpty()) {
|
||||
if (allowCreate) {
|
||||
sidId = null;
|
||||
jdbcTemplate.update(insertSid, new Object[] {new Boolean(principal), sidName});
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
|
||||
"Transaction must be running");
|
||||
sidId = new Long(jdbcTemplate.queryForLong(sidIdentityQuery));
|
||||
}
|
||||
} else {
|
||||
sidId = (Long) sidIds.iterator().next();
|
||||
}
|
||||
|
||||
if (allowCreate) {
|
||||
jdbcTemplate.update(insertSid, new Object[] {Boolean.valueOf(sidIsPrincipal), sidName});
|
||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
|
||||
return new Long(jdbcTemplate.queryForLong(sidIdentityQuery));
|
||||
}
|
||||
|
||||
return null;
|
||||
return sidId;
|
||||
}
|
||||
|
||||
public void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren) throws ChildrenExistException {
|
||||
public void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren)
|
||||
throws ChildrenExistException {
|
||||
Assert.notNull(objectIdentity, "Object Identity required");
|
||||
Assert.notNull(objectIdentity.getIdentifier(), "Object Identity doesn't provide an identifier");
|
||||
|
||||
if (deleteChildren) {
|
||||
List<ObjectIdentity> children = findChildren(objectIdentity);
|
||||
if (children != null) {
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
deleteAcl(children.get(i), true);
|
||||
ObjectIdentity[] children = findChildren(objectIdentity);
|
||||
if (children != null) {
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
deleteAcl(children[i], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!foreignKeysInDatabase) {
|
||||
// We need to perform a manual verification for what a FK would normally do
|
||||
// We generally don't do this, in the interests of deadlock management
|
||||
List<ObjectIdentity> children = findChildren(objectIdentity);
|
||||
if (children != null) {
|
||||
throw new ChildrenExistException("Cannot delete '" + objectIdentity + "' (has " + children.size()
|
||||
if (!foreignKeysInDatabase) {
|
||||
// We need to perform a manual verification for what a FK would normally do
|
||||
// We generally don't do this, in the interests of deadlock management
|
||||
ObjectIdentity[] children = findChildren(objectIdentity);
|
||||
if (children != null) {
|
||||
throw new ChildrenExistException("Cannot delete '" + objectIdentity + "' (has " + children.length
|
||||
+ " children)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Long oidPrimaryKey = retrieveObjectIdentityPrimaryKey(objectIdentity);
|
||||
|
||||
|
||||
// Delete this ACL's ACEs in the acl_entry table
|
||||
deleteEntries(oidPrimaryKey);
|
||||
|
||||
@@ -264,15 +273,17 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
* @param oidPrimaryKey the rows in acl_entry to delete
|
||||
*/
|
||||
protected void deleteEntries(Long oidPrimaryKey) {
|
||||
jdbcTemplate.update(deleteEntryByObjectIdentityForeignKey,
|
||||
jdbcTemplate.update(deleteEntryByObjectIdentityForeignKey,
|
||||
new Object[] {oidPrimaryKey});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a single row from acl_object_identity that is associated with the presented ObjectIdentity primary key.
|
||||
*
|
||||
* <p>
|
||||
* We do not delete any entries from acl_class, even if no classes are using that class any longer. This is a
|
||||
* deadlock avoidance approach.
|
||||
* </p>
|
||||
*
|
||||
* @param oidPrimaryKey to delete the acl_object_identity
|
||||
*/
|
||||
@@ -293,7 +304,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
|
||||
try {
|
||||
return new Long(jdbcTemplate.queryForLong(selectObjectIdentityPrimaryKey,
|
||||
new Object[] {oid.getType(), oid.getIdentifier()}));
|
||||
new Object[] {oid.getJavaType().getName(), oid.getIdentifier()}));
|
||||
} catch (DataAccessException notFound) {
|
||||
return null;
|
||||
}
|
||||
@@ -303,6 +314,12 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
* This implementation will simply delete all ACEs in the database and recreate them on each invocation of
|
||||
* this method. A more comprehensive implementation might use dirty state checking, or more likely use ORM
|
||||
* capabilities for create, update and delete operations of {@link MutableAcl}.
|
||||
*
|
||||
* @param acl DOCUMENT ME!
|
||||
*
|
||||
* @return DOCUMENT ME!
|
||||
*
|
||||
* @throws NotFoundException DOCUMENT ME!
|
||||
*/
|
||||
public MutableAcl updateAcl(MutableAcl acl) throws NotFoundException {
|
||||
Assert.notNull(acl.getId(), "Object Identity doesn't provide an identifier");
|
||||
@@ -322,14 +339,14 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
// Retrieve the ACL via superclass (ensures cache registration, proper retrieval etc)
|
||||
return (MutableAcl) super.readAclById(acl.getObjectIdentity());
|
||||
}
|
||||
|
||||
|
||||
private void clearCacheIncludingChildren(ObjectIdentity objectIdentity) {
|
||||
Assert.notNull(objectIdentity, "ObjectIdentity required");
|
||||
List<ObjectIdentity> children = findChildren(objectIdentity);
|
||||
Assert.notNull(objectIdentity, "ObjectIdentity required");
|
||||
ObjectIdentity[] children = findChildren(objectIdentity);
|
||||
if (children != null) {
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
clearCacheIncludingChildren(children.get(i));
|
||||
}
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
clearCacheIncludingChildren(children[i]);
|
||||
}
|
||||
}
|
||||
aclCache.evictFromCache(objectIdentity);
|
||||
}
|
||||
@@ -340,7 +357,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
*
|
||||
* @param acl to modify (a row must already exist in acl_object_identity)
|
||||
*
|
||||
* @throws NotFoundException if the ACL could not be found to update.
|
||||
* @throws NotFoundException DOCUMENT ME!
|
||||
*/
|
||||
protected void updateObjectIdentity(MutableAcl acl) {
|
||||
Long parentId = null;
|
||||
@@ -364,73 +381,20 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the query that will be used to retrieve the identity of a newly created row in the <tt>acl_class</tt>
|
||||
* table.
|
||||
*
|
||||
* @param classIdentityQuery the query, which should return the identifier. Defaults to <tt>call identity()</tt>
|
||||
*/
|
||||
public void setClassIdentityQuery(String classIdentityQuery) {
|
||||
Assert.hasText(classIdentityQuery, "New classIdentityQuery query is required");
|
||||
this.classIdentityQuery = classIdentityQuery;
|
||||
}
|
||||
public void setClassIdentityQuery(String identityQuery) {
|
||||
Assert.hasText(identityQuery, "New identity query is required");
|
||||
this.classIdentityQuery = identityQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the query that will be used to retrieve the identity of a newly created row in the <tt>acl_sid</tt>
|
||||
* table.
|
||||
*
|
||||
* @param sidIdentityQuery the query, which should return the identifier. Defaults to <tt>call identity()</tt>
|
||||
*/
|
||||
public void setSidIdentityQuery(String sidIdentityQuery) {
|
||||
Assert.hasText(sidIdentityQuery, "New sidIdentityQuery query is required");
|
||||
this.sidIdentityQuery = sidIdentityQuery;
|
||||
}
|
||||
|
||||
public void setDeleteEntryByObjectIdentityForeignKeySql(String deleteEntryByObjectIdentityForeignKey) {
|
||||
this.deleteEntryByObjectIdentityForeignKey = deleteEntryByObjectIdentityForeignKey;
|
||||
}
|
||||
|
||||
public void setDeleteObjectIdentityByPrimaryKeySql(String deleteObjectIdentityByPrimaryKey) {
|
||||
this.deleteObjectIdentityByPrimaryKey = deleteObjectIdentityByPrimaryKey;
|
||||
}
|
||||
|
||||
public void setInsertClassSql(String insertClass) {
|
||||
this.insertClass = insertClass;
|
||||
}
|
||||
|
||||
public void setInsertEntrySql(String insertEntry) {
|
||||
this.insertEntry = insertEntry;
|
||||
}
|
||||
|
||||
public void setInsertObjectIdentitySql(String insertObjectIdentity) {
|
||||
this.insertObjectIdentity = insertObjectIdentity;
|
||||
}
|
||||
|
||||
public void setInsertSidSql(String insertSid) {
|
||||
this.insertSid = insertSid;
|
||||
}
|
||||
|
||||
public void setClassPrimaryKeyQuery(String selectClassPrimaryKey) {
|
||||
this.selectClassPrimaryKey = selectClassPrimaryKey;
|
||||
}
|
||||
|
||||
public void setObjectIdentityPrimaryKeyQuery(String selectObjectIdentityPrimaryKey) {
|
||||
this.selectObjectIdentityPrimaryKey = selectObjectIdentityPrimaryKey;
|
||||
}
|
||||
|
||||
public void setSidPrimaryKeyQuery(String selectSidPrimaryKey) {
|
||||
this.selectSidPrimaryKey = selectSidPrimaryKey;
|
||||
}
|
||||
|
||||
public void setUpdateObjectIdentity(String updateObjectIdentity) {
|
||||
this.updateObjectIdentity = updateObjectIdentity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param foreignKeysInDatabase if false this class will perform additional FK constrain checking, which may
|
||||
* cause deadlocks (the default is true, so deadlocks are avoided but the database is expected to enforce FKs)
|
||||
*/
|
||||
public void setForeignKeysInDatabase(boolean foreignKeysInDatabase) {
|
||||
this.foreignKeysInDatabase = foreignKeysInDatabase;
|
||||
}
|
||||
public void setSidIdentityQuery(String identityQuery) {
|
||||
Assert.hasText(identityQuery, "New identity query is required");
|
||||
this.sidIdentityQuery = identityQuery;
|
||||
}
|
||||
/**
|
||||
* @param foreignKeysInDatabase if false this class will perform additional FK constrain checking, which may
|
||||
* cause deadlocks (the default is true, so deadlocks are avoided but the database is expected to enforce FKs)
|
||||
*/
|
||||
public void setForeignKeysInDatabase(boolean foreignKeysInDatabase) {
|
||||
this.foreignKeysInDatabase = foreignKeysInDatabase;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,18 +14,16 @@
|
||||
*/
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.NotFoundException;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Performs lookups for {@link org.springframework.security.acls.model.AclService}.
|
||||
*
|
||||
* Performs lookups for {@link org.springframework.security.acls.AclService}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
@@ -42,7 +40,7 @@ public interface LookupStrategy {
|
||||
* @return a <tt>Map</tt> where keys represent the {@link ObjectIdentity} of the located {@link Acl} and values
|
||||
* are the located {@link Acl} (never <tt>null</tt> although some entries may be missing; this method
|
||||
* should not throw {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used
|
||||
* to automatically create entries if required)
|
||||
* to automatically create entries if required)
|
||||
*/
|
||||
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids);
|
||||
Map readAclsById(ObjectIdentity[] objects, Sid[] sids);
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
/**
|
||||
* Abstract base class for Acl data operations.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 3.0
|
||||
*/
|
||||
public abstract class AclDataAccessException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Constructs an <code>AclDataAccessException</code> with the specified
|
||||
* message and root cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param t the root cause
|
||||
*/
|
||||
public AclDataAccessException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an <code>AclDataAccessException</code> with the specified
|
||||
* message and no root cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public AclDataAccessException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* Strategy which creates an <tt>ObjectIdentity</tt> from an object identifier (such as a primary key)
|
||||
* and type information.
|
||||
* <p>
|
||||
* Differs from {@link ObjectIdentityRetrievalStrategy} in that it is used in situations when the actual object
|
||||
* instance isn't available.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface ObjectIdentityGenerator {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param id the identifier of the domain object, not null
|
||||
* @param type the type of the object (usually a class name), not null
|
||||
* @return
|
||||
*/
|
||||
ObjectIdentity createObjectIdentity(Serializable id, String type);
|
||||
|
||||
}
|
||||
+10
-10
@@ -12,7 +12,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.model;
|
||||
package org.springframework.security.acls.objectidentity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@@ -21,11 +21,11 @@ import java.io.Serializable;
|
||||
* Represents the identity of an individual domain object instance.
|
||||
*
|
||||
* <p>
|
||||
* As implementations of <tt>ObjectIdentity</tt> are used as the key to represent
|
||||
* As implementations of <tt>ObjectIdentity</tt> are used as the key to represent
|
||||
* domain objects in the ACL subsystem, it is essential that implementations provide
|
||||
* methods so that object-equality rather than reference-equality can be relied upon
|
||||
* reliably. In other words, the ACL subsystem can consider two
|
||||
* <tt>ObjectIdentity</tt>s equal if <tt>identity1.equals(identity2)</tt>, rather than
|
||||
* reliably. In other words, the ACL subsystem can consider two
|
||||
* <tt>ObjectIdentity</tt>s equal if <tt>identity1.equals(identity2)</tt>, rather than
|
||||
* reference-equality of <tt>identity1==identity2</tt>.
|
||||
* </p>
|
||||
*
|
||||
@@ -46,10 +46,10 @@ public interface ObjectIdentity extends Serializable {
|
||||
/**
|
||||
* Obtains the actual identifier. This identifier must not be reused to represent other domain objects with
|
||||
* the same <tt>javaType</tt>.
|
||||
*
|
||||
*
|
||||
* <p>Because ACLs are largely immutable, it is strongly recommended to use
|
||||
* a synthetic identifier (such as a database sequence number for the primary key). Do not use an identifier with
|
||||
* business meaning, as that business meaning may change in the future such change will cascade to the ACL
|
||||
* business meaning, as that business meaning may change in the future such change will cascade to the ACL
|
||||
* subsystem data.</p>
|
||||
*
|
||||
* @return the identifier (unique within this <tt>javaType</tt>; never <tt>null</tt>)
|
||||
@@ -57,12 +57,12 @@ public interface ObjectIdentity extends Serializable {
|
||||
Serializable getIdentifier();
|
||||
|
||||
/**
|
||||
* Obtains the "type" metadata for the domain object. This will often be a Java type name (an interface or a class)
|
||||
* – traditionally it is the name of the domain object implementation class.
|
||||
* Obtains the Java type represented by the domain object. The Java type can be an interface or a class, but is
|
||||
* most often the domain object implementation class.
|
||||
*
|
||||
* @return the "type" of the domain object (never <tt>null</tt>).
|
||||
* @return the Java type of the domain object (never <tt>null</tt>)
|
||||
*/
|
||||
String getType();
|
||||
Class getJavaType();
|
||||
|
||||
/**
|
||||
* @return a hash code representation of the <tt>ObjectIdentity</tt>
|
||||
+46
-45
@@ -12,14 +12,18 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.domain;
|
||||
package org.springframework.security.acls.objectidentity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import org.springframework.security.acls.IdentityUnavailableException;
|
||||
import org.springframework.security.acls.jdbc.LookupStrategy;
|
||||
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
/**
|
||||
@@ -34,51 +38,51 @@ import org.springframework.util.ClassUtils;
|
||||
public class ObjectIdentityImpl implements ObjectIdentity {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final String type;
|
||||
private Class javaType;
|
||||
private Serializable identifier;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public ObjectIdentityImpl(String type, Serializable identifier) {
|
||||
Assert.hasText(type, "Type required");
|
||||
public ObjectIdentityImpl(String javaType, Serializable identifier) {
|
||||
Assert.hasText(javaType, "Java Type required");
|
||||
Assert.notNull(identifier, "identifier required");
|
||||
|
||||
try {
|
||||
this.javaType = Class.forName(javaType);
|
||||
} catch (Exception ex) {
|
||||
ReflectionUtils.handleReflectionException(ex);
|
||||
}
|
||||
|
||||
this.identifier = identifier;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor which uses the name of the supplied class as the <tt>type</tt> property.
|
||||
*/
|
||||
public ObjectIdentityImpl(Class<?> javaType, Serializable identifier) {
|
||||
public ObjectIdentityImpl(Class javaType, Serializable identifier) {
|
||||
Assert.notNull(javaType, "Java Type required");
|
||||
Assert.notNull(identifier, "identifier required");
|
||||
this.type = javaType.getName();
|
||||
this.javaType = javaType;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Creates the <code>ObjectIdentityImpl</code> based on the passed
|
||||
* object instance. The passed object must provide a <code>getId()</code>
|
||||
* method, otherwise an exception will be thrown.
|
||||
* <p>
|
||||
* The class name of the object passed will be considered the {@link #type}, so if more control is required,
|
||||
* a different constructor should be used.
|
||||
* method, otherwise an exception will be thrown. The object passed will
|
||||
* be considered the {@link #javaType}, so if more control is required,
|
||||
* an alternate constructor should be used instead.
|
||||
*
|
||||
* @param object the domain object instance to create an identity for.
|
||||
* @param object the domain object instance to create an identity for
|
||||
*
|
||||
* @throws IdentityUnavailableException if identity could not be extracted
|
||||
*/
|
||||
public ObjectIdentityImpl(Object object) throws IdentityUnavailableException {
|
||||
Assert.notNull(object, "object cannot be null");
|
||||
|
||||
Class<?> typeClass = ClassUtils.getUserClass(object.getClass());
|
||||
type = typeClass.getName();
|
||||
this.javaType = ClassUtils.getUserClass(object.getClass());
|
||||
|
||||
Object result;
|
||||
|
||||
try {
|
||||
Method method = typeClass.getMethod("getId", new Class[] {});
|
||||
Method method = this.javaType.getMethod("getId", new Class[] {});
|
||||
result = method.invoke(object, new Object[] {});
|
||||
} catch (Exception e) {
|
||||
throw new IdentityUnavailableException("Could not extract identity from object " + object, e);
|
||||
@@ -92,46 +96,43 @@ public class ObjectIdentityImpl implements ObjectIdentity {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Important so caching operates properly.
|
||||
* Important so caching operates properly.<P>Considers an object of the same class equal if it has the same
|
||||
* <code>classname</code> and <code>id</code> properties.</p>
|
||||
*
|
||||
* <p>
|
||||
* Considers an object of the same class equal if it has the same <code>classname</code> and
|
||||
* <code>id</code> properties.
|
||||
* <p>
|
||||
* Numeric identities (Integer and Long values) are considered equal if they are numerically equal. Other
|
||||
* serializable types are evaluated using a simple equality.
|
||||
* Note that this class uses string equality for the identifier field, which ensures it better supports
|
||||
* differences between {@link LookupStrategy} requirements and the domain object represented by this
|
||||
* <code>ObjectIdentityImpl</code>.
|
||||
* </p>
|
||||
*
|
||||
* @param arg0 object to compare
|
||||
*
|
||||
* @return <code>true</code> if the presented object matches this object
|
||||
*/
|
||||
public boolean equals(Object arg0) {
|
||||
if (arg0 == null || !(arg0 instanceof ObjectIdentityImpl)) {
|
||||
if (arg0 == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(arg0 instanceof ObjectIdentityImpl)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectIdentityImpl other = (ObjectIdentityImpl) arg0;
|
||||
|
||||
if (identifier instanceof Number && other.identifier instanceof Number) {
|
||||
// Integers and Longs with same value should be considered equal
|
||||
if (((Number)identifier).longValue() != ((Number)other.identifier).longValue()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Use plain equality for other serializable types
|
||||
if (!identifier.equals(other.identifier)) {
|
||||
return false;
|
||||
}
|
||||
if (this.getIdentifier().toString().equals(other.getIdentifier().toString()) && this.getJavaType().equals(other.getJavaType())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return type.equals(other.type);
|
||||
return false;
|
||||
}
|
||||
|
||||
public Serializable getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
public Class getJavaType() {
|
||||
return javaType;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,16 +142,16 @@ public class ObjectIdentityImpl implements ObjectIdentity {
|
||||
*/
|
||||
public int hashCode() {
|
||||
int code = 31;
|
||||
code ^= this.type.hashCode();
|
||||
code ^= this.javaType.hashCode();
|
||||
code ^= this.identifier.hashCode();
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(this.getClass().getName()).append("[");
|
||||
sb.append("Type: ").append(this.type);
|
||||
sb.append("Java Type: ").append(this.javaType.getName());
|
||||
sb.append("; Identifier: ").append(this.identifier).append("]");
|
||||
|
||||
return sb.toString();
|
||||
+1
-2
@@ -13,8 +13,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
|
||||
package org.springframework.security.acls.objectidentity;
|
||||
|
||||
/**
|
||||
* Strategy interface that provides the ability to determine which {@link ObjectIdentity}
|
||||
+4
-14
@@ -13,29 +13,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.ObjectIdentityGenerator;
|
||||
import org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy;
|
||||
package org.springframework.security.acls.objectidentity;
|
||||
|
||||
/**
|
||||
* Basic implementation of {@link ObjectIdentityRetrievalStrategy} and <tt>ObjectIdentityGenerator</tt>
|
||||
* that uses the constructors of {@link ObjectIdentityImpl} to create the {@link ObjectIdentity}.
|
||||
* Basic implementation of {@link ObjectIdentityRetrievalStrategy} that uses the constructor of {@link
|
||||
* ObjectIdentityImpl} to create the {@link ObjectIdentity}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class ObjectIdentityRetrievalStrategyImpl implements ObjectIdentityRetrievalStrategy, ObjectIdentityGenerator {
|
||||
public class ObjectIdentityRetrievalStrategyImpl implements ObjectIdentityRetrievalStrategy {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public ObjectIdentity getObjectIdentity(Object domainObject) {
|
||||
return new ObjectIdentityImpl(domainObject);
|
||||
}
|
||||
|
||||
public ObjectIdentity createObjectIdentity(Serializable id, String type) {
|
||||
return new ObjectIdentityImpl(type, id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Provides indirection between ACL packages and domain objects.
|
||||
</body>
|
||||
</html>
|
||||
+2
-3
@@ -12,10 +12,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.domain;
|
||||
package org.springframework.security.acls.sid;
|
||||
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
+3
-4
@@ -12,12 +12,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.domain;
|
||||
package org.springframework.security.acls.sid;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.userdetails.UserDetails;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.model;
|
||||
package org.springframework.security.acls.sid;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
+3
-5
@@ -13,11 +13,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.model;
|
||||
package org.springframework.security.acls.sid;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.Authentication;
|
||||
|
||||
|
||||
/**
|
||||
@@ -30,5 +28,5 @@ import org.springframework.security.core.Authentication;
|
||||
public interface SidRetrievalStrategy {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
List<Sid> getSids(Authentication authentication);
|
||||
Sid[] getSids(Authentication authentication);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/* 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.acls.sid;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
|
||||
/**
|
||||
* Basic implementation of {@link SidRetrievalStrategy} that creates a {@link Sid} for the principal, as well as
|
||||
* every granted authority the principal holds.
|
||||
* <p>
|
||||
* The returned array will always contain the {@link PrincipalSid} before any {@link GrantedAuthoritySid} elements.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SidRetrievalStrategyImpl implements SidRetrievalStrategy {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public Sid[] getSids(Authentication authentication) {
|
||||
GrantedAuthority[] authorities = authentication.getAuthorities();
|
||||
Sid[] sids = new Sid[authorities.length + 1];
|
||||
|
||||
sids[0] = new PrincipalSid(authentication);
|
||||
|
||||
for (int i = 1; i <= authorities.length; i++) {
|
||||
sids[i] = new GrantedAuthoritySid(authorities[i - 1]);
|
||||
}
|
||||
|
||||
return sids;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Provides indirection between ACL packages and security identities, such as principals and GrantedAuthority[]s.
|
||||
</body>
|
||||
</html>
|
||||
+22
-24
@@ -13,25 +13,23 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.acls.afterinvocation;
|
||||
package org.springframework.security.afterinvocation;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.ConfigAttribute;
|
||||
|
||||
import org.springframework.security.access.AfterInvocationProvider;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AclService;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
|
||||
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.Authentication;
|
||||
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.util.Assert;
|
||||
|
||||
|
||||
@@ -45,19 +43,19 @@ public abstract class AbstractAclProvider implements AfterInvocationProvider {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
protected AclService aclService;
|
||||
protected Class<?> processDomainObjectClass = Object.class;
|
||||
protected Class processDomainObjectClass = Object.class;
|
||||
protected ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
|
||||
protected SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
protected String processConfigAttribute;
|
||||
protected List<Permission> requirePermission = Arrays.asList(BasePermission.READ);
|
||||
protected Permission[] requirePermission = {BasePermission.READ};
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public AbstractAclProvider(AclService aclService, String processConfigAttribute, List<Permission> requirePermission) {
|
||||
public AbstractAclProvider(AclService aclService, String processConfigAttribute, Permission[] requirePermission) {
|
||||
Assert.hasText(processConfigAttribute, "A processConfigAttribute is mandatory");
|
||||
Assert.notNull(aclService, "An AclService is mandatory");
|
||||
|
||||
if (requirePermission == null || requirePermission.isEmpty()) {
|
||||
if ((requirePermission == null) || (requirePermission.length == 0)) {
|
||||
throw new IllegalArgumentException("One or more requirePermission entries is mandatory");
|
||||
}
|
||||
|
||||
@@ -68,7 +66,7 @@ public abstract class AbstractAclProvider implements AfterInvocationProvider {
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
protected Class<?> getProcessDomainObjectClass() {
|
||||
protected Class getProcessDomainObjectClass() {
|
||||
return processDomainObjectClass;
|
||||
}
|
||||
|
||||
@@ -77,7 +75,7 @@ public abstract class AbstractAclProvider implements AfterInvocationProvider {
|
||||
ObjectIdentity objectIdentity = objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
|
||||
|
||||
// Obtain the SIDs applicable to the principal
|
||||
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
|
||||
Sid[] sids = sidRetrievalStrategy.getSids(authentication);
|
||||
|
||||
Acl acl = null;
|
||||
|
||||
@@ -101,7 +99,7 @@ public abstract class AbstractAclProvider implements AfterInvocationProvider {
|
||||
this.processConfigAttribute = processConfigAttribute;
|
||||
}
|
||||
|
||||
public void setProcessDomainObjectClass(Class<?> processDomainObjectClass) {
|
||||
public void setProcessDomainObjectClass(Class processDomainObjectClass) {
|
||||
Assert.notNull(processDomainObjectClass, "processDomainObjectClass cannot be set to null");
|
||||
this.processDomainObjectClass = processDomainObjectClass;
|
||||
}
|
||||
@@ -122,7 +120,7 @@ public abstract class AbstractAclProvider implements AfterInvocationProvider {
|
||||
*
|
||||
* @return always <code>true</code>
|
||||
*/
|
||||
public boolean supports(Class<?> clazz) {
|
||||
public boolean supports(Class clazz) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+26
-16
@@ -12,19 +12,22 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.afterinvocation;
|
||||
package org.springframework.security.afterinvocation;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthorizationServiceException;
|
||||
import org.springframework.security.ConfigAttribute;
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
|
||||
import org.springframework.security.acls.AclService;
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.AuthorizationServiceException;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.acls.model.AclService;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
|
||||
/**
|
||||
@@ -38,8 +41,8 @@ import org.springframework.security.core.Authentication;
|
||||
* <p>
|
||||
* This after invocation provider will fire if any {@link ConfigAttribute#getAttribute()} matches the {@link
|
||||
* #processConfigAttribute}. The provider will then lookup the ACLs from the <code>AclService</code> and ensure the
|
||||
* principal is {@link org.springframework.security.acls.Acl#isGranted(List,
|
||||
* List, boolean) Acl.isGranted(Permission[], Sid[], boolean)}
|
||||
* principal is {@link org.springframework.security.acls.Acl#isGranted(org.springframework.security.acls.Permission[],
|
||||
* org.springframework.security.acls.sid.Sid[], boolean) Acl.isGranted(Permission[], Sid[], boolean)}
|
||||
* when presenting the {@link #requirePermission} array to that method.
|
||||
* <p>
|
||||
* If the principal does not have permission, that element will not be included in the returned
|
||||
@@ -66,14 +69,13 @@ public class AclEntryAfterInvocationCollectionFilteringProvider extends Abstract
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public AclEntryAfterInvocationCollectionFilteringProvider(AclService aclService, List<Permission> requirePermission) {
|
||||
public AclEntryAfterInvocationCollectionFilteringProvider(AclService aclService, Permission[] requirePermission) {
|
||||
super(aclService, "AFTER_ACL_COLLECTION_READ", requirePermission);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
|
||||
public Object decide(Authentication authentication, Object object, ConfigAttributeDefinition config,
|
||||
Object returnedObject) throws AccessDeniedException {
|
||||
|
||||
if (returnedObject == null) {
|
||||
@@ -84,7 +86,11 @@ public class AclEntryAfterInvocationCollectionFilteringProvider extends Abstract
|
||||
return null;
|
||||
}
|
||||
|
||||
for (ConfigAttribute attr : config) {
|
||||
Iterator iter = config.getConfigAttributes().iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
ConfigAttribute attr = (ConfigAttribute) iter.next();
|
||||
|
||||
if (!this.supports(attr)) {
|
||||
continue;
|
||||
}
|
||||
@@ -102,7 +108,11 @@ public class AclEntryAfterInvocationCollectionFilteringProvider extends Abstract
|
||||
}
|
||||
|
||||
// Locate unauthorised Collection elements
|
||||
for (Object domainObject : filterer) {
|
||||
Iterator collectionIter = filterer.iterator();
|
||||
|
||||
while (collectionIter.hasNext()) {
|
||||
Object domainObject = collectionIter.next();
|
||||
|
||||
// Ignore nulls or entries which aren't instances of the configured domain object class
|
||||
if (domainObject == null || !getProcessDomainObjectClass().isAssignableFrom(domainObject.getClass())) {
|
||||
continue;
|
||||
+22
-20
@@ -12,22 +12,25 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls.afterinvocation;
|
||||
package org.springframework.security.afterinvocation;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.SpringSecurityMessageSource;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.ConfigAttribute;
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
|
||||
import org.springframework.security.acls.AclService;
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.acls.model.AclService;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
|
||||
/**
|
||||
@@ -39,8 +42,8 @@ import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
* <p>
|
||||
* This after invocation provider will fire if any {@link ConfigAttribute#getAttribute()} matches the {@link
|
||||
* #processConfigAttribute}. The provider will then lookup the ACLs from the <tt>AclService</tt> and ensure the
|
||||
* principal is {@link org.springframework.security.acls.Acl#isGranted(List,
|
||||
List, boolean) Acl.isGranted(Permission[], Sid[], boolean)}
|
||||
* principal is {@link org.springframework.security.acls.Acl#isGranted(org.springframework.security.acls.Permission[],
|
||||
org.springframework.security.acls.sid.Sid[], boolean) Acl.isGranted(Permission[], Sid[], boolean)}
|
||||
* when presenting the {@link #requirePermission} array to that method.
|
||||
* <p>
|
||||
* Often users will setup an <code>AclEntryAfterInvocationProvider</code> with a {@link
|
||||
@@ -65,20 +68,17 @@ public class AclEntryAfterInvocationProvider extends AbstractAclProvider impleme
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public AclEntryAfterInvocationProvider(AclService aclService, List<Permission> requirePermission) {
|
||||
public AclEntryAfterInvocationProvider(AclService aclService, Permission[] requirePermission) {
|
||||
super(aclService, "AFTER_ACL_READ", requirePermission);
|
||||
}
|
||||
|
||||
public AclEntryAfterInvocationProvider(AclService aclService, String processConfigAttribute,
|
||||
List<Permission> requirePermission) {
|
||||
super(aclService, processConfigAttribute, requirePermission);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
|
||||
public Object decide(Authentication authentication, Object object, ConfigAttributeDefinition config,
|
||||
Object returnedObject) throws AccessDeniedException {
|
||||
|
||||
Iterator iter = config.getConfigAttributes().iterator();
|
||||
|
||||
if (returnedObject == null) {
|
||||
// AclManager interface contract prohibits nulls
|
||||
// As they have permission to null/nothing, grant access
|
||||
@@ -95,9 +95,11 @@ public class AclEntryAfterInvocationProvider extends AbstractAclProvider impleme
|
||||
}
|
||||
|
||||
return returnedObject;
|
||||
}
|
||||
}
|
||||
|
||||
while (iter.hasNext()) {
|
||||
ConfigAttribute attr = (ConfigAttribute) iter.next();
|
||||
|
||||
for (ConfigAttribute attr : config) {
|
||||
if (!this.supports(attr)) {
|
||||
continue;
|
||||
}
|
||||
+35
-36
@@ -12,30 +12,28 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.acls;
|
||||
package org.springframework.security.vote;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthorizationServiceException;
|
||||
import org.springframework.security.ConfigAttribute;
|
||||
import org.springframework.security.ConfigAttributeDefinition;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AclService;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.Permission;
|
||||
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.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.security.access.AuthorizationServiceException;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
import org.springframework.security.access.vote.AbstractAclVoter;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
|
||||
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.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -51,17 +49,16 @@ import org.springframework.util.StringUtils;
|
||||
* The voter will vote if any {@link ConfigAttribute#getAttribute()} matches the {@link #processConfigAttribute}.
|
||||
* The provider will then locate the first method argument of type {@link #processDomainObjectClass}. Assuming that
|
||||
* method argument is non-null, the provider will then lookup the ACLs from the <code>AclManager</code> and ensure the
|
||||
* principal is {@link Acl#isGranted(List,
|
||||
* List, boolean)} when presenting the {@link #requirePermission} array to that
|
||||
* principal is {@link Acl#isGranted(org.springframework.security.acls.Permission[],
|
||||
* org.springframework.security.acls.sid.Sid[], boolean)} when presenting the {@link #requirePermission} array to that
|
||||
* method.
|
||||
* <p>
|
||||
* If the method argument is <tt>null</tt>, the voter will abstain from voting. If the method argument
|
||||
* could not be found, an {@link AuthorizationServiceException} will be thrown.
|
||||
* could not be found, an {@link org.springframework.security.AuthorizationServiceException} will be thrown.
|
||||
* <p>
|
||||
* In practical terms users will typically setup a number of <tt>AclEntryVoter</tt>s. Each will have a
|
||||
* different {@link #setProcessDomainObjectClass processDomainObjectClass}, {@link #processConfigAttribute} and
|
||||
* {@link #requirePermission} combination. For example, a small application might employ the following instances of
|
||||
* <tt>AclEntryVoter</tt>:
|
||||
* different {@link #processDomainObjectClass}, {@link #processConfigAttribute} and {@link #requirePermission}
|
||||
* combination. For example, a small application might employ the following instances of <tt>AclEntryVoter</tt>:
|
||||
* <ul>
|
||||
* <li>Process domain object class <code>BankAccount</code>, configuration attribute
|
||||
* <code>VOTE_ACL_BANK_ACCONT_READ</code>, require permission <code>BasePermission.READ</code></li>
|
||||
@@ -94,7 +91,7 @@ public class AclEntryVoter extends AbstractAclVoter {
|
||||
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
|
||||
private String internalMethod;
|
||||
private String processConfigAttribute;
|
||||
private List<Permission> requirePermission;
|
||||
private Permission[] requirePermission;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
@@ -108,7 +105,7 @@ public class AclEntryVoter extends AbstractAclVoter {
|
||||
|
||||
this.aclService = aclService;
|
||||
this.processConfigAttribute = processConfigAttribute;
|
||||
this.requirePermission = Arrays.asList(requirePermission);
|
||||
this.requirePermission = requirePermission;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
@@ -153,9 +150,11 @@ public class AclEntryVoter extends AbstractAclVoter {
|
||||
}
|
||||
}
|
||||
|
||||
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
|
||||
public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {
|
||||
Iterator iter = config.getConfigAttributes().iterator();
|
||||
|
||||
for(ConfigAttribute attr : attributes) {
|
||||
while (iter.hasNext()) {
|
||||
ConfigAttribute attr = (ConfigAttribute) iter.next();
|
||||
|
||||
if (!this.supports(attr)) {
|
||||
continue;
|
||||
@@ -170,13 +169,13 @@ public class AclEntryVoter extends AbstractAclVoter {
|
||||
logger.debug("Voting to abstain - domainObject is null");
|
||||
}
|
||||
|
||||
return ACCESS_ABSTAIN;
|
||||
return AccessDecisionVoter.ACCESS_ABSTAIN;
|
||||
}
|
||||
|
||||
// Evaluate if we are required to use an inner domain object
|
||||
if (StringUtils.hasText(internalMethod)) {
|
||||
try {
|
||||
Class<?> clazz = domainObject.getClass();
|
||||
Class clazz = domainObject.getClass();
|
||||
Method method = clazz.getMethod(internalMethod, new Class[0]);
|
||||
domainObject = method.invoke(domainObject, new Object[0]);
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
@@ -199,7 +198,7 @@ public class AclEntryVoter extends AbstractAclVoter {
|
||||
ObjectIdentity objectIdentity = objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
|
||||
|
||||
// Obtain the SIDs applicable to the principal
|
||||
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
|
||||
Sid[] sids = sidRetrievalStrategy.getSids(authentication);
|
||||
|
||||
Acl acl;
|
||||
|
||||
@@ -211,7 +210,7 @@ public class AclEntryVoter extends AbstractAclVoter {
|
||||
logger.debug("Voting to deny access - no ACLs apply for this principal");
|
||||
}
|
||||
|
||||
return ACCESS_DENIED;
|
||||
return AccessDecisionVoter.ACCESS_DENIED;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -220,25 +219,25 @@ public class AclEntryVoter extends AbstractAclVoter {
|
||||
logger.debug("Voting to grant access");
|
||||
}
|
||||
|
||||
return ACCESS_GRANTED;
|
||||
return AccessDecisionVoter.ACCESS_GRANTED;
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(
|
||||
"Voting to deny access - ACLs returned, but insufficient permissions for this principal");
|
||||
}
|
||||
|
||||
return ACCESS_DENIED;
|
||||
return AccessDecisionVoter.ACCESS_DENIED;
|
||||
}
|
||||
} catch (NotFoundException nfe) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Voting to deny access - no ACLs apply for this principal");
|
||||
}
|
||||
|
||||
return ACCESS_DENIED;
|
||||
return AccessDecisionVoter.ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
// No configuration attribute matched, so abstain
|
||||
return ACCESS_ABSTAIN;
|
||||
return AccessDecisionVoter.ACCESS_ABSTAIN;
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
-- ACL schema sql used in HSQLDB
|
||||
|
||||
-- drop table acl_entry;
|
||||
-- drop table acl_object_identity;
|
||||
-- drop table acl_class;
|
||||
-- drop table acl_sid;
|
||||
|
||||
|
||||
create table acl_sid(
|
||||
id bigint generated by default as identity(start with 100) not null primary key,
|
||||
principal boolean not null,
|
||||
sid varchar_ignorecase(100) not null,
|
||||
constraint unique_uk_1 unique(sid,principal));
|
||||
|
||||
create table acl_class(
|
||||
id bigint generated by default as identity(start with 100) not null primary key,
|
||||
class varchar_ignorecase(100) not null,
|
||||
constraint unique_uk_2 unique(class)
|
||||
);
|
||||
|
||||
create table acl_object_identity(
|
||||
id bigint generated by default as identity(start with 100) not null primary key,
|
||||
object_id_class bigint not null,
|
||||
object_id_identity bigint not null,
|
||||
parent_object bigint,
|
||||
owner_sid bigint,
|
||||
entries_inheriting boolean not null,
|
||||
constraint unique_uk_3 unique(object_id_class,object_id_identity),
|
||||
constraint foreign_fk_1 foreign key(parent_object)references acl_object_identity(id),
|
||||
constraint foreign_fk_2 foreign key(object_id_class)references acl_class(id),
|
||||
constraint foreign_fk_3 foreign key(owner_sid)references acl_sid(id)
|
||||
);
|
||||
|
||||
create table acl_entry(
|
||||
id bigint generated by default as identity(start with 100) not null primary key,
|
||||
acl_object_identity bigint not null,
|
||||
ace_order int not null,
|
||||
sid bigint not null,
|
||||
mask integer not null,
|
||||
granting boolean not null,
|
||||
audit_success boolean not null,
|
||||
audit_failure boolean not null,
|
||||
constraint unique_uk_4 unique(acl_object_identity,ace_order),
|
||||
constraint foreign_fk_4 foreign key(acl_object_identity) references acl_object_identity(id),
|
||||
constraint foreign_fk_5 foreign key(sid) references acl_sid(id)
|
||||
);
|
||||
@@ -1,46 +0,0 @@
|
||||
-- ACL Schema SQL for PostgreSQL
|
||||
|
||||
-- drop table acl_entry;
|
||||
-- drop table acl_object_identity;
|
||||
-- drop table acl_class;
|
||||
-- drop table acl_sid;
|
||||
|
||||
create table acl_sid(
|
||||
id bigserial not null primary key,
|
||||
principal boolean not null,
|
||||
sid varchar(100) not null,
|
||||
constraint unique_uk_1 unique(sid,principal)
|
||||
);
|
||||
|
||||
create table acl_class(
|
||||
id bigserial not null primary key,
|
||||
class varchar(100) not null,
|
||||
constraint unique_uk_2 unique(class)
|
||||
);
|
||||
|
||||
create table acl_object_identity(
|
||||
id bigserial primary key,
|
||||
object_id_class bigint not null,
|
||||
object_id_identity bigint not null,
|
||||
parent_object bigint,
|
||||
owner_sid bigint,
|
||||
entries_inheriting boolean not null,
|
||||
constraint unique_uk_3 unique(object_id_class,object_id_identity),
|
||||
constraint foreign_fk_1 foreign key(parent_object)references acl_object_identity(id),
|
||||
constraint foreign_fk_2 foreign key(object_id_class)references acl_class(id),
|
||||
constraint foreign_fk_3 foreign key(owner_sid)references acl_sid(id)
|
||||
);
|
||||
|
||||
create table acl_entry(
|
||||
id bigserial primary key,
|
||||
acl_object_identity bigint not null,
|
||||
ace_order int not null,
|
||||
sid bigint not null,
|
||||
mask integer not null,
|
||||
granting boolean not null,
|
||||
audit_success boolean not null,
|
||||
audit_failure boolean not null,
|
||||
constraint unique_uk_4 unique(acl_object_identity,ace_order),
|
||||
constraint foreign_fk_4 foreign key(acl_object_identity) references acl_object_identity(id),
|
||||
constraint foreign_fk_5 foreign key(sid) references acl_sid(id)
|
||||
);
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
|
||||
|
||||
<!--
|
||||
- Application context containing business beans.
|
||||
-
|
||||
- Used by all artifacts.
|
||||
-
|
||||
- $Id:applicationContext-test.xml 1754 2006-11-17 02:01:21Z benalex $
|
||||
-->
|
||||
|
||||
<beans>
|
||||
|
||||
<bean id="databaseSeeder" class="org.springframework.security.acls.jdbc.DatabaseSeeder">
|
||||
<constructor-arg ref="dataSource"/>
|
||||
<constructor-arg value="classpath:org/springframework/security/acls/jdbc/testData.sql"/>
|
||||
</bean>
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
</bean>
|
||||
|
||||
<bean id="aclCache" class="org.springframework.security.acls.jdbc.EhCacheBasedAclCache">
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
|
||||
<property name="cacheManager">
|
||||
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
|
||||
</property>
|
||||
<property name="cacheName" value="aclCache"/>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
|
||||
<constructor-arg ref="dataSource"/>
|
||||
<constructor-arg ref="aclCache"/>
|
||||
<constructor-arg ref="aclAuthorizationStrategy"/>
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<bean class="org.springframework.security.GrantedAuthorityImpl">
|
||||
<constructor-arg value="ROLE_ADMINISTRATOR"/>
|
||||
</bean>
|
||||
<bean class="org.springframework.security.GrantedAuthorityImpl">
|
||||
<constructor-arg value="ROLE_ADMINISTRATOR"/>
|
||||
</bean>
|
||||
<bean class="org.springframework.security.GrantedAuthorityImpl">
|
||||
<constructor-arg value="ROLE_ADMINISTRATOR"/>
|
||||
</bean>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="aclService" class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
|
||||
<constructor-arg ref="dataSource"/>
|
||||
<constructor-arg ref="lookupStrategy"/>
|
||||
<constructor-arg ref="aclCache"/>
|
||||
</bean>
|
||||
|
||||
<bean id="dataSource" class="org.springframework.security.TestDataSource">
|
||||
<constructor-arg value="acltest" />
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,27 @@
|
||||
-- Not required. Just shows the sort of queries being sent to DB.
|
||||
|
||||
|
||||
select ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY, ACL_ENTRY.ACE_ORDER,
|
||||
ACL_OBJECT_IDENTITY.ID as ACL_ID,
|
||||
ACL_OBJECT_IDENTITY.PARENT_OBJECT,
|
||||
ACL_OBJECT_IDENTITY,ENTRIES_INHERITING,
|
||||
ACL_ENTRY.ID as ACE_ID, ACL_ENTRY.MASK, ACL_ENTRY.GRANTING, ACL_ENTRY.AUDIT_SUCCESS, ACL_ENTRY.AUDIT_FAILURE,
|
||||
ACL_SID.PRINCIPAL as ACE_PRINCIPAL, ACL_SID.SID as ACE_SID,
|
||||
ACLI_SID.PRINCIPAL as ACL_PRINCIPAL, ACLI_SID.SID as ACL_SID,
|
||||
ACL_CLASS.CLASS
|
||||
|
||||
from ACL_OBJECT_IDENTITY, ACL_SID ACLI_SID, ACL_CLASS
|
||||
LEFT JOIN ACL_ENTRY ON ACL_OBJECT_IDENTITY.ID = ACL_ENTRY.ACL_OBJECT_IDENTITY
|
||||
LEFT JOIN ACL_SID ON ACL_ENTRY.SID = ACL_SID.ID
|
||||
|
||||
where
|
||||
|
||||
ACLI_SID.ID = ACL_OBJECT_IDENTITY.OWNER_SID
|
||||
and ACL_CLASS.ID = ACL_OBJECT_IDENTITY.OBJECT_ID_CLASS
|
||||
and (
|
||||
(ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY = 1
|
||||
and ACL_CLASS.CLASS = 'sample.contact.Contact')
|
||||
or
|
||||
(ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY = 2000
|
||||
and ACL_CLASS.CLASS = 'sample.contact.Contact')
|
||||
) order by ACL_OBJECT_IDENTITY.OBJECT_ID_IDENTITY asc, ACL_ENTRY.ACE_ORDER asc
|
||||
@@ -0,0 +1,45 @@
|
||||
-- Injected into DatabaseSeeder via applicationContext-test.xml (see test case JdbcAclServiceTests)
|
||||
|
||||
-- DROP TABLE ACL_ENTRY;
|
||||
-- DROP TABLE ACL_OBJECT_IDENTITY;
|
||||
-- DROP TABLE ACL_CLASS;
|
||||
-- DROP TABLE ACL_SID;
|
||||
|
||||
|
||||
CREATE TABLE ACL_SID(
|
||||
ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,
|
||||
PRINCIPAL BOOLEAN NOT NULL,
|
||||
SID VARCHAR_IGNORECASE(100) NOT NULL,
|
||||
CONSTRAINT UNIQUE_UK_1 UNIQUE(SID,PRINCIPAL));
|
||||
|
||||
CREATE TABLE ACL_CLASS(
|
||||
ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,
|
||||
CLASS VARCHAR_IGNORECASE(100) NOT NULL,
|
||||
CONSTRAINT UNIQUE_UK_2 UNIQUE(CLASS));
|
||||
|
||||
INSERT INTO ACL_CLASS VALUES (1, 'sample.contact.Contact');
|
||||
|
||||
CREATE TABLE ACL_OBJECT_IDENTITY(
|
||||
ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,
|
||||
OBJECT_ID_CLASS BIGINT NOT NULL,
|
||||
OBJECT_ID_IDENTITY BIGINT NOT NULL,
|
||||
PARENT_OBJECT BIGINT,
|
||||
OWNER_SID BIGINT,
|
||||
ENTRIES_INHERITING BOOLEAN NOT NULL,
|
||||
CONSTRAINT UNIQUE_UK_3 UNIQUE(OBJECT_ID_CLASS,OBJECT_ID_IDENTITY),
|
||||
CONSTRAINT FOREIGN_FK_1 FOREIGN KEY(PARENT_OBJECT)REFERENCES ACL_OBJECT_IDENTITY(ID),
|
||||
CONSTRAINT FOREIGN_FK_2 FOREIGN KEY(OBJECT_ID_CLASS)REFERENCES ACL_CLASS(ID),
|
||||
CONSTRAINT FOREIGN_FK_3 FOREIGN KEY(OWNER_SID)REFERENCES ACL_SID(ID));
|
||||
|
||||
CREATE TABLE ACL_ENTRY(
|
||||
ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,
|
||||
ACL_OBJECT_IDENTITY BIGINT NOT NULL,
|
||||
ACE_ORDER INT NOT NULL,
|
||||
SID BIGINT NOT NULL,
|
||||
MASK INTEGER NOT NULL,
|
||||
GRANTING BOOLEAN NOT NULL,
|
||||
AUDIT_SUCCESS BOOLEAN NOT NULL,
|
||||
AUDIT_FAILURE BOOLEAN NOT NULL,
|
||||
CONSTRAINT UNIQUE_UK_4 UNIQUE(ACL_OBJECT_IDENTITY,ACE_ORDER),
|
||||
CONSTRAINT FOREIGN_FK_4 FOREIGN KEY(ACL_OBJECT_IDENTITY) REFERENCES ACL_OBJECT_IDENTITY(ID),
|
||||
CONSTRAINT FOREIGN_FK_5 FOREIGN KEY(SID) REFERENCES ACL_SID(ID));
|
||||
@@ -1,39 +0,0 @@
|
||||
-- Not required. Just shows the sort of queries being sent to DB.
|
||||
|
||||
|
||||
select acl_object_identity.object_id_identity,
|
||||
acl_entry.ace_order,
|
||||
acl_object_identity.id as acl_id,
|
||||
acl_object_identity.parent_object,
|
||||
acl_object_identity,
|
||||
entries_inheriting,
|
||||
acl_entry.id as ace_id,
|
||||
acl_entry.mask,
|
||||
acl_entry.granting,
|
||||
acl_entry.audit_success,
|
||||
acl_entry.audit_failure,
|
||||
acl_sid.principal as ace_principal,
|
||||
acl_sid.sid as ace_sid,
|
||||
acli_sid.principal as acl_principal,
|
||||
acli_sid.sid as acl_sid,
|
||||
acl_class.class
|
||||
|
||||
from acl_object_identity,
|
||||
acl_sid acli_sid,
|
||||
acl_class
|
||||
|
||||
left join acl_entry on acl_object_identity.id = acl_entry.acl_object_identity
|
||||
left join acl_sid on acl_entry.sid = acl_sid.id
|
||||
|
||||
where
|
||||
acli_sid.id = acl_object_identity.owner_sid
|
||||
|
||||
and acl_class.id = acl_object_identity.object_id_class
|
||||
|
||||
and (
|
||||
|
||||
(acl_object_identity.object_id_identity = 1 and acl_class.class = 'sample.contact.contact')
|
||||
or
|
||||
(acl_object_identity.object_id_identity = 2000 and acl_class.class = 'sample.contact.contact')
|
||||
|
||||
) order by acl_object_identity.object_id_identity asc, acl_entry.ace_order asc
|
||||
+101
-104
@@ -1,8 +1,5 @@
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import org.springframework.security.acls.domain.AclFormattingUtils;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
@@ -13,115 +10,115 @@ import junit.framework.TestCase;
|
||||
*/
|
||||
public class AclFormattingUtilsTests extends TestCase {
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public final void testDemergePatternsParametersConstraints() throws Exception {
|
||||
try {
|
||||
AclFormattingUtils.demergePatterns(null, "SOME STRING");
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public final void testDemergePatternsParametersConstraints() throws Exception {
|
||||
try {
|
||||
AclFormattingUtils.demergePatterns(null, "SOME STRING");
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
AclFormattingUtils.demergePatterns("SOME STRING", null);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
try {
|
||||
AclFormattingUtils.demergePatterns("SOME STRING", null);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
AclFormattingUtils.demergePatterns("SOME STRING", "LONGER SOME STRING");
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
try {
|
||||
AclFormattingUtils.demergePatterns("SOME STRING", "LONGER SOME STRING");
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
AclFormattingUtils.demergePatterns("SOME STRING", "SAME LENGTH");
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown IllegalArgumentException");
|
||||
}
|
||||
}
|
||||
try {
|
||||
AclFormattingUtils.demergePatterns("SOME STRING", "SAME LENGTH");
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown IllegalArgumentException");
|
||||
}
|
||||
}
|
||||
|
||||
public final void testDemergePatterns() throws Exception {
|
||||
String original = "...........................A...R";
|
||||
String removeBits = "...............................R";
|
||||
Assert.assertEquals("...........................A....", AclFormattingUtils
|
||||
.demergePatterns(original, removeBits));
|
||||
public final void testDemergePatterns() throws Exception {
|
||||
String original = "...........................A...R";
|
||||
String removeBits = "...............................R";
|
||||
Assert.assertEquals("...........................A....", AclFormattingUtils
|
||||
.demergePatterns(original, removeBits));
|
||||
|
||||
Assert.assertEquals("ABCDEF", AclFormattingUtils.demergePatterns("ABCDEF", "......"));
|
||||
Assert.assertEquals("......", AclFormattingUtils.demergePatterns("ABCDEF", "GHIJKL"));
|
||||
}
|
||||
|
||||
public final void testMergePatternsParametersConstraints() throws Exception {
|
||||
try {
|
||||
AclFormattingUtils.mergePatterns(null, "SOME STRING");
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
Assert.assertEquals("ABCDEF", AclFormattingUtils.demergePatterns("ABCDEF", "......"));
|
||||
Assert.assertEquals("......", AclFormattingUtils.demergePatterns("ABCDEF", "GHIJKL"));
|
||||
}
|
||||
|
||||
public final void testMergePatternsParametersConstraints() throws Exception {
|
||||
try {
|
||||
AclFormattingUtils.mergePatterns(null, "SOME STRING");
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
AclFormattingUtils.mergePatterns("SOME STRING", null);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
try {
|
||||
AclFormattingUtils.mergePatterns("SOME STRING", null);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
AclFormattingUtils.mergePatterns("SOME STRING", "LONGER SOME STRING");
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
try {
|
||||
AclFormattingUtils.mergePatterns("SOME STRING", "LONGER SOME STRING");
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
AclFormattingUtils.mergePatterns("SOME STRING", "SAME LENGTH");
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown IllegalArgumentException");
|
||||
}
|
||||
}
|
||||
try {
|
||||
AclFormattingUtils.mergePatterns("SOME STRING", "SAME LENGTH");
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown IllegalArgumentException");
|
||||
}
|
||||
}
|
||||
|
||||
public final void testMergePatterns() throws Exception {
|
||||
String original = "...............................R";
|
||||
String extraBits = "...........................A....";
|
||||
Assert.assertEquals("...........................A...R", AclFormattingUtils
|
||||
.mergePatterns(original, extraBits));
|
||||
public final void testMergePatterns() throws Exception {
|
||||
String original = "...............................R";
|
||||
String extraBits = "...........................A....";
|
||||
Assert.assertEquals("...........................A...R", AclFormattingUtils
|
||||
.mergePatterns(original, extraBits));
|
||||
|
||||
Assert.assertEquals("ABCDEF", AclFormattingUtils.mergePatterns("ABCDEF", "......"));
|
||||
Assert.assertEquals("GHIJKL", AclFormattingUtils.mergePatterns("ABCDEF", "GHIJKL"));
|
||||
}
|
||||
|
||||
public final void testBinaryPrints() throws Exception {
|
||||
Assert.assertEquals("............................****", AclFormattingUtils.printBinary(15));
|
||||
|
||||
try {
|
||||
AclFormattingUtils.printBinary(15, Permission.RESERVED_ON);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
AclFormattingUtils.printBinary(15, Permission.RESERVED_OFF);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
Assert.assertEquals("............................xxxx", AclFormattingUtils.printBinary(15, 'x'));
|
||||
}
|
||||
Assert.assertEquals("ABCDEF", AclFormattingUtils.mergePatterns("ABCDEF", "......"));
|
||||
Assert.assertEquals("GHIJKL", AclFormattingUtils.mergePatterns("ABCDEF", "GHIJKL"));
|
||||
}
|
||||
|
||||
public final void testBinaryPrints() throws Exception {
|
||||
Assert.assertEquals("............................****", AclFormattingUtils.printBinary(15));
|
||||
|
||||
try {
|
||||
AclFormattingUtils.printBinary(15, Permission.RESERVED_ON);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
AclFormattingUtils.printBinary(15, Permission.RESERVED_OFF);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
Assert.assertEquals("............................xxxx", AclFormattingUtils.printBinary(15, 'x'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
package org.springframework.security.acls;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.Test;
|
||||
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.acls.model.SidRetrievalStrategy;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 3.0
|
||||
*/
|
||||
public class AclPermissionEvaluatorTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void hasPermissionReturnsTrueIfAclGrantsPermission() throws Exception {
|
||||
AclService service = mock(AclService.class);
|
||||
AclPermissionEvaluator pe = new AclPermissionEvaluator(service);
|
||||
ObjectIdentity oid = mock(ObjectIdentity.class);
|
||||
ObjectIdentityRetrievalStrategy oidStrategy = mock(ObjectIdentityRetrievalStrategy.class);
|
||||
when(oidStrategy.getObjectIdentity(anyObject())).thenReturn(oid);
|
||||
pe.setObjectIdentityRetrievalStrategy(oidStrategy);
|
||||
pe.setSidRetrievalStrategy(mock(SidRetrievalStrategy.class));
|
||||
Acl acl = mock(Acl.class);
|
||||
|
||||
when(service.readAclById(any(ObjectIdentity.class), anyList())).thenReturn(acl);
|
||||
when(acl.isGranted(anyList(), anyList(), eq(false))).thenReturn(true);
|
||||
|
||||
assertTrue(pe.hasPermission(mock(Authentication.class), new Object(), "READ"));
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package org.springframework.security.acls;
|
||||
|
||||
/**
|
||||
* Dummy domain object class
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public final class TargetObject {
|
||||
|
||||
}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.UnloadedSidException;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
/**
|
||||
* Test class for {@link AccessControlEntryImpl}
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
public class AccessControlEntryTests extends TestCase {
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void testConstructorRequiredFields() throws Exception {
|
||||
// Check Acl field is present
|
||||
try {
|
||||
AccessControlEntry ace = new AccessControlEntryImpl(null, null, new PrincipalSid("johndoe"),
|
||||
BasePermission.ADMINISTRATION, true, true, true);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// Check Sid field is present
|
||||
try {
|
||||
AccessControlEntry ace = new AccessControlEntryImpl(null, new MockAcl(), null,
|
||||
BasePermission.ADMINISTRATION, true, true, true);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// Check Permission field is present
|
||||
try {
|
||||
AccessControlEntry ace = new AccessControlEntryImpl(null, new MockAcl(), new PrincipalSid("johndoe"), null,
|
||||
true, true, true);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testAccessControlEntryImplGetters() throws Exception {
|
||||
Acl mockAcl = new MockAcl();
|
||||
Sid sid = new PrincipalSid("johndoe");
|
||||
|
||||
// Create a sample entry
|
||||
AccessControlEntry ace = new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.ADMINISTRATION,
|
||||
true, true, true);
|
||||
|
||||
// and check every get() method
|
||||
Assert.assertEquals(new Long(1), ace.getId());
|
||||
Assert.assertEquals(mockAcl, ace.getAcl());
|
||||
Assert.assertEquals(sid, ace.getSid());
|
||||
Assert.assertTrue(ace.isGranting());
|
||||
Assert.assertEquals(BasePermission.ADMINISTRATION, ace.getPermission());
|
||||
Assert.assertTrue(((AuditableAccessControlEntry) ace).isAuditFailure());
|
||||
Assert.assertTrue(((AuditableAccessControlEntry) ace).isAuditSuccess());
|
||||
}
|
||||
|
||||
public void testEquals() throws Exception {
|
||||
Acl mockAcl = new MockAcl();
|
||||
Sid sid = new PrincipalSid("johndoe");
|
||||
|
||||
AccessControlEntry ace = new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.ADMINISTRATION,
|
||||
true, true, true);
|
||||
|
||||
Assert.assertFalse(ace.equals(null));
|
||||
Assert.assertFalse(ace.equals(new Long(100)));
|
||||
Assert.assertTrue(ace.equals(ace));
|
||||
Assert.assertTrue(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, true, true, true)));
|
||||
Assert.assertFalse(ace.equals(new AccessControlEntryImpl(new Long(2), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, true, true, true)));
|
||||
Assert.assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, new PrincipalSid("scott"),
|
||||
BasePermission.ADMINISTRATION, true, true, true)));
|
||||
Assert.assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.WRITE, true,
|
||||
true, true)));
|
||||
Assert.assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, false, true, true)));
|
||||
Assert.assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, true, false, true)));
|
||||
Assert.assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, true, true, false)));
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class MockAcl implements Acl {
|
||||
|
||||
public AccessControlEntry[] getEntries() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ObjectIdentity getObjectIdentity() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Sid getOwner() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Acl getParentAcl() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isEntriesInheriting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isGranted(Permission[] permission, Sid[] sids, boolean administrativeMode)
|
||||
throws NotFoundException, UnloadedSidException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isSidLoaded(Sid[] sids) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-105
@@ -1,105 +0,0 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.Mockery;
|
||||
import org.jmock.integration.junit4.JUnit4Mockery;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
|
||||
/**
|
||||
* Tests for {@link AccessControlEntryImpl}.
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
* @version $Id$
|
||||
*/
|
||||
public class AccessControlImplEntryTests {
|
||||
Mockery jmock = new JUnit4Mockery();
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@Test
|
||||
public void testConstructorRequiredFields() {
|
||||
// Check Acl field is present
|
||||
try {
|
||||
new AccessControlEntryImpl(null, null, new PrincipalSid("johndoe"),
|
||||
BasePermission.ADMINISTRATION, true, true, true);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
|
||||
// Check Sid field is present
|
||||
try {
|
||||
new AccessControlEntryImpl(null, jmock.mock(Acl.class), null,
|
||||
BasePermission.ADMINISTRATION, true, true, true);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
|
||||
// Check Permission field is present
|
||||
try {
|
||||
new AccessControlEntryImpl(null, jmock.mock(Acl.class), new PrincipalSid("johndoe"), null,
|
||||
true, true, true);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccessControlEntryImplGetters() {
|
||||
Acl mockAcl = jmock.mock(Acl.class);
|
||||
Sid sid = new PrincipalSid("johndoe");
|
||||
|
||||
// Create a sample entry
|
||||
AccessControlEntry ace = new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.ADMINISTRATION,
|
||||
true, true, true);
|
||||
|
||||
// and check every get() method
|
||||
assertEquals(new Long(1), ace.getId());
|
||||
assertEquals(mockAcl, ace.getAcl());
|
||||
assertEquals(sid, ace.getSid());
|
||||
assertTrue(ace.isGranting());
|
||||
assertEquals(BasePermission.ADMINISTRATION, ace.getPermission());
|
||||
assertTrue(((AuditableAccessControlEntry) ace).isAuditFailure());
|
||||
assertTrue(((AuditableAccessControlEntry) ace).isAuditSuccess());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
final Acl mockAcl = jmock.mock(Acl.class);
|
||||
final ObjectIdentity oid = jmock.mock(ObjectIdentity.class);
|
||||
jmock.checking(new Expectations() {{
|
||||
allowing(mockAcl).getObjectIdentity(); will(returnValue(oid));
|
||||
}});
|
||||
Sid sid = new PrincipalSid("johndoe");
|
||||
|
||||
AccessControlEntry ace = new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.ADMINISTRATION,
|
||||
true, true, true);
|
||||
|
||||
assertFalse(ace.equals(null));
|
||||
assertFalse(ace.equals(new Long(100)));
|
||||
assertTrue(ace.equals(ace));
|
||||
assertTrue(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, true, true, true)));
|
||||
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(2), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, true, true, true)));
|
||||
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, new PrincipalSid("scott"),
|
||||
BasePermission.ADMINISTRATION, true, true, true)));
|
||||
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.WRITE, true,
|
||||
true, true)));
|
||||
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, false, true, true)));
|
||||
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, true, false, true)));
|
||||
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
|
||||
BasePermission.ADMINISTRATION, true, true, false)));
|
||||
}
|
||||
}
|
||||
@@ -1,189 +1,242 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jmock.Mockery;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AlreadyExistsException;
|
||||
import org.springframework.security.acls.model.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.model.AuditableAcl;
|
||||
import org.springframework.security.acls.model.ChildrenExistException;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.MutableAclService;
|
||||
import org.springframework.security.acls.model.NotFoundException;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.OwnershipAcl;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AlreadyExistsException;
|
||||
import org.springframework.security.acls.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.AuditableAcl;
|
||||
import org.springframework.security.acls.ChildrenExistException;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.MutableAclService;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.OwnershipAcl;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.sid.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.TestingAuthenticationToken;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
|
||||
/**
|
||||
* Tests for {@link AclImpl}.
|
||||
*
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
public class AclImplTests {
|
||||
private static final String TARGET_CLASS = "org.springframework.security.acls.TargetObject";
|
||||
private static final List<Permission> READ = Arrays.asList(BasePermission.READ );
|
||||
private static final List<Permission> WRITE = Arrays.asList(BasePermission.WRITE);
|
||||
private static final List<Permission> CREATE = Arrays.asList(BasePermission.CREATE );
|
||||
private static final List<Permission> DELETE = Arrays.asList(BasePermission.DELETE );
|
||||
private static final List<Sid> SCOTT = Arrays.asList((Sid)new PrincipalSid("scott"));
|
||||
private static final List<Sid> BEN = Arrays.asList((Sid)new PrincipalSid("ben"));
|
||||
|
||||
Authentication auth = new TestingAuthenticationToken("joe", "ignored", "ROLE_ADMINISTRATOR");
|
||||
Mockery jmockCtx = new Mockery();
|
||||
AclAuthorizationStrategy mockAuthzStrategy;
|
||||
AuditLogger mockAuditLogger;
|
||||
ObjectIdentity objectIdentity = new ObjectIdentityImpl(TARGET_CLASS, 100);
|
||||
|
||||
public class AclImplTests extends TestCase {
|
||||
// ~ Methods ========================================================================================================
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
mockAuthzStrategy = mock(AclAuthorizationStrategy.class);
|
||||
mockAuditLogger = mock(AuditLogger.class);;
|
||||
auth.setAuthenticated(true);
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void constructorsRejectNullObjectIdentity() throws Exception {
|
||||
try {
|
||||
new AclImpl(null, 1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid("joe"));
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
new AclImpl(null, 1, mockAuthzStrategy, mockAuditLogger);
|
||||
}
|
||||
public void testConstructorsRejectNullParameters() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("johndoe", "ignored",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_ADMINISTRATOR") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void constructorsRejectNullId() throws Exception {
|
||||
try {
|
||||
new AclImpl(objectIdentity, null, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid("joe"));
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
new AclImpl(objectIdentity, null, mockAuthzStrategy, mockAuditLogger);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void constructorsRejectNullAclAuthzStrategy() throws Exception {
|
||||
try {
|
||||
new AclImpl(objectIdentity, 1, null, mockAuditLogger, null, null, true, new PrincipalSid("joe"));
|
||||
Acl acl = new AclImpl(null, new Long(1), strategy, auditLogger);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
new AclImpl(objectIdentity, 1, null, mockAuditLogger);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void constructorsRejectNullAuditLogger() throws Exception {
|
||||
try {
|
||||
new AclImpl(objectIdentity, 1, mockAuthzStrategy, null, null, null, true, new PrincipalSid("joe"));
|
||||
Acl acl = new AclImpl(identity, null, strategy, auditLogger);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
Acl acl = new AclImpl(identity, new Long(1), null, auditLogger);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
Acl acl = new AclImpl(identity, new Long(1), strategy, null);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
Acl acl = new AclImpl(null, new Long(1), strategy, auditLogger, null, null, true, new PrincipalSid("johndoe"));
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
Acl acl = new AclImpl(identity, null, strategy, auditLogger, null, null, true, new PrincipalSid("johndoe"));
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
Acl acl = new AclImpl(identity, new Long(1), null, auditLogger, null, null, true, new PrincipalSid("johndoe"));
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
Acl acl = new AclImpl(identity, new Long(1), strategy, null, null, null, true, new PrincipalSid("johndoe"));
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
Acl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, true, null);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
new AclImpl(objectIdentity, 1, mockAuthzStrategy, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insertAceRejectsNullParameters() throws Exception {
|
||||
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid(
|
||||
"joe"));
|
||||
public void testInsertAceRejectsNullParameters() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("johndoe", "ignored",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_ADMINISTRATOR") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
try {
|
||||
acl.insertAce(0, null, new GrantedAuthoritySid("ROLE_IGNORED"), true);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
acl.insertAce(0, BasePermission.READ, null, true);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insertAceAddsElementAtCorrectIndex() throws Exception {
|
||||
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid("joe"));
|
||||
public void testInsertAceAddsElementAtCorrectIndex() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("johndoe", "ignored",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_ADMINISTRATOR") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
// Insert one permission
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST1"), true);
|
||||
service.updateAcl(acl);
|
||||
// Check it was successfully added
|
||||
assertEquals(1, acl.getEntries().size());
|
||||
assertEquals(acl.getEntries().get(0).getAcl(), acl);
|
||||
assertEquals(acl.getEntries().get(0).getPermission(), BasePermission.READ);
|
||||
assertEquals(acl.getEntries().get(0).getSid(), new GrantedAuthoritySid("ROLE_TEST1"));
|
||||
assertEquals(1, acl.getEntries().length);
|
||||
assertEquals(acl.getEntries()[0].getAcl(), acl);
|
||||
assertEquals(acl.getEntries()[0].getPermission(), BasePermission.READ);
|
||||
assertEquals(acl.getEntries()[0].getSid(), new GrantedAuthoritySid("ROLE_TEST1"));
|
||||
|
||||
// Add a second permission
|
||||
acl.insertAce(1, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST2"), true);
|
||||
service.updateAcl(acl);
|
||||
// Check it was added on the last position
|
||||
assertEquals(2, acl.getEntries().size());
|
||||
assertEquals(acl.getEntries().get(1).getAcl(), acl);
|
||||
assertEquals(acl.getEntries().get(1).getPermission(), BasePermission.READ);
|
||||
assertEquals(acl.getEntries().get(1).getSid(), new GrantedAuthoritySid("ROLE_TEST2"));
|
||||
assertEquals(2, acl.getEntries().length);
|
||||
assertEquals(acl.getEntries()[1].getAcl(), acl);
|
||||
assertEquals(acl.getEntries()[1].getPermission(), BasePermission.READ);
|
||||
assertEquals(acl.getEntries()[1].getSid(), new GrantedAuthoritySid("ROLE_TEST2"));
|
||||
|
||||
// Add a third permission, after the first one
|
||||
acl.insertAce(1, BasePermission.WRITE, new GrantedAuthoritySid("ROLE_TEST3"), false);
|
||||
service.updateAcl(acl);
|
||||
assertEquals(3, acl.getEntries().size());
|
||||
assertEquals(3, acl.getEntries().length);
|
||||
// Check the third entry was added between the two existent ones
|
||||
assertEquals(acl.getEntries().get(0).getPermission(), BasePermission.READ);
|
||||
assertEquals(acl.getEntries().get(0).getSid(), new GrantedAuthoritySid("ROLE_TEST1"));
|
||||
assertEquals(acl.getEntries().get(1).getPermission(), BasePermission.WRITE);
|
||||
assertEquals(acl.getEntries().get(1).getSid(), new GrantedAuthoritySid("ROLE_TEST3"));
|
||||
assertEquals(acl.getEntries().get(2).getPermission(), BasePermission.READ);
|
||||
assertEquals(acl.getEntries().get(2).getSid(), new GrantedAuthoritySid("ROLE_TEST2"));
|
||||
assertEquals(acl.getEntries()[0].getPermission(), BasePermission.READ);
|
||||
assertEquals(acl.getEntries()[0].getSid(), new GrantedAuthoritySid("ROLE_TEST1"));
|
||||
assertEquals(acl.getEntries()[1].getPermission(), BasePermission.WRITE);
|
||||
assertEquals(acl.getEntries()[1].getSid(), new GrantedAuthoritySid("ROLE_TEST3"));
|
||||
assertEquals(acl.getEntries()[2].getPermission(), BasePermission.READ);
|
||||
assertEquals(acl.getEntries()[2].getSid(), new GrantedAuthoritySid("ROLE_TEST2"));
|
||||
}
|
||||
|
||||
@Test(expected=NotFoundException.class)
|
||||
public void insertAceFailsForNonExistentElement() throws Exception {
|
||||
MutableAcl acl = new AclImpl(objectIdentity,1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid(
|
||||
"joe"));
|
||||
public void testInsertAceFailsForInexistentElement() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("johndoe", "ignored",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_ADMINISTRATOR") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
// Insert one permission
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST1"), true);
|
||||
service.updateAcl(acl);
|
||||
|
||||
acl.insertAce(55, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST2"), true);
|
||||
try {
|
||||
acl.insertAce(55, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST2"), true);
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteAceKeepsInitialOrdering() throws Exception {
|
||||
MutableAcl acl = new AclImpl(objectIdentity,1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid(
|
||||
"joe"));
|
||||
public void testDeleteAceKeepsInitialOrdering() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("johndoe", "ignored",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_ADMINISTRATOR") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
// Add several permissions
|
||||
@@ -194,69 +247,84 @@ public class AclImplTests {
|
||||
|
||||
// Delete first permission and check the order of the remaining permissions is kept
|
||||
acl.deleteAce(0);
|
||||
assertEquals(2, acl.getEntries().size());
|
||||
assertEquals(acl.getEntries().get(0).getSid(), new GrantedAuthoritySid("ROLE_TEST2"));
|
||||
assertEquals(acl.getEntries().get(1).getSid(), new GrantedAuthoritySid("ROLE_TEST3"));
|
||||
assertEquals(2, acl.getEntries().length);
|
||||
assertEquals(acl.getEntries()[0].getSid(), new GrantedAuthoritySid("ROLE_TEST2"));
|
||||
assertEquals(acl.getEntries()[1].getSid(), new GrantedAuthoritySid("ROLE_TEST3"));
|
||||
|
||||
// Add one more permission and remove the permission in the middle
|
||||
acl.insertAce(2, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST4"), true);
|
||||
service.updateAcl(acl);
|
||||
acl.deleteAce(1);
|
||||
assertEquals(2, acl.getEntries().size());
|
||||
assertEquals(acl.getEntries().get(0).getSid(), new GrantedAuthoritySid("ROLE_TEST2"));
|
||||
assertEquals(acl.getEntries().get(1).getSid(), new GrantedAuthoritySid("ROLE_TEST4"));
|
||||
assertEquals(2, acl.getEntries().length);
|
||||
assertEquals(acl.getEntries()[0].getSid(), new GrantedAuthoritySid("ROLE_TEST2"));
|
||||
assertEquals(acl.getEntries()[1].getSid(), new GrantedAuthoritySid("ROLE_TEST4"));
|
||||
|
||||
// Remove remaining permissions
|
||||
acl.deleteAce(1);
|
||||
acl.deleteAce(0);
|
||||
assertEquals(0, acl.getEntries().size());
|
||||
assertEquals(0, acl.getEntries().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteAceFailsForNonExistentElement() throws Exception {
|
||||
public void testDeleteAceFailsForInexistentElement() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("johndoe", "ignored",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_ADMINISTRATOR") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
MutableAcl acl = new AclImpl(objectIdentity, (1), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"joe"));
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
try {
|
||||
acl.deleteAce(99);
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isGrantingRejectsEmptyParameters() throws Exception {
|
||||
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid(
|
||||
"joe"));
|
||||
Sid ben = new PrincipalSid("ben");
|
||||
public void testIsGrantingRejectsEmptyParameters() throws Exception {
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
|
||||
try {
|
||||
acl.isGranted(new ArrayList<Permission>(0), Arrays.asList(ben) , false);
|
||||
acl.isGranted(new Permission[] {}, new Sid[] { new PrincipalSid("ben") }, false);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
acl.isGranted(READ, new ArrayList<Sid>(0), false);
|
||||
acl.isGranted(new Permission[] { BasePermission.READ }, new Sid[] {}, false);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isGrantingGrantsAccessForAclWithNoParent() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored", "ROLE_GENERAL","ROLE_GUEST");
|
||||
public void testIsGrantingGrantsAccessForAclWithNoParent() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored", new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL"), new GrantedAuthorityImpl("ROLE_GUEST") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
ObjectIdentity rootOid = new ObjectIdentityImpl(TARGET_CLASS, 100);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity rootOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
|
||||
// Create an ACL which owner is not the authenticated principal
|
||||
MutableAcl rootAcl = new AclImpl(rootOid, 1, mockAuthzStrategy, mockAuditLogger, null, null, false, new PrincipalSid(
|
||||
"joe"));
|
||||
MutableAcl rootAcl = new AclImpl(rootOid, new Long(1), strategy, auditLogger, null, null, false, new PrincipalSid(
|
||||
"johndoe"));
|
||||
|
||||
// Grant some permissions
|
||||
rootAcl.insertAce(0, BasePermission.READ, new PrincipalSid("ben"), false);
|
||||
@@ -265,50 +333,59 @@ public class AclImplTests {
|
||||
rootAcl.insertAce(3, BasePermission.WRITE, new GrantedAuthoritySid("WRITE_ACCESS_ROLE"), true);
|
||||
|
||||
// Check permissions granting
|
||||
List<Permission> permissions = Arrays.asList(BasePermission.READ, BasePermission.CREATE);
|
||||
List<Sid> sids = Arrays.asList(new PrincipalSid("ben"), new GrantedAuthoritySid("ROLE_GUEST"));
|
||||
Permission[] permissions = new Permission[] { BasePermission.READ, BasePermission.CREATE };
|
||||
Sid[] sids = new Sid[] { new PrincipalSid("ben"), new GrantedAuthoritySid("ROLE_GUEST") };
|
||||
assertFalse(rootAcl.isGranted(permissions, sids, false));
|
||||
try {
|
||||
rootAcl.isGranted(permissions, SCOTT, false);
|
||||
rootAcl.isGranted(permissions, new Sid[] { new PrincipalSid("scott") }, false);
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
assertTrue(rootAcl.isGranted(WRITE, SCOTT, false));
|
||||
assertFalse(rootAcl.isGranted(WRITE,
|
||||
Arrays.asList(new PrincipalSid("rod"), new GrantedAuthoritySid("WRITE_ACCESS_ROLE")), false));
|
||||
assertTrue(rootAcl.isGranted(WRITE, Arrays.asList(new GrantedAuthoritySid("WRITE_ACCESS_ROLE"), new PrincipalSid("rod")), false));
|
||||
assertTrue(rootAcl.isGranted(new Permission[] { BasePermission.WRITE }, new Sid[] { new PrincipalSid("scott") },
|
||||
false));
|
||||
assertFalse(rootAcl.isGranted(new Permission[] { BasePermission.WRITE }, new Sid[] { new PrincipalSid("rod"),
|
||||
new GrantedAuthoritySid("WRITE_ACCESS_ROLE") }, false));
|
||||
assertTrue(rootAcl.isGranted(new Permission[] { BasePermission.WRITE }, new Sid[] {
|
||||
new GrantedAuthoritySid("WRITE_ACCESS_ROLE"), new PrincipalSid("rod") }, false));
|
||||
try {
|
||||
// Change the type of the Sid and check the granting process
|
||||
rootAcl.isGranted(WRITE, Arrays.asList(new GrantedAuthoritySid("rod"), new PrincipalSid("WRITE_ACCESS_ROLE")), false);
|
||||
rootAcl.isGranted(new Permission[] { BasePermission.WRITE }, new Sid[] { new GrantedAuthoritySid("rod"),
|
||||
new PrincipalSid("WRITE_ACCESS_ROLE") }, false);
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isGrantingGrantsAccessForInheritableAcls() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored","ROLE_GENERAL");
|
||||
public void testIsGrantingGrantsAccessForInheritableAcls() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
ObjectIdentity grandParentOid = new ObjectIdentityImpl(TARGET_CLASS, 100);
|
||||
ObjectIdentity parentOid1 = new ObjectIdentityImpl(TARGET_CLASS, 101);
|
||||
ObjectIdentity parentOid2 = new ObjectIdentityImpl(TARGET_CLASS, 102);
|
||||
ObjectIdentity childOid1 = new ObjectIdentityImpl(TARGET_CLASS, 103);
|
||||
ObjectIdentity childOid2 = new ObjectIdentityImpl(TARGET_CLASS, 104);
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity grandParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity parentOid1 = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity parentOid2 = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
ObjectIdentity childOid1 = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(103));
|
||||
ObjectIdentity childOid2 = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(104));
|
||||
|
||||
// Create ACLs
|
||||
MutableAcl grandParentAcl = new AclImpl(grandParentOid, 1, mockAuthzStrategy, mockAuditLogger, null, null, false,
|
||||
new PrincipalSid("joe"));
|
||||
MutableAcl parentAcl1 = new AclImpl(parentOid1, 2, mockAuthzStrategy, mockAuditLogger, null, null, true,
|
||||
new PrincipalSid("joe"));
|
||||
MutableAcl parentAcl2 = new AclImpl(parentOid2, 3, mockAuthzStrategy, mockAuditLogger, null, null, true,
|
||||
new PrincipalSid("joe"));
|
||||
MutableAcl childAcl1 = new AclImpl(childOid1, 4, mockAuthzStrategy, mockAuditLogger, null, null, true,
|
||||
new PrincipalSid("joe"));
|
||||
MutableAcl childAcl2 = new AclImpl(childOid2, 4, mockAuthzStrategy, mockAuditLogger, null, null, false,
|
||||
new PrincipalSid("joe"));
|
||||
MutableAcl grandParentAcl = new AclImpl(grandParentOid, new Long(1), strategy, auditLogger, null, null, false,
|
||||
new PrincipalSid("johndoe"));
|
||||
MutableAcl parentAcl1 = new AclImpl(parentOid1, new Long(2), strategy, auditLogger, null, null, true,
|
||||
new PrincipalSid("johndoe"));
|
||||
MutableAcl parentAcl2 = new AclImpl(parentOid2, new Long(3), strategy, auditLogger, null, null, true,
|
||||
new PrincipalSid("johndoe"));
|
||||
MutableAcl childAcl1 = new AclImpl(childOid1, new Long(4), strategy, auditLogger, null, null, true,
|
||||
new PrincipalSid("johndoe"));
|
||||
MutableAcl childAcl2 = new AclImpl(childOid2, new Long(4), strategy, auditLogger, null, null, false,
|
||||
new PrincipalSid("johndoe"));
|
||||
|
||||
// Create hierarchies
|
||||
childAcl2.setParent(childAcl1);
|
||||
@@ -327,33 +404,45 @@ public class AclImplTests {
|
||||
childAcl1.insertAce(0, BasePermission.CREATE, new PrincipalSid("scott"), true);
|
||||
|
||||
// Check granting process for parent1
|
||||
assertTrue(parentAcl1.isGranted(READ, SCOTT, false));
|
||||
assertTrue(parentAcl1.isGranted(READ, Arrays.asList((Sid)new GrantedAuthoritySid("ROLE_USER_READ")), false));
|
||||
assertTrue(parentAcl1.isGranted(WRITE, BEN, false));
|
||||
assertFalse(parentAcl1.isGranted(DELETE, BEN, false));
|
||||
assertFalse(parentAcl1.isGranted(DELETE, SCOTT, false));
|
||||
assertTrue(parentAcl1.isGranted(new Permission[] { BasePermission.READ }, new Sid[] { new PrincipalSid("scott") },
|
||||
false));
|
||||
assertTrue(parentAcl1.isGranted(new Permission[] { BasePermission.READ }, new Sid[] { new GrantedAuthoritySid(
|
||||
"ROLE_USER_READ") }, false));
|
||||
assertTrue(parentAcl1.isGranted(new Permission[] { BasePermission.WRITE }, new Sid[] { new PrincipalSid("ben") },
|
||||
false));
|
||||
assertFalse(parentAcl1.isGranted(new Permission[] { BasePermission.DELETE }, new Sid[] { new PrincipalSid("ben") },
|
||||
false));
|
||||
assertFalse(parentAcl1.isGranted(new Permission[] { BasePermission.DELETE },
|
||||
new Sid[] { new PrincipalSid("scott") }, false));
|
||||
|
||||
// Check granting process for parent2
|
||||
assertTrue(parentAcl2.isGranted(CREATE, BEN, false));
|
||||
assertTrue(parentAcl2.isGranted(WRITE, BEN, false));
|
||||
assertFalse(parentAcl2.isGranted(DELETE, BEN, false));
|
||||
assertTrue(parentAcl2.isGranted(new Permission[] { BasePermission.CREATE }, new Sid[] { new PrincipalSid("ben") },
|
||||
false));
|
||||
assertTrue(parentAcl2.isGranted(new Permission[] { BasePermission.WRITE }, new Sid[] { new PrincipalSid("ben") },
|
||||
false));
|
||||
assertFalse(parentAcl2.isGranted(new Permission[] { BasePermission.DELETE }, new Sid[] { new PrincipalSid("ben") },
|
||||
false));
|
||||
|
||||
// Check granting process for child1
|
||||
assertTrue(childAcl1.isGranted(CREATE, SCOTT,
|
||||
assertTrue(childAcl1.isGranted(new Permission[] { BasePermission.CREATE }, new Sid[] { new PrincipalSid("scott") },
|
||||
false));
|
||||
assertTrue(childAcl1.isGranted(new Permission[] { BasePermission.READ }, new Sid[] { new GrantedAuthoritySid(
|
||||
"ROLE_USER_READ") }, false));
|
||||
assertFalse(childAcl1.isGranted(new Permission[] { BasePermission.DELETE }, new Sid[] { new PrincipalSid("ben") },
|
||||
false));
|
||||
assertTrue(childAcl1.isGranted(READ, Arrays.asList((Sid)new GrantedAuthoritySid("ROLE_USER_READ")), false));
|
||||
assertFalse(childAcl1.isGranted(DELETE, BEN, false));
|
||||
|
||||
// Check granting process for child2 (doesn't inherit the permissions from its parent)
|
||||
try {
|
||||
assertTrue(childAcl2.isGranted(CREATE, SCOTT, false));
|
||||
assertTrue(childAcl2.isGranted(new Permission[] { BasePermission.CREATE },
|
||||
new Sid[] { new PrincipalSid("scott") }, false));
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
assertTrue(childAcl2.isGranted(CREATE, Arrays.asList((Sid)new PrincipalSid("joe")), false));
|
||||
assertTrue(childAcl2.isGranted(new Permission[] { BasePermission.CREATE }, new Sid[] { new PrincipalSid(
|
||||
"johndoe") }, false));
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
@@ -361,13 +450,18 @@ public class AclImplTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updatedAceValuesAreCorrectlyReflectedInAcl() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored","ROLE_GENERAL");
|
||||
public void testUpdateAce() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, false, new PrincipalSid(
|
||||
"joe"));
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, false, new PrincipalSid(
|
||||
"johndoe"));
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
@@ -375,9 +469,9 @@ public class AclImplTests {
|
||||
acl.insertAce(2, BasePermission.CREATE, new PrincipalSid("ben"), true);
|
||||
service.updateAcl(acl);
|
||||
|
||||
assertEquals(acl.getEntries().get(0).getPermission(), BasePermission.READ);
|
||||
assertEquals(acl.getEntries().get(1).getPermission(), BasePermission.WRITE);
|
||||
assertEquals(acl.getEntries().get(2).getPermission(), BasePermission.CREATE);
|
||||
assertEquals(acl.getEntries()[0].getPermission(), BasePermission.READ);
|
||||
assertEquals(acl.getEntries()[1].getPermission(), BasePermission.WRITE);
|
||||
assertEquals(acl.getEntries()[2].getPermission(), BasePermission.CREATE);
|
||||
|
||||
// Change each permission
|
||||
acl.updateAce(0, BasePermission.CREATE);
|
||||
@@ -385,127 +479,105 @@ public class AclImplTests {
|
||||
acl.updateAce(2, BasePermission.READ);
|
||||
|
||||
// Check the change was successfuly made
|
||||
assertEquals(acl.getEntries().get(0).getPermission(), BasePermission.CREATE);
|
||||
assertEquals(acl.getEntries().get(1).getPermission(), BasePermission.DELETE);
|
||||
assertEquals(acl.getEntries().get(2).getPermission(), BasePermission.READ);
|
||||
assertEquals(acl.getEntries()[0].getPermission(), BasePermission.CREATE);
|
||||
assertEquals(acl.getEntries()[1].getPermission(), BasePermission.DELETE);
|
||||
assertEquals(acl.getEntries()[2].getPermission(), BasePermission.READ);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void auditableEntryFlagsAreUpdatedCorrectly() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored", "ROLE_AUDITING", "ROLE_GENERAL");
|
||||
public void testUpdateAuditing() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored", new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_AUDITING"), new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, false, new PrincipalSid(
|
||||
"joe"));
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, false, new PrincipalSid(
|
||||
"johndoe"));
|
||||
MockAclService service = new MockAclService();
|
||||
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
acl.insertAce(1, BasePermission.WRITE, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
service.updateAcl(acl);
|
||||
|
||||
assertFalse(((AuditableAccessControlEntry) acl.getEntries().get(0)).isAuditFailure());
|
||||
assertFalse(((AuditableAccessControlEntry) acl.getEntries().get(1)).isAuditFailure());
|
||||
assertFalse(((AuditableAccessControlEntry) acl.getEntries().get(0)).isAuditSuccess());
|
||||
assertFalse(((AuditableAccessControlEntry) acl.getEntries().get(1)).isAuditSuccess());
|
||||
assertFalse(((AuditableAccessControlEntry) acl.getEntries()[0]).isAuditFailure());
|
||||
assertFalse(((AuditableAccessControlEntry) acl.getEntries()[1]).isAuditFailure());
|
||||
assertFalse(((AuditableAccessControlEntry) acl.getEntries()[0]).isAuditSuccess());
|
||||
assertFalse(((AuditableAccessControlEntry) acl.getEntries()[1]).isAuditSuccess());
|
||||
|
||||
// Change each permission
|
||||
((AuditableAcl) acl).updateAuditing(0, true, true);
|
||||
((AuditableAcl) acl).updateAuditing(1, true, true);
|
||||
|
||||
// Check the change was successfuly made
|
||||
assertTrue(((AuditableAccessControlEntry) acl.getEntries().get(0)).isAuditFailure());
|
||||
assertTrue(((AuditableAccessControlEntry) acl.getEntries().get(1)).isAuditFailure());
|
||||
assertTrue(((AuditableAccessControlEntry) acl.getEntries().get(0)).isAuditSuccess());
|
||||
assertTrue(((AuditableAccessControlEntry) acl.getEntries().get(1)).isAuditSuccess());
|
||||
assertTrue(((AuditableAccessControlEntry) acl.getEntries()[0]).isAuditFailure());
|
||||
assertTrue(((AuditableAccessControlEntry) acl.getEntries()[1]).isAuditFailure());
|
||||
assertTrue(((AuditableAccessControlEntry) acl.getEntries()[0]).isAuditSuccess());
|
||||
assertTrue(((AuditableAccessControlEntry) acl.getEntries()[1]).isAuditSuccess());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gettersAndSettersAreConsistent() throws Exception {
|
||||
public void testGettersSetters() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored", new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, (100));
|
||||
ObjectIdentity identity2 = new ObjectIdentityImpl(TARGET_CLASS, (101));
|
||||
MutableAcl acl = new AclImpl(identity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true,
|
||||
new PrincipalSid("joe"));
|
||||
MutableAcl parentAcl = new AclImpl(identity2, 2, mockAuthzStrategy, mockAuditLogger, null, null, true,
|
||||
new PrincipalSid("joe"));
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL"), new GrantedAuthorityImpl("ROLE_GENERAL"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity identity2 = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
MutableAcl parentAcl = new AclImpl(identity2, new Long(2), strategy, auditLogger, null, null, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
MockAclService service = new MockAclService();
|
||||
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
acl.insertAce(1, BasePermission.WRITE, new GrantedAuthoritySid("ROLE_USER_READ"), true);
|
||||
service.updateAcl(acl);
|
||||
|
||||
assertEquals(acl.getId(), 1);
|
||||
|
||||
assertEquals(acl.getId(), new Long(1));
|
||||
assertEquals(acl.getObjectIdentity(), identity);
|
||||
assertEquals(acl.getOwner(), new PrincipalSid("joe"));
|
||||
assertEquals(acl.getOwner(), new PrincipalSid("johndoe"));
|
||||
assertNull(acl.getParentAcl());
|
||||
assertTrue(acl.isEntriesInheriting());
|
||||
assertEquals(2, acl.getEntries().size());
|
||||
|
||||
assertEquals(2, acl.getEntries().length);
|
||||
|
||||
acl.setParent(parentAcl);
|
||||
assertEquals(acl.getParentAcl(), parentAcl);
|
||||
|
||||
|
||||
acl.setEntriesInheriting(false);
|
||||
assertFalse(acl.isEntriesInheriting());
|
||||
|
||||
|
||||
((OwnershipAcl) acl).setOwner(new PrincipalSid("ben"));
|
||||
assertEquals(acl.getOwner(), new PrincipalSid("ben"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSidLoadedBehavesAsExpected() throws Exception {
|
||||
List<Sid> loadedSids = Arrays.asList(new PrincipalSid("ben"), new GrantedAuthoritySid("ROLE_IGNORED"));
|
||||
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, loadedSids, true,
|
||||
new PrincipalSid("joe"));
|
||||
|
||||
|
||||
public void testIsSidLoaded() throws Exception {
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL"), new GrantedAuthorityImpl("ROLE_GENERAL"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
|
||||
Sid[] loadedSids = new Sid[] { new PrincipalSid("ben"), new GrantedAuthoritySid("ROLE_IGNORED") };
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), strategy, auditLogger, null, loadedSids, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
|
||||
assertTrue(acl.isSidLoaded(loadedSids));
|
||||
assertTrue(acl.isSidLoaded(Arrays.asList(new GrantedAuthoritySid("ROLE_IGNORED"), new PrincipalSid("ben"))));
|
||||
assertTrue(acl.isSidLoaded(Arrays.asList((Sid)new GrantedAuthoritySid("ROLE_IGNORED"))));
|
||||
assertTrue(acl.isSidLoaded(BEN));
|
||||
assertTrue(acl.isSidLoaded(new Sid[] { new GrantedAuthoritySid("ROLE_IGNORED"), new PrincipalSid("ben") }));
|
||||
assertTrue(acl.isSidLoaded(new Sid[] { new GrantedAuthoritySid("ROLE_IGNORED")}));
|
||||
assertTrue(acl.isSidLoaded(new Sid[] { new PrincipalSid("ben") }));
|
||||
assertTrue(acl.isSidLoaded(null));
|
||||
assertTrue(acl.isSidLoaded(new ArrayList<Sid>(0)));
|
||||
assertTrue(acl.isSidLoaded(Arrays.asList((Sid)new GrantedAuthoritySid("ROLE_IGNORED"), new GrantedAuthoritySid("ROLE_IGNORED"))));
|
||||
assertFalse(acl.isSidLoaded(Arrays.asList((Sid)new GrantedAuthoritySid("ROLE_GENERAL"), new GrantedAuthoritySid("ROLE_IGNORED"))));
|
||||
assertFalse(acl.isSidLoaded(Arrays.asList((Sid)new GrantedAuthoritySid("ROLE_IGNORED"), new GrantedAuthoritySid("ROLE_GENERAL"))));
|
||||
assertTrue(acl.isSidLoaded(new Sid[] { }));
|
||||
assertTrue(acl.isSidLoaded(new Sid[] { new GrantedAuthoritySid("ROLE_IGNORED"), new GrantedAuthoritySid("ROLE_IGNORED") }));
|
||||
assertFalse(acl.isSidLoaded(new Sid[] { new GrantedAuthoritySid("ROLE_GENERAL"), new GrantedAuthoritySid("ROLE_IGNORED") }));
|
||||
assertFalse(acl.isSidLoaded(new Sid[] { new GrantedAuthoritySid("ROLE_IGNORED"), new GrantedAuthoritySid("ROLE_GENERAL") }));
|
||||
}
|
||||
|
||||
@Test(expected=NotFoundException.class)
|
||||
public void insertAceRaisesNotFoundExceptionForIndexLessThanZero() throws Exception {
|
||||
AclImpl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true,
|
||||
new PrincipalSid("joe"));
|
||||
acl.insertAce(-1, mock(Permission.class), mock(Sid.class), true);
|
||||
}
|
||||
|
||||
@Test(expected=NotFoundException.class)
|
||||
public void deleteAceRaisesNotFoundExceptionForIndexLessThanZero() throws Exception {
|
||||
AclImpl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true,
|
||||
new PrincipalSid("joe"));
|
||||
acl.deleteAce(-1);
|
||||
}
|
||||
|
||||
@Test(expected=NotFoundException.class)
|
||||
public void insertAceRaisesNotFoundExceptionForIndexGreaterThanSize() throws Exception {
|
||||
AclImpl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true,
|
||||
new PrincipalSid("joe"));
|
||||
// Insert at zero, OK.
|
||||
acl.insertAce(0, mock(Permission.class), mock(Sid.class), true);
|
||||
// Size is now 1
|
||||
acl.insertAce(2, mock(Permission.class), mock(Sid.class), true);
|
||||
}
|
||||
|
||||
// SEC-1151
|
||||
@Test(expected=NotFoundException.class)
|
||||
public void deleteAceRaisesNotFoundExceptionForIndexEqualToSize() throws Exception {
|
||||
AclImpl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true,
|
||||
new PrincipalSid("joe"));
|
||||
acl.insertAce(0, mock(Permission.class), mock(Sid.class), true);
|
||||
// Size is now 1
|
||||
acl.deleteAce(1);
|
||||
}
|
||||
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
// ~ Inner Classes ==================================================================================================
|
||||
|
||||
private class MockAclService implements MutableAclService {
|
||||
public MutableAcl createAcl(ObjectIdentity objectIdentity) throws AlreadyExistsException {
|
||||
@@ -519,9 +591,8 @@ public class AclImplTests {
|
||||
* Mock implementation that populates the aces list with fully initialized AccessControlEntries
|
||||
* @see org.springframework.security.acls.MutableAclService#updateAcl(org.springframework.security.acls.MutableAcl)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public MutableAcl updateAcl(MutableAcl acl) throws NotFoundException {
|
||||
List<AccessControlEntry> oldAces = acl.getEntries();
|
||||
AccessControlEntry[] oldAces = acl.getEntries();
|
||||
Field acesField = FieldUtils.getField(AclImpl.class, "aces");
|
||||
acesField.setAccessible(true);
|
||||
List newAces;
|
||||
@@ -529,10 +600,10 @@ public class AclImplTests {
|
||||
newAces = (List) acesField.get(acl);
|
||||
newAces.clear();
|
||||
|
||||
for (int i = 0; i < oldAces.size(); i++) {
|
||||
AccessControlEntry ac = oldAces.get(i);
|
||||
for (int i = 0; i < oldAces.length; i++) {
|
||||
AccessControlEntry ac = oldAces[i];
|
||||
// Just give an ID to all this acl's aces, rest of the fields are just copied
|
||||
newAces.add(new AccessControlEntryImpl((i + 1), ac.getAcl(), ac.getSid(), ac.getPermission(), ac
|
||||
newAces.add(new AccessControlEntryImpl(new Long(i + 1), ac.getAcl(), ac.getSid(), ac.getPermission(), ac
|
||||
.isGranting(), ((AuditableAccessControlEntry) ac).isAuditSuccess(),
|
||||
((AuditableAccessControlEntry) ac).isAuditFailure()));
|
||||
}
|
||||
@@ -544,7 +615,7 @@ public class AclImplTests {
|
||||
return acl;
|
||||
}
|
||||
|
||||
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
|
||||
public ObjectIdentity[] findChildren(ObjectIdentity parentIdentity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -552,15 +623,15 @@ public class AclImplTests {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException {
|
||||
public Acl readAclById(ObjectIdentity object, Sid[] sids) throws NotFoundException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects) throws NotFoundException {
|
||||
public Map readAclsById(ObjectIdentity[] objects) throws NotFoundException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) throws NotFoundException {
|
||||
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids) throws NotFoundException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+259
-223
@@ -3,258 +3,294 @@ package org.springframework.security.acls.domain;
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.NotFoundException;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.TestingAuthenticationToken;
|
||||
|
||||
/**
|
||||
* Test class for {@link AclAuthorizationStrategyImpl} and {@link AclImpl}
|
||||
* security checks.
|
||||
*
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
public class AclImplementationSecurityCheckTests extends TestCase {
|
||||
private static final String TARGET_CLASS = "org.springframework.security.acls.TargetObject";
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
protected void setUp() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
protected void tearDown() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
public void testSecurityCheckNoACEs() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
public void testSecurityCheckNoACEs() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password","ROLE_GENERAL","ROLE_AUDITING","ROLE_OWNERSHIP");
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
Acl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
|
||||
Acl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
// Create another authorization strategy
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy2 = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO"),
|
||||
new GrantedAuthorityImpl("ROLE_THREE") });
|
||||
Acl acl2 = new AclImpl(identity, new Long(1), aclAuthorizationStrategy2, new ConsoleAuditLogger());
|
||||
// Check access in case the principal has no authorization rights
|
||||
try {
|
||||
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
public void testSecurityCheckWithMultipleACEs() throws Exception {
|
||||
// Create a simple authentication with ROLE_GENERAL
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
// Create another authorization strategy
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy2 = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO"),
|
||||
new GrantedAuthorityImpl("ROLE_THREE") });
|
||||
Acl acl2 = new AclImpl(identity, new Long(1), aclAuthorizationStrategy2, new ConsoleAuditLogger());
|
||||
// Check access in case the principal has no authorization rights
|
||||
try {
|
||||
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
}
|
||||
}
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
// Authorization strategy will require a different role for each access
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
|
||||
public void testSecurityCheckWithMultipleACEs() throws Exception {
|
||||
// Create a simple authentication with ROLE_GENERAL
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
// Let's give the principal the ADMINISTRATION permission, without
|
||||
// granting access
|
||||
MutableAcl aclFirstDeny = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
aclFirstDeny.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), false);
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||
// Authorization strategy will require a different role for each access
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
// The CHANGE_GENERAL test should pass as the principal has ROLE_GENERAL
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
// The CHANGE_AUDITING and CHANGE_OWNERSHIP should fail since the
|
||||
// principal doesn't have these authorities,
|
||||
// nor granting access
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.fail("It should have thrown AccessDeniedException");
|
||||
}
|
||||
catch (AccessDeniedException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.fail("It should have thrown AccessDeniedException");
|
||||
}
|
||||
catch (AccessDeniedException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// Let's give the principal the ADMINISTRATION permission, without
|
||||
// granting access
|
||||
MutableAcl aclFirstDeny = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
aclFirstDeny.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), false);
|
||||
// Add granting access to this principal
|
||||
aclFirstDeny.insertAce(1, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
// and try again for CHANGE_AUDITING - the first ACE's granting flag
|
||||
// (false) will deny this access
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.fail("It should have thrown AccessDeniedException");
|
||||
}
|
||||
catch (AccessDeniedException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// The CHANGE_GENERAL test should pass as the principal has ROLE_GENERAL
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
// Create another ACL and give the principal the ADMINISTRATION
|
||||
// permission, with granting access
|
||||
MutableAcl aclFirstAllow = new AclImpl(identity, new Long(1), aclAuthorizationStrategy,
|
||||
new ConsoleAuditLogger());
|
||||
aclFirstAllow.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
|
||||
// The CHANGE_AUDITING and CHANGE_OWNERSHIP should fail since the
|
||||
// principal doesn't have these authorities,
|
||||
// nor granting access
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.fail("It should have thrown AccessDeniedException");
|
||||
}
|
||||
catch (AccessDeniedException expected) {
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.fail("It should have thrown AccessDeniedException");
|
||||
}
|
||||
catch (AccessDeniedException expected) {
|
||||
}
|
||||
// The CHANGE_AUDITING test should pass as there is one ACE with
|
||||
// granting access
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstAllow, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
|
||||
// Add granting access to this principal
|
||||
aclFirstDeny.insertAce(1, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
// and try again for CHANGE_AUDITING - the first ACE's granting flag
|
||||
// (false) will deny this access
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.fail("It should have thrown AccessDeniedException");
|
||||
}
|
||||
catch (AccessDeniedException expected) {
|
||||
}
|
||||
// Add a deny ACE and test again for CHANGE_AUDITING
|
||||
aclFirstAllow.insertAce(1, BasePermission.ADMINISTRATION, new PrincipalSid(auth), false);
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstAllow, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
|
||||
// Create another ACL and give the principal the ADMINISTRATION
|
||||
// permission, with granting access
|
||||
MutableAcl aclFirstAllow = new AclImpl(identity, new Long(1), aclAuthorizationStrategy,
|
||||
new ConsoleAuditLogger());
|
||||
aclFirstAllow.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
// Create an ACL with no ACE
|
||||
MutableAcl aclNoACE = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclNoACE, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
// and still grant access for CHANGE_GENERAL
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclNoACE, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.fail("It shouldn't have thrown NotFoundException");
|
||||
}
|
||||
}
|
||||
|
||||
// The CHANGE_AUDITING test should pass as there is one ACE with
|
||||
// granting access
|
||||
public void testSecurityCheckWithInheritableACEs() throws Exception {
|
||||
// Create a simple authentication with ROLE_GENERAL
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstAllow, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
// Authorization strategy will require a different role for each access
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
|
||||
// Add a deny ACE and test again for CHANGE_AUDITING
|
||||
aclFirstAllow.insertAce(1, BasePermission.ADMINISTRATION, new PrincipalSid(auth), false);
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclFirstAllow, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
// Let's give the principal an ADMINISTRATION permission, with granting
|
||||
// access
|
||||
MutableAcl parentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
parentAcl.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
MutableAcl childAcl = new AclImpl(identity, new Long(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
|
||||
// Create an ACL with no ACE
|
||||
MutableAcl aclNoACE = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclNoACE, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
// and still grant access for CHANGE_GENERAL
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(aclNoACE, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.fail("It shouldn't have thrown NotFoundException");
|
||||
}
|
||||
}
|
||||
// Check against the 'child' acl, which doesn't offer any authorization
|
||||
// rights on CHANGE_OWNERSHIP
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
public void testSecurityCheckWithInheritableACEs() throws Exception {
|
||||
// Create a simple authentication with ROLE_GENERAL
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password",
|
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
// Link the child with its parent and test again against the
|
||||
// CHANGE_OWNERSHIP right
|
||||
childAcl.setParent(parentAcl);
|
||||
childAcl.setEntriesInheriting(true);
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.fail("It shouldn't have thrown NotFoundException");
|
||||
}
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||
// Authorization strategy will require a different role for each access
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
// Create a root parent and link it to the middle parent
|
||||
MutableAcl rootParentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy,
|
||||
new ConsoleAuditLogger());
|
||||
parentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
rootParentAcl.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
parentAcl.setEntriesInheriting(true);
|
||||
parentAcl.setParent(rootParentAcl);
|
||||
childAcl.setParent(parentAcl);
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.fail("It shouldn't have thrown NotFoundException");
|
||||
}
|
||||
}
|
||||
|
||||
// Let's give the principal an ADMINISTRATION permission, with granting
|
||||
// access
|
||||
MutableAcl parentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
parentAcl.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
MutableAcl childAcl = new AclImpl(identity, new Long(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
public void testSecurityCheckPrincipalOwner() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_ONE"),
|
||||
new GrantedAuthorityImpl("ROLE_ONE") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
// Check against the 'child' acl, which doesn't offer any authorization
|
||||
// rights on CHANGE_OWNERSHIP
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
|
||||
// Link the child with its parent and test again against the
|
||||
// CHANGE_OWNERSHIP right
|
||||
childAcl.setParent(parentAcl);
|
||||
childAcl.setEntriesInheriting(true);
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.fail("It shouldn't have thrown NotFoundException");
|
||||
}
|
||||
|
||||
// Create a root parent and link it to the middle parent
|
||||
MutableAcl rootParentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy,
|
||||
new ConsoleAuditLogger());
|
||||
parentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
rootParentAcl.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
|
||||
parentAcl.setEntriesInheriting(true);
|
||||
parentAcl.setParent(rootParentAcl);
|
||||
childAcl.setParent(parentAcl);
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.fail("It shouldn't have thrown NotFoundException");
|
||||
}
|
||||
}
|
||||
|
||||
public void testSecurityCheckPrincipalOwner() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_ONE"),
|
||||
new GrantedAuthorityImpl("ROLE_ONE") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
|
||||
Acl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger(), null, null,
|
||||
false, new PrincipalSid(auth));
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
}
|
||||
Acl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger(), null, null,
|
||||
false, new PrincipalSid(auth));
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_GENERAL);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_AUDITING);
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
try {
|
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (AccessDeniedException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown AccessDeniedException");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,92 +1,137 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.Mockery;
|
||||
import org.jmock.integration.junit4.JUnit4Mockery;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.model.AuditableAccessControlEntry;
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
|
||||
/**
|
||||
* Test class for {@link ConsoleAuditLogger}.
|
||||
*
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
* @version $Id$
|
||||
*/
|
||||
public class AuditLoggerTests {
|
||||
public class AuditLoggerTests extends TestCase {
|
||||
//~ Instance fields ================================================================================================
|
||||
private Mockery jmock = new JUnit4Mockery();
|
||||
private PrintStream console;
|
||||
private ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
private ConsoleAuditLogger logger;
|
||||
private AuditableAccessControlEntry ace;
|
||||
private Expectations aceRequiresAudit;
|
||||
private Expectations aceDoesntRequireAudit;
|
||||
|
||||
private PrintStream console;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
private ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
logger = new ConsoleAuditLogger();
|
||||
ace = jmock.mock(AuditableAccessControlEntry.class);
|
||||
aceRequiresAudit = new Expectations() {{
|
||||
allowing(ace).isAuditSuccess(); will(returnValue(true));
|
||||
allowing(ace).isAuditFailure(); will(returnValue(true));
|
||||
}};
|
||||
aceDoesntRequireAudit = new Expectations() {{
|
||||
allowing(ace).isAuditSuccess(); will(returnValue(false));
|
||||
allowing(ace).isAuditFailure(); will(returnValue(false));
|
||||
}};
|
||||
public void setUp() throws Exception {
|
||||
console = System.out;
|
||||
System.setOut(new PrintStream(bytes));
|
||||
}
|
||||
|
||||
console = System.out;
|
||||
System.setOut(new PrintStream(bytes));
|
||||
}
|
||||
public void tearDown() throws Exception {
|
||||
System.setOut(console);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
System.setOut(console);
|
||||
bytes.reset();
|
||||
}
|
||||
public void testLoggingTests() throws Exception {
|
||||
ConsoleAuditLogger logger = new ConsoleAuditLogger();
|
||||
MockAccessControlEntryImpl auditableAccessControlEntry = new MockAccessControlEntryImpl();
|
||||
|
||||
@Test
|
||||
public void nonAuditableAceIsIgnored() {
|
||||
AccessControlEntry ace = jmock.mock(AccessControlEntry.class);
|
||||
logger.logIfNeeded(true, ace);
|
||||
assertEquals(0, bytes.size());
|
||||
}
|
||||
logger.logIfNeeded(true, auditableAccessControlEntry);
|
||||
Assert.assertTrue(bytes.size() == 0);
|
||||
|
||||
@Test
|
||||
public void successIsNotLoggedIfAceDoesntRequireSuccessAudit() throws Exception {
|
||||
jmock.checking(aceDoesntRequireAudit);
|
||||
logger.logIfNeeded(true, ace);
|
||||
assertEquals(0, bytes.size());
|
||||
}
|
||||
bytes.reset();
|
||||
logger.logIfNeeded(false, auditableAccessControlEntry);
|
||||
Assert.assertTrue(bytes.size() == 0);
|
||||
|
||||
@Test
|
||||
public void successIsLoggedIfAceRequiresSuccessAudit() throws Exception {
|
||||
jmock.checking(aceRequiresAudit);
|
||||
logger.logIfNeeded(true, ace);
|
||||
assertTrue(bytes.toString().startsWith("GRANTED due to ACE"));
|
||||
}
|
||||
auditableAccessControlEntry.setAuditSuccess(true);
|
||||
bytes.reset();
|
||||
|
||||
@Test
|
||||
public void failureIsntLoggedIfAceDoesntRequireFailureAudit() throws Exception {
|
||||
jmock.checking(aceDoesntRequireAudit);
|
||||
logger.logIfNeeded(false, ace);
|
||||
assertEquals(0, bytes.size());
|
||||
}
|
||||
logger.logIfNeeded(true, auditableAccessControlEntry);
|
||||
Assert.assertTrue(bytes.toString().length() > 0);
|
||||
Assert.assertTrue(bytes.toString().startsWith("GRANTED due to ACE"));
|
||||
|
||||
@Test
|
||||
public void failureIsLoggedIfAceRequiresFailureAudit() throws Exception {
|
||||
jmock.checking(aceRequiresAudit);
|
||||
logger.logIfNeeded(false, ace);
|
||||
assertTrue(bytes.toString().startsWith("DENIED due to ACE"));
|
||||
}
|
||||
auditableAccessControlEntry.setAuditFailure(true);
|
||||
bytes.reset();
|
||||
|
||||
logger.logIfNeeded(false, auditableAccessControlEntry);
|
||||
Assert.assertTrue(bytes.toString().length() > 0);
|
||||
Assert.assertTrue(bytes.toString().startsWith("DENIED due to ACE"));
|
||||
|
||||
MockAccessControlEntry accessControlEntry = new MockAccessControlEntry();
|
||||
bytes.reset();
|
||||
logger.logIfNeeded(true, accessControlEntry);
|
||||
Assert.assertTrue(bytes.size() == 0);
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class MockAccessControlEntryImpl implements AuditableAccessControlEntry {
|
||||
private boolean auditFailure = false;
|
||||
|
||||
private boolean auditSuccess = false;
|
||||
|
||||
public boolean isAuditFailure() {
|
||||
return auditFailure;
|
||||
}
|
||||
|
||||
public boolean isAuditSuccess() {
|
||||
return auditSuccess;
|
||||
}
|
||||
|
||||
public Acl getAcl() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Serializable getId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Permission getPermission() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Sid getSid() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isGranting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setAuditFailure(boolean auditFailure) {
|
||||
this.auditFailure = auditFailure;
|
||||
}
|
||||
|
||||
public void setAuditSuccess(boolean auditSuccess) {
|
||||
this.auditSuccess = auditSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
private class MockAccessControlEntry implements AccessControlEntry {
|
||||
|
||||
public Acl getAcl() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Serializable getId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Permission getPermission() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Sid getSid() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isGranting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
-189
@@ -1,189 +0,0 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.acls.domain.IdentityUnavailableException;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
|
||||
/**
|
||||
* Tests for {@link ObjectIdentityImpl}.
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
public class ObjectIdentityImplTests {
|
||||
|
||||
private static final String DOMAIN_CLASS =
|
||||
"org.springframework.security.acls.domain.ObjectIdentityImplTests$MockIdDomainObject";
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@Test
|
||||
public void constructorsRespectRequiredFields() throws Exception {
|
||||
// Check one-argument constructor required field
|
||||
try {
|
||||
new ObjectIdentityImpl(null);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
|
||||
// Check String-Serializable constructor required field
|
||||
try {
|
||||
new ObjectIdentityImpl("", Long.valueOf(1));
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
|
||||
// Check Serializable parameter is not null
|
||||
try {
|
||||
new ObjectIdentityImpl(DOMAIN_CLASS, null);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
|
||||
// The correct way of using String-Serializable constructor
|
||||
try {
|
||||
new ObjectIdentityImpl(DOMAIN_CLASS, Long.valueOf(1));
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
fail("It shouldn't have thrown IllegalArgumentException");
|
||||
}
|
||||
|
||||
// Check the Class-Serializable constructor
|
||||
try {
|
||||
new ObjectIdentityImpl(MockIdDomainObject.class, null);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gettersReturnExpectedValues() throws Exception {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(DOMAIN_CLASS, Long.valueOf(1));
|
||||
assertEquals(Long.valueOf(1), obj.getIdentifier());
|
||||
assertEquals(MockIdDomainObject.class.getName(), obj.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetIdMethodConstraints() throws Exception {
|
||||
// Check the getId() method is present
|
||||
try {
|
||||
new ObjectIdentityImpl("A_STRING_OBJECT");
|
||||
fail("It should have thrown IdentityUnavailableException");
|
||||
}
|
||||
catch (IdentityUnavailableException expected) {
|
||||
|
||||
}
|
||||
|
||||
// getId() should return a non-null value
|
||||
MockIdDomainObject mockId = new MockIdDomainObject();
|
||||
try {
|
||||
new ObjectIdentityImpl(mockId);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
}
|
||||
|
||||
// getId() should return a Serializable object
|
||||
mockId.setId(new MockIdDomainObject());
|
||||
try {
|
||||
new ObjectIdentityImpl(mockId);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
|
||||
// getId() should return a Serializable object
|
||||
mockId.setId(new Long(100));
|
||||
try {
|
||||
new ObjectIdentityImpl(mockId);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void constructorRejectsInvalidTypeParameter() throws Exception {
|
||||
new ObjectIdentityImpl("", Long.valueOf(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals() throws Exception {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(DOMAIN_CLASS, Long.valueOf(1));
|
||||
MockIdDomainObject mockObj = new MockIdDomainObject();
|
||||
mockObj.setId(Long.valueOf(1));
|
||||
|
||||
String string = "SOME_STRING";
|
||||
assertNotSame(obj, string);
|
||||
assertFalse(obj.equals(null));
|
||||
assertFalse(obj.equals("DIFFERENT_OBJECT_TYPE"));
|
||||
assertFalse(obj.equals(new ObjectIdentityImpl(DOMAIN_CLASS, Long.valueOf(2))));
|
||||
assertFalse(obj.equals(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.domain.ObjectIdentityImplTests$MockOtherIdDomainObject",
|
||||
Long.valueOf(1))));
|
||||
assertEquals(new ObjectIdentityImpl(DOMAIN_CLASS,Long.valueOf(1)), obj);
|
||||
assertEquals(obj, new ObjectIdentityImpl(mockObj));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hashcodeIsDifferentForDifferentJavaTypes() throws Exception {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(Object.class, Long.valueOf(1));
|
||||
ObjectIdentity obj2 = new ObjectIdentityImpl(String.class, Long.valueOf(1));
|
||||
assertFalse(obj.hashCode() == obj2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void longAndIntegerIdsWithSameValueAreEqualAndHaveSameHashcode() {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(Object.class, new Long(5));
|
||||
ObjectIdentity obj2 = new ObjectIdentityImpl(Object.class, new Integer(5));
|
||||
|
||||
assertEquals(obj, obj2);
|
||||
assertEquals(obj.hashCode(), obj2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalStringIdsAreEqualAndHaveSameHashcode() throws Exception {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(Object.class, "1000");
|
||||
ObjectIdentity obj2 = new ObjectIdentityImpl(Object.class, "1000");
|
||||
assertEquals(obj, obj2);
|
||||
assertEquals(obj.hashCode(), obj2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stringAndNumericIdsAreNotEqual() throws Exception {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(Object.class, "1000");
|
||||
ObjectIdentity obj2 = new ObjectIdentityImpl(Object.class, Long.valueOf(1000));
|
||||
assertFalse(obj.equals(obj2));
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class MockIdDomainObject {
|
||||
private Object id;
|
||||
|
||||
public Object getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Object id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private class MockOtherIdDomainObject {
|
||||
private Object id;
|
||||
|
||||
public Object getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Object id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,32 +14,28 @@
|
||||
*/
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
|
||||
/**
|
||||
* Tests classes associated with Permission.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
* @version $Id${date}
|
||||
*/
|
||||
public class PermissionTests {
|
||||
private static final Log LOGGER = LogFactory.getLog(PermissionTests.class);
|
||||
|
||||
private DefaultPermissionFactory permissionFactory;
|
||||
|
||||
@Before
|
||||
public void createPermissionfactory() {
|
||||
permissionFactory = new DefaultPermissionFactory();
|
||||
}
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@Test
|
||||
public void basePermissionTest() {
|
||||
Permission p = permissionFactory.buildFromName("WRITE");
|
||||
assertNotNull(p);
|
||||
Permission p = BasePermission.buildFromName("WRITE");
|
||||
assertNotNull(p);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -55,16 +51,14 @@ public class PermissionTests {
|
||||
|
||||
@Test
|
||||
public void fromInteger() {
|
||||
Permission permission = permissionFactory.buildFromMask(7);
|
||||
Permission permission = BasePermission.buildFromMask(7);
|
||||
System.out.println("7 = " + permission.toString());
|
||||
permission = permissionFactory.buildFromMask(4);
|
||||
permission = BasePermission.buildFromMask(4);
|
||||
System.out.println("4 = " + permission.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stringConversion() {
|
||||
permissionFactory.registerPublicPermissions(SpecialPermission.class);
|
||||
|
||||
System.out.println("R = " + BasePermission.READ.toString());
|
||||
assertEquals("BasePermission[...............................R=1]", BasePermission.READ.toString());
|
||||
|
||||
|
||||
@@ -14,20 +14,27 @@
|
||||
*/
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.Permission;
|
||||
|
||||
|
||||
/**
|
||||
* A test permission.
|
||||
*
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SpecialPermission extends BasePermission {
|
||||
public static final Permission ENTER = new SpecialPermission(1 << 5, 'E'); // 32
|
||||
public static final Permission LEAVE = new SpecialPermission(1 << 6, 'L');
|
||||
|
||||
/**
|
||||
* Registers the public static permissions defined on this class. This is mandatory so
|
||||
* that the static methods will operate correctly.
|
||||
*/
|
||||
static {
|
||||
registerPermissionsFor(SpecialPermission.class);
|
||||
}
|
||||
|
||||
protected SpecialPermission(int mask, char code) {
|
||||
super(mask, code);
|
||||
super(mask, code);
|
||||
}
|
||||
}
|
||||
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Ehcache;
|
||||
|
||||
import org.springframework.cache.ehcache.EhCacheFactoryBean;
|
||||
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
|
||||
import org.springframework.security.acls.domain.AclImpl;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.domain.ConsoleAuditLogger;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.sid.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
||||
|
||||
public class AclPermissionInheritanceTests extends TestCase {
|
||||
|
||||
private JdbcMutableAclService aclService;
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
private DriverManagerDataSource dataSource;
|
||||
private DataSourceTransactionManager txManager;
|
||||
private TransactionStatus txStatus;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
|
||||
dataSource = new DriverManagerDataSource();
|
||||
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
dataSource.setUrl("jdbc:hsqldb:mem:permissiontest");
|
||||
dataSource.setUsername("sa");
|
||||
dataSource.setPassword("");
|
||||
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
|
||||
txManager = new DataSourceTransactionManager();
|
||||
txManager.setDataSource(dataSource);
|
||||
|
||||
txStatus = txManager.getTransaction(new DefaultTransactionDefinition());
|
||||
|
||||
aclService = createAclService(dataSource);
|
||||
|
||||
Authentication auth = new UsernamePasswordAuthenticationToken(
|
||||
"system", "secret", new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_IGNORED")});
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
txManager.rollback(txStatus);
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
public void test1() throws Exception {
|
||||
|
||||
createAclSchema(jdbcTemplate);
|
||||
|
||||
ObjectIdentityImpl rootObject =
|
||||
new ObjectIdentityImpl(TestDomainObject.class, new Long(1));
|
||||
|
||||
MutableAcl parent = aclService.createAcl(rootObject);
|
||||
MutableAcl child = aclService.createAcl(new ObjectIdentityImpl(TestDomainObject.class, new Long(2)));
|
||||
child.setParent(parent);
|
||||
aclService.updateAcl(child);
|
||||
|
||||
parent = (AclImpl) aclService.readAclById(rootObject);
|
||||
parent.insertAce(0, BasePermission.READ,
|
||||
new PrincipalSid("john"), true);
|
||||
aclService.updateAcl(parent);
|
||||
|
||||
parent = (AclImpl) aclService.readAclById(rootObject);
|
||||
parent.insertAce(1, BasePermission.READ,
|
||||
new PrincipalSid("joe"), true);
|
||||
aclService.updateAcl(parent);
|
||||
|
||||
child = (MutableAcl) aclService.readAclById(
|
||||
new ObjectIdentityImpl(TestDomainObject.class, new Long(2)));
|
||||
|
||||
parent = (MutableAcl) child.getParentAcl();
|
||||
|
||||
assertEquals("Fails because child has a stale reference to its parent",
|
||||
2, parent.getEntries().length);
|
||||
assertEquals(1, parent.getEntries()[0].getPermission().getMask());
|
||||
assertEquals(new PrincipalSid("john"), parent.getEntries()[0].getSid());
|
||||
assertEquals(1, parent.getEntries()[1].getPermission().getMask());
|
||||
assertEquals(new PrincipalSid("joe"), parent.getEntries()[1].getSid());
|
||||
|
||||
}
|
||||
public void test2() throws Exception {
|
||||
|
||||
createAclSchema(jdbcTemplate);
|
||||
|
||||
ObjectIdentityImpl rootObject =
|
||||
new ObjectIdentityImpl(TestDomainObject.class, new Long(1));
|
||||
|
||||
MutableAcl parent = aclService.createAcl(rootObject);
|
||||
MutableAcl child = aclService.createAcl(new ObjectIdentityImpl(TestDomainObject.class, new Long(2)));
|
||||
child.setParent(parent);
|
||||
aclService.updateAcl(child);
|
||||
|
||||
parent.insertAce(0, BasePermission.ADMINISTRATION,
|
||||
new GrantedAuthoritySid("ROLE_ADMINISTRATOR"), true);
|
||||
aclService.updateAcl(parent);
|
||||
|
||||
parent.insertAce(1, BasePermission.DELETE, new PrincipalSid("terry"), true);
|
||||
aclService.updateAcl(parent);
|
||||
|
||||
child = (MutableAcl) aclService.readAclById(
|
||||
new ObjectIdentityImpl(TestDomainObject.class, new Long(2)));
|
||||
|
||||
parent = (MutableAcl) child.getParentAcl();
|
||||
|
||||
assertEquals(2, parent.getEntries().length);
|
||||
assertEquals(16, parent.getEntries()[0].getPermission().getMask());
|
||||
assertEquals(new GrantedAuthoritySid("ROLE_ADMINISTRATOR"), parent.getEntries()[0].getSid());
|
||||
assertEquals(8, parent.getEntries()[1].getPermission().getMask());
|
||||
assertEquals(new PrincipalSid("terry"), parent.getEntries()[1].getSid());
|
||||
|
||||
}
|
||||
|
||||
private JdbcMutableAclService createAclService(DriverManagerDataSource ds)
|
||||
throws IOException {
|
||||
|
||||
GrantedAuthorityImpl adminAuthority = new GrantedAuthorityImpl("ROLE_ADMINISTRATOR");
|
||||
AclAuthorizationStrategyImpl authStrategy = new AclAuthorizationStrategyImpl(
|
||||
new GrantedAuthorityImpl[]{adminAuthority,adminAuthority,adminAuthority});
|
||||
|
||||
EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
|
||||
ehCacheManagerFactoryBean.afterPropertiesSet();
|
||||
CacheManager cacheManager = (CacheManager) ehCacheManagerFactoryBean.getObject();
|
||||
|
||||
EhCacheFactoryBean ehCacheFactoryBean = new EhCacheFactoryBean();
|
||||
ehCacheFactoryBean.setCacheName("aclAche");
|
||||
ehCacheFactoryBean.setCacheManager(cacheManager);
|
||||
ehCacheFactoryBean.afterPropertiesSet();
|
||||
Ehcache ehCache = (Ehcache) ehCacheFactoryBean.getObject();
|
||||
|
||||
AclCache aclAche = new EhCacheBasedAclCache(ehCache);
|
||||
|
||||
BasicLookupStrategy lookupStrategy =
|
||||
new BasicLookupStrategy(ds, aclAche, authStrategy, new ConsoleAuditLogger());
|
||||
|
||||
return new JdbcMutableAclService(ds,lookupStrategy, aclAche);
|
||||
}
|
||||
|
||||
private void createAclSchema(JdbcTemplate jdbcTemplate) {
|
||||
|
||||
jdbcTemplate.execute("DROP TABLE ACL_ENTRY IF EXISTS;");
|
||||
jdbcTemplate.execute("DROP TABLE ACL_OBJECT_IDENTITY IF EXISTS;");
|
||||
jdbcTemplate.execute("DROP TABLE ACL_CLASS IF EXISTS");
|
||||
jdbcTemplate.execute("DROP TABLE ACL_SID IF EXISTS");
|
||||
|
||||
jdbcTemplate.execute(
|
||||
"CREATE TABLE ACL_SID(" +
|
||||
"ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY," +
|
||||
"PRINCIPAL BOOLEAN NOT NULL," +
|
||||
"SID VARCHAR_IGNORECASE(100) NOT NULL," +
|
||||
"CONSTRAINT UNIQUE_UK_1 UNIQUE(SID,PRINCIPAL));");
|
||||
jdbcTemplate.execute(
|
||||
"CREATE TABLE ACL_CLASS(" +
|
||||
"ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY," +
|
||||
"CLASS VARCHAR_IGNORECASE(100) NOT NULL," +
|
||||
"CONSTRAINT UNIQUE_UK_2 UNIQUE(CLASS));");
|
||||
jdbcTemplate.execute(
|
||||
"CREATE TABLE ACL_OBJECT_IDENTITY(" +
|
||||
"ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY," +
|
||||
"OBJECT_ID_CLASS BIGINT NOT NULL," +
|
||||
"OBJECT_ID_IDENTITY BIGINT NOT NULL," +
|
||||
"PARENT_OBJECT BIGINT," +
|
||||
"OWNER_SID BIGINT," +
|
||||
"ENTRIES_INHERITING BOOLEAN NOT NULL," +
|
||||
"CONSTRAINT UNIQUE_UK_3 UNIQUE(OBJECT_ID_CLASS,OBJECT_ID_IDENTITY)," +
|
||||
"CONSTRAINT FOREIGN_FK_1 FOREIGN KEY(PARENT_OBJECT)REFERENCES ACL_OBJECT_IDENTITY(ID)," +
|
||||
"CONSTRAINT FOREIGN_FK_2 FOREIGN KEY(OBJECT_ID_CLASS)REFERENCES ACL_CLASS(ID)," +
|
||||
"CONSTRAINT FOREIGN_FK_3 FOREIGN KEY(OWNER_SID)REFERENCES ACL_SID(ID));");
|
||||
jdbcTemplate.execute(
|
||||
"CREATE TABLE ACL_ENTRY(" +
|
||||
"ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY," +
|
||||
"ACL_OBJECT_IDENTITY BIGINT NOT NULL,ACE_ORDER INT NOT NULL,SID BIGINT NOT NULL," +
|
||||
"MASK INTEGER NOT NULL,GRANTING BOOLEAN NOT NULL,AUDIT_SUCCESS BOOLEAN NOT NULL," +
|
||||
"AUDIT_FAILURE BOOLEAN NOT NULL,CONSTRAINT UNIQUE_UK_4 UNIQUE(ACL_OBJECT_IDENTITY,ACE_ORDER)," +
|
||||
"CONSTRAINT FOREIGN_FK_4 FOREIGN KEY(ACL_OBJECT_IDENTITY) REFERENCES ACL_OBJECT_IDENTITY(ID)," +
|
||||
"CONSTRAINT FOREIGN_FK_5 FOREIGN KEY(SID) REFERENCES ACL_SID(ID));");
|
||||
}
|
||||
|
||||
public static class TestDomainObject {
|
||||
|
||||
private Long id;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
+87
-103
@@ -1,7 +1,5 @@
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Assert;
|
||||
@@ -17,40 +15,38 @@ import org.junit.Test;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.TestDataSource;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.domain.ConsoleAuditLogger;
|
||||
import org.springframework.security.acls.domain.EhCacheBasedAclCache;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.domain.PrincipalSid;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AuditableAccessControlEntry;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.NotFoundException;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
/**
|
||||
* Tests {@link BasicLookupStrategy}
|
||||
*
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
public class BasicLookupStrategyTests {
|
||||
|
||||
private static final Sid BEN_SID = new PrincipalSid("ben");
|
||||
private static final String TARGET_CLASS = "org.springframework.security.acls.TargetObject";
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
|
||||
private static JdbcTemplate jdbcTemplate;
|
||||
private BasicLookupStrategy strategy;
|
||||
private static SingleConnectionDataSource dataSource;
|
||||
|
||||
private LookupStrategy strategy;
|
||||
|
||||
private static TestDataSource dataSource;
|
||||
|
||||
private static CacheManager cacheManager;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
@@ -62,11 +58,10 @@ public class BasicLookupStrategyTests {
|
||||
|
||||
@BeforeClass
|
||||
public static void createDatabase() throws Exception {
|
||||
dataSource = new SingleConnectionDataSource("jdbc:hsqldb:mem:lookupstrategytest", "sa", "", true);
|
||||
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
dataSource = new TestDataSource("lookupstrategytest");
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
|
||||
Resource resource = new ClassPathResource("createAclSchema.sql");
|
||||
Resource resource = new ClassPathResource("org/springframework/security/acls/jdbc/testData.sql");
|
||||
String sql = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()));
|
||||
jdbcTemplate.execute(sql);
|
||||
}
|
||||
@@ -85,7 +80,7 @@ public class BasicLookupStrategyTests {
|
||||
@Before
|
||||
public void populateDatabase() {
|
||||
String query = "INSERT INTO acl_sid(ID,PRINCIPAL,SID) VALUES (1,1,'ben');"
|
||||
+ "INSERT INTO acl_class(ID,CLASS) VALUES (2,'" + TARGET_CLASS + "');"
|
||||
+ "INSERT INTO acl_class(ID,CLASS) VALUES (2,'org.springframework.security.TargetObject');"
|
||||
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (1,2,100,null,1,1);"
|
||||
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (2,2,101,1,1,1);"
|
||||
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (3,2,102,2,1,1);"
|
||||
@@ -123,45 +118,45 @@ public class BasicLookupStrategyTests {
|
||||
|
||||
@Test
|
||||
public void testAclsRetrievalWithDefaultBatchSize() throws Exception {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(101));
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
// Deliberately use an integer for the child, to reproduce bug report in SEC-819
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Integer(102));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(102));
|
||||
|
||||
Map<ObjectIdentity, Acl> map = this.strategy.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
|
||||
Map map = this.strategy.readAclsById(new ObjectIdentity[] { topParentOid, middleParentOid, childOid }, null);
|
||||
checkEntries(topParentOid, middleParentOid, childOid, map);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAclsRetrievalFromCacheOnly() throws Exception {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Integer(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(102));
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
|
||||
// Objects were put in cache
|
||||
strategy.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
|
||||
strategy.readAclsById(new ObjectIdentity[] { topParentOid, middleParentOid, childOid }, null);
|
||||
|
||||
// Let's empty the database to force acls retrieval from cache
|
||||
emptyDatabase();
|
||||
Map<ObjectIdentity, Acl> map = this.strategy.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
|
||||
Map map = this.strategy.readAclsById(new ObjectIdentity[] { topParentOid, middleParentOid, childOid }, null);
|
||||
|
||||
checkEntries(topParentOid, middleParentOid, childOid, map);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAclsRetrievalWithCustomBatchSize() throws Exception {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Integer(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(102));
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
|
||||
// Set a batch size to allow multiple database queries in order to retrieve all acls
|
||||
((BasicLookupStrategy) this.strategy).setBatchSize(1);
|
||||
Map<ObjectIdentity, Acl> map = this.strategy.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
|
||||
Map map = this.strategy.readAclsById(new ObjectIdentity[] { topParentOid, middleParentOid, childOid }, null);
|
||||
checkEntries(topParentOid, middleParentOid, childOid, map);
|
||||
}
|
||||
|
||||
private void checkEntries(ObjectIdentity topParentOid, ObjectIdentity middleParentOid, ObjectIdentity childOid,
|
||||
Map<ObjectIdentity, Acl> map) throws Exception {
|
||||
private void checkEntries(ObjectIdentity topParentOid, ObjectIdentity middleParentOid, ObjectIdentity childOid, Map map)
|
||||
throws Exception {
|
||||
Assert.assertEquals(3, map.size());
|
||||
|
||||
MutableAcl topParent = (MutableAcl) map.get(topParentOid);
|
||||
@@ -179,9 +174,9 @@ public class BasicLookupStrategyTests {
|
||||
Assert.assertEquals(middleParentOid, child.getParentAcl().getObjectIdentity());
|
||||
|
||||
// Check their ACEs were correctly retrieved
|
||||
Assert.assertEquals(2, topParent.getEntries().size());
|
||||
Assert.assertEquals(1, middleParent.getEntries().size());
|
||||
Assert.assertEquals(1, child.getEntries().size());
|
||||
Assert.assertEquals(2, topParent.getEntries().length);
|
||||
Assert.assertEquals(1, middleParent.getEntries().length);
|
||||
Assert.assertEquals(1, child.getEntries().length);
|
||||
|
||||
// Check object identities were correctly retrieved
|
||||
Assert.assertEquals(topParentOid, topParent.getObjectIdentity());
|
||||
@@ -192,54 +187,54 @@ public class BasicLookupStrategyTests {
|
||||
Assert.assertTrue(topParent.isEntriesInheriting());
|
||||
Assert.assertEquals(topParent.getId(), new Long(1));
|
||||
Assert.assertEquals(topParent.getOwner(), new PrincipalSid("ben"));
|
||||
Assert.assertEquals(topParent.getEntries().get(0).getId(), new Long(1));
|
||||
Assert.assertEquals(topParent.getEntries().get(0).getPermission(), BasePermission.READ);
|
||||
Assert.assertEquals(topParent.getEntries().get(0).getSid(), new PrincipalSid("ben"));
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries().get(0)).isAuditFailure());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries().get(0)).isAuditSuccess());
|
||||
Assert.assertTrue(((AuditableAccessControlEntry) topParent.getEntries().get(0)).isGranting());
|
||||
Assert.assertEquals(topParent.getEntries()[0].getId(), new Long(1));
|
||||
Assert.assertEquals(topParent.getEntries()[0].getPermission(), BasePermission.READ);
|
||||
Assert.assertEquals(topParent.getEntries()[0].getSid(), new PrincipalSid("ben"));
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries()[0]).isAuditFailure());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries()[0]).isAuditSuccess());
|
||||
Assert.assertTrue(((AuditableAccessControlEntry) topParent.getEntries()[0]).isGranting());
|
||||
|
||||
Assert.assertEquals(topParent.getEntries().get(1).getId(), new Long(2));
|
||||
Assert.assertEquals(topParent.getEntries().get(1).getPermission(), BasePermission.WRITE);
|
||||
Assert.assertEquals(topParent.getEntries().get(1).getSid(), new PrincipalSid("ben"));
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries().get(1)).isAuditFailure());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries().get(1)).isAuditSuccess());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries().get(1)).isGranting());
|
||||
Assert.assertEquals(topParent.getEntries()[1].getId(), new Long(2));
|
||||
Assert.assertEquals(topParent.getEntries()[1].getPermission(), BasePermission.WRITE);
|
||||
Assert.assertEquals(topParent.getEntries()[1].getSid(), new PrincipalSid("ben"));
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries()[1]).isAuditFailure());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries()[1]).isAuditSuccess());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries()[1]).isGranting());
|
||||
|
||||
Assert.assertTrue(middleParent.isEntriesInheriting());
|
||||
Assert.assertEquals(middleParent.getId(), new Long(2));
|
||||
Assert.assertEquals(middleParent.getOwner(), new PrincipalSid("ben"));
|
||||
Assert.assertEquals(middleParent.getEntries().get(0).getId(), new Long(3));
|
||||
Assert.assertEquals(middleParent.getEntries().get(0).getPermission(), BasePermission.DELETE);
|
||||
Assert.assertEquals(middleParent.getEntries().get(0).getSid(), new PrincipalSid("ben"));
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) middleParent.getEntries().get(0)).isAuditFailure());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) middleParent.getEntries().get(0)).isAuditSuccess());
|
||||
Assert.assertTrue(((AuditableAccessControlEntry) middleParent.getEntries().get(0)).isGranting());
|
||||
Assert.assertEquals(middleParent.getEntries()[0].getId(), new Long(3));
|
||||
Assert.assertEquals(middleParent.getEntries()[0].getPermission(), BasePermission.DELETE);
|
||||
Assert.assertEquals(middleParent.getEntries()[0].getSid(), new PrincipalSid("ben"));
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) middleParent.getEntries()[0]).isAuditFailure());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) middleParent.getEntries()[0]).isAuditSuccess());
|
||||
Assert.assertTrue(((AuditableAccessControlEntry) middleParent.getEntries()[0]).isGranting());
|
||||
|
||||
Assert.assertTrue(child.isEntriesInheriting());
|
||||
Assert.assertEquals(child.getId(), new Long(3));
|
||||
Assert.assertEquals(child.getOwner(), new PrincipalSid("ben"));
|
||||
Assert.assertEquals(child.getEntries().get(0).getId(), new Long(4));
|
||||
Assert.assertEquals(child.getEntries().get(0).getPermission(), BasePermission.DELETE);
|
||||
Assert.assertEquals(child.getEntries().get(0).getSid(), new PrincipalSid("ben"));
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) child.getEntries().get(0)).isAuditFailure());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) child.getEntries().get(0)).isAuditSuccess());
|
||||
Assert.assertFalse((child.getEntries().get(0)).isGranting());
|
||||
Assert.assertEquals(child.getEntries()[0].getId(), new Long(4));
|
||||
Assert.assertEquals(child.getEntries()[0].getPermission(), BasePermission.DELETE);
|
||||
Assert.assertEquals(child.getEntries()[0].getSid(), new PrincipalSid("ben"));
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) child.getEntries()[0]).isAuditFailure());
|
||||
Assert.assertFalse(((AuditableAccessControlEntry) child.getEntries()[0]).isAuditSuccess());
|
||||
Assert.assertFalse((child.getEntries()[0]).isGranting());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAllParentsAreRetrievedWhenChildIsLoaded() throws Exception {
|
||||
String query = "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (4,2,103,1,1,1);";
|
||||
jdbcTemplate.execute(query);
|
||||
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Integer(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(102));
|
||||
ObjectIdentity middleParent2Oid = new ObjectIdentityImpl(TARGET_CLASS, new Long(103));
|
||||
|
||||
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
ObjectIdentity middleParent2Oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(103));
|
||||
|
||||
// Retrieve the child
|
||||
Map<ObjectIdentity, Acl> map = this.strategy.readAclsById(Arrays.asList(childOid), null);
|
||||
|
||||
Map map = this.strategy.readAclsById(new ObjectIdentity[] { childOid }, null);
|
||||
|
||||
// Check that the child and all its parents were retrieved
|
||||
Assert.assertNotNull(map.get(childOid));
|
||||
Assert.assertEquals(childOid, ((Acl) map.get(childOid)).getObjectIdentity());
|
||||
@@ -247,7 +242,7 @@ public class BasicLookupStrategyTests {
|
||||
Assert.assertEquals(middleParentOid, ((Acl) map.get(middleParentOid)).getObjectIdentity());
|
||||
Assert.assertNotNull(map.get(topParentOid));
|
||||
Assert.assertEquals(topParentOid, ((Acl) map.get(topParentOid)).getObjectIdentity());
|
||||
|
||||
|
||||
// The second parent shouldn't have been retrieved
|
||||
Assert.assertNull(map.get(middleParent2Oid));
|
||||
}
|
||||
@@ -264,18 +259,18 @@ public class BasicLookupStrategyTests {
|
||||
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (5,4,0,1,1,1,0,0)";
|
||||
jdbcTemplate.execute(query);
|
||||
|
||||
ObjectIdentity grandParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(104));
|
||||
ObjectIdentity parent1Oid = new ObjectIdentityImpl(TARGET_CLASS, new Long(105));
|
||||
ObjectIdentity parent2Oid = new ObjectIdentityImpl(TARGET_CLASS, new Integer(106));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Integer(107));
|
||||
ObjectIdentity grandParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(104));
|
||||
ObjectIdentity parent1Oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(105));
|
||||
ObjectIdentity parent2Oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(106));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(107));
|
||||
|
||||
// First lookup only child, thus populating the cache with grandParent, parent1 and child
|
||||
List<Permission> checkPermission = Arrays.asList(BasePermission.READ);
|
||||
List<Sid> sids = Arrays.asList(BEN_SID);
|
||||
List<ObjectIdentity> childOids = Arrays.asList(childOid);
|
||||
|
||||
strategy.setBatchSize(6);
|
||||
Map<ObjectIdentity, Acl> foundAcls = strategy.readAclsById(childOids, sids);
|
||||
Permission[] checkPermission = new Permission[] { BasePermission.READ };
|
||||
Sid[] sids = new Sid[] { new PrincipalSid("ben") };
|
||||
ObjectIdentity[] childOids = new ObjectIdentity[] { childOid };
|
||||
|
||||
((BasicLookupStrategy) this.strategy).setBatchSize(6);
|
||||
Map foundAcls = strategy.readAclsById(childOids, sids);
|
||||
|
||||
Acl foundChildAcl = (Acl) foundAcls.get(childOid);
|
||||
Assert.assertNotNull(foundChildAcl);
|
||||
@@ -283,7 +278,7 @@ public class BasicLookupStrategyTests {
|
||||
|
||||
// Search for object identities has to be done in the following order: last element have to be one which
|
||||
// is already in cache and the element before it must not be stored in cache
|
||||
List<ObjectIdentity> allOids = Arrays.asList(grandParentOid, parent1Oid, parent2Oid, childOid);
|
||||
ObjectIdentity[] allOids = new ObjectIdentity[] { grandParentOid, parent1Oid, parent2Oid, childOid };
|
||||
try {
|
||||
foundAcls = strategy.readAclsById(allOids, sids);
|
||||
Assert.assertTrue(true);
|
||||
@@ -295,16 +290,5 @@ public class BasicLookupStrategyTests {
|
||||
Assert.assertNotNull(foundParent2Acl);
|
||||
Assert.assertTrue(foundParent2Acl.isGranted(checkPermission, sids, false));
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void nullOwnerIsNotSupported() {
|
||||
String query = "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (4,2,104,null,null,1);";
|
||||
|
||||
jdbcTemplate.execute(query);
|
||||
|
||||
ObjectIdentity oid = new ObjectIdentityImpl(TARGET_CLASS, new Long(104));
|
||||
|
||||
strategy.readAclsById(Arrays.asList(oid), Arrays.asList(BEN_SID));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,7 +27,7 @@ import javax.sql.DataSource;
|
||||
|
||||
|
||||
/**
|
||||
* Seeds the database for {@link JdbcMutableAclServiceTests}.
|
||||
* Seeds the database for {@link JdbcAclServiceTests}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
|
||||
+43
-62
@@ -1,6 +1,9 @@
|
||||
package org.springframework.security.acls.jdbc;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@@ -8,7 +11,6 @@ import java.io.FileOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.ehcache.Cache;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
@@ -18,37 +20,35 @@ import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
|
||||
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
|
||||
import org.springframework.security.acls.domain.AclImpl;
|
||||
import org.springframework.security.acls.domain.ConsoleAuditLogger;
|
||||
import org.springframework.security.acls.domain.EhCacheBasedAclCache;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.TestingAuthenticationToken;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
|
||||
/**
|
||||
* Tests {@link EhCacheBasedAclCache}
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
* @version $Id$
|
||||
*/
|
||||
public class EhCacheBasedAclCacheTests {
|
||||
private static final String TARGET_CLASS = "org.springframework.security.acls.TargetObject";
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
private static CacheManager cacheManager;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
@BeforeClass
|
||||
public static void initCacheManaer() {
|
||||
cacheManager = new CacheManager();
|
||||
// Use disk caching immediately (to test for serialization issue reported in SEC-527)
|
||||
cacheManager.addCache(new Cache("ehcachebasedacltests", 0, true, false, 600, 300));
|
||||
cacheManager.addCache(new Cache("ehcachebasedacltests", 0, true, false, 30, 30));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
@@ -68,10 +68,11 @@ public class EhCacheBasedAclCacheTests {
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void constructorRejectsNullParameters() throws Exception {
|
||||
new EhCacheBasedAclCache(null);
|
||||
AclCache aclCache = new EhCacheBasedAclCache(null);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -124,11 +125,11 @@ public class EhCacheBasedAclCacheTests {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// SEC-527
|
||||
@Test
|
||||
public void testDiskSerializationOfMutableAclObjectInstance() throws Exception {
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
@@ -137,20 +138,20 @@ public class EhCacheBasedAclCacheTests {
|
||||
// Serialization test
|
||||
File file = File.createTempFile("SEC_TEST", ".object");
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
ObjectOutputStream oos = new ObjectOutputStream(fos);
|
||||
oos.writeObject(acl);
|
||||
oos.close();
|
||||
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
ObjectInputStream ois = new ObjectInputStream(fis);
|
||||
MutableAcl retrieved = (MutableAcl) ois.readObject();
|
||||
ois.close();
|
||||
|
||||
ObjectOutputStream oos = new ObjectOutputStream(fos);
|
||||
oos.writeObject(acl);
|
||||
oos.close();
|
||||
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
ObjectInputStream ois = new ObjectInputStream(fis);
|
||||
MutableAcl retrieved = (MutableAcl) ois.readObject();
|
||||
ois.close();
|
||||
|
||||
assertEquals(acl, retrieved);
|
||||
|
||||
|
||||
Object retrieved1 = FieldUtils.getProtectedFieldValue("aclAuthorizationStrategy", retrieved);
|
||||
assertEquals(null, retrieved1);
|
||||
|
||||
|
||||
Object retrieved2 = FieldUtils.getProtectedFieldValue("auditLogger", retrieved);
|
||||
assertEquals(null, retrieved2);
|
||||
}
|
||||
@@ -160,7 +161,7 @@ public class EhCacheBasedAclCacheTests {
|
||||
Ehcache cache = getCache();
|
||||
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
@@ -172,13 +173,13 @@ public class EhCacheBasedAclCacheTests {
|
||||
assertEquals(2, cache.getDiskStoreSize());
|
||||
assertTrue(cache.isElementOnDisk(acl.getObjectIdentity()));
|
||||
assertFalse(cache.isElementInMemory(acl.getObjectIdentity()));
|
||||
|
||||
|
||||
// Check we can get from cache the same objects we put in
|
||||
assertEquals(myCache.getFromCache(new Long(1)), acl);
|
||||
assertEquals(myCache.getFromCache(identity), acl);
|
||||
|
||||
// Put another object in cache
|
||||
ObjectIdentity identity2 = new ObjectIdentityImpl(TARGET_CLASS, new Long(101));
|
||||
ObjectIdentity identity2 = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
MutableAcl acl2 = new AclImpl(identity2, new Long(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
|
||||
myCache.putInCache(acl2);
|
||||
@@ -187,7 +188,7 @@ public class EhCacheBasedAclCacheTests {
|
||||
|
||||
// Try to evict an entry that doesn't exist
|
||||
myCache.evictFromCache(new Long(3));
|
||||
myCache.evictFromCache(new ObjectIdentityImpl(TARGET_CLASS, new Long(102)));
|
||||
myCache.evictFromCache(new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102)));
|
||||
assertEquals(cache.getSize(), 4);
|
||||
assertEquals(4, cache.getDiskStoreSize());
|
||||
|
||||
@@ -203,25 +204,24 @@ public class EhCacheBasedAclCacheTests {
|
||||
assertEquals(cache.getSize(), 0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void cacheOperationsAclWithParent() throws Exception {
|
||||
Ehcache cache = getCache();
|
||||
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
|
||||
|
||||
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(1));
|
||||
ObjectIdentity identityParent = new ObjectIdentityImpl(TARGET_CLASS, new Long(2));
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity identityParent = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
MutableAcl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
MutableAcl parentAcl = new AclImpl(identityParent, new Long(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
|
||||
|
||||
|
||||
acl.setParent(parentAcl);
|
||||
|
||||
assertEquals(0, cache.getDiskStoreSize());
|
||||
@@ -229,32 +229,13 @@ public class EhCacheBasedAclCacheTests {
|
||||
assertEquals(cache.getSize(), 4);
|
||||
assertEquals(4, cache.getDiskStoreSize());
|
||||
assertTrue(cache.isElementOnDisk(acl.getObjectIdentity()));
|
||||
assertTrue(cache.isElementOnDisk(Long.valueOf(1)));
|
||||
assertFalse(cache.isElementInMemory(acl.getObjectIdentity()));
|
||||
assertFalse(cache.isElementInMemory(Long.valueOf(1)));
|
||||
cache.flush();
|
||||
// Wait for the spool to be written to disk (it's asynchronous)
|
||||
Map spool = (Map) FieldUtils.getFieldValue(cache, "diskStore.spool");
|
||||
|
||||
while(spool.size() > 0) {
|
||||
Thread.sleep(50);
|
||||
}
|
||||
|
||||
// Check we can get from cache the same objects we put in
|
||||
AclImpl aclFromCache = (AclImpl) myCache.getFromCache(new Long(1));
|
||||
// For the checks on transient fields, we need to be sure that the object is being loaded from the cache,
|
||||
// not from the ehcache spool or elsewhere...
|
||||
assertFalse(acl == aclFromCache);
|
||||
assertEquals(acl, aclFromCache);
|
||||
// SEC-951 check transient fields are set on parent
|
||||
assertNotNull(FieldUtils.getFieldValue(aclFromCache.getParentAcl(), "aclAuthorizationStrategy"));
|
||||
assertNotNull(FieldUtils.getFieldValue(aclFromCache.getParentAcl(), "auditLogger"));
|
||||
assertEquals(acl, myCache.getFromCache(identity));
|
||||
assertNotNull(FieldUtils.getFieldValue(aclFromCache, "aclAuthorizationStrategy"));
|
||||
AclImpl parentAclFromCache = (AclImpl) myCache.getFromCache(new Long(2));
|
||||
assertEquals(parentAcl, parentAclFromCache);
|
||||
assertNotNull(FieldUtils.getFieldValue(parentAclFromCache, "aclAuthorizationStrategy"));
|
||||
assertEquals(parentAcl, myCache.getFromCache(identityParent));
|
||||
assertEquals(myCache.getFromCache(new Long(1)), acl);
|
||||
assertEquals(myCache.getFromCache(identity), acl);
|
||||
assertEquals(myCache.getFromCache(new Long(2)), parentAcl);
|
||||
assertEquals(myCache.getFromCache(identityParent), parentAcl);
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
@@ -0,0 +1,415 @@
|
||||
/* 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.acls.jdbc;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.acls.AccessControlEntry;
|
||||
import org.springframework.security.acls.Acl;
|
||||
import org.springframework.security.acls.AlreadyExistsException;
|
||||
import org.springframework.security.acls.ChildrenExistException;
|
||||
import org.springframework.security.acls.MutableAcl;
|
||||
import org.springframework.security.acls.NotFoundException;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity;
|
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.TestingAuthenticationToken;
|
||||
import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;
|
||||
|
||||
|
||||
/**
|
||||
* Integration tests the ACL system using an in-memory database.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Andrei Stefan
|
||||
* @version $Id:JdbcAclServiceTests.java 1754 2006-11-17 02:01:21Z benalex $
|
||||
*/
|
||||
public class JdbcAclServiceTests extends AbstractTransactionalDataSourceSpringContextTests {
|
||||
//~ Constant fields ================================================================================================
|
||||
|
||||
public static final String SELECT_ALL_CLASSES = "SELECT * FROM acl_class WHERE class = ?";
|
||||
|
||||
public static final String SELECT_ALL_OBJECT_IDENTITIES = "SELECT * FROM acl_object_identity";
|
||||
|
||||
public static final String SELECT_OBJECT_IDENTITY = "SELECT * FROM acl_object_identity WHERE object_id_identity = ?";
|
||||
|
||||
public static final String SELECT_ACL_ENTRY = "SELECT * FROM acl_entry, acl_object_identity WHERE " +
|
||||
"acl_object_identity.id = acl_entry.acl_object_identity " +
|
||||
"AND acl_object_identity.object_id_identity <= ?";
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private JdbcMutableAclService jdbcMutableAclService;
|
||||
|
||||
private AclCache aclCache;
|
||||
|
||||
private LookupStrategy lookupStrategy;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
protected String[] getConfigLocations() {
|
||||
return new String[] {"classpath:org/springframework/security/acls/jdbc/applicationContext-test.xml"};
|
||||
}
|
||||
|
||||
public void setJdbcMutableAclService(JdbcMutableAclService jdbcAclService) {
|
||||
this.jdbcMutableAclService = jdbcAclService;
|
||||
}
|
||||
|
||||
public void setAclCache(AclCache aclCache) {
|
||||
this.aclCache = aclCache;
|
||||
}
|
||||
|
||||
public void setLookupStrategy(LookupStrategy lookupStrategy) {
|
||||
this.lookupStrategy = lookupStrategy;
|
||||
}
|
||||
|
||||
protected void onTearDown() throws Exception {
|
||||
super.onTearDown();
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
public void testLifecycle() {
|
||||
setComplete();
|
||||
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ADMINISTRATOR")});
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(102));
|
||||
|
||||
MutableAcl topParent = jdbcMutableAclService.createAcl(topParentOid);
|
||||
MutableAcl middleParent = jdbcMutableAclService.createAcl(middleParentOid);
|
||||
MutableAcl child = jdbcMutableAclService.createAcl(childOid);
|
||||
|
||||
// Specify the inheritence hierarchy
|
||||
middleParent.setParent(topParent);
|
||||
child.setParent(middleParent);
|
||||
|
||||
// Now let's add a couple of permissions
|
||||
topParent.insertAce(0, BasePermission.READ, new PrincipalSid(auth), true);
|
||||
topParent.insertAce(1, BasePermission.WRITE, new PrincipalSid(auth), false);
|
||||
middleParent.insertAce(0, BasePermission.DELETE, new PrincipalSid(auth), true);
|
||||
child.insertAce(0, BasePermission.DELETE, new PrincipalSid(auth), false);
|
||||
|
||||
// Explictly save the changed ACL
|
||||
jdbcMutableAclService.updateAcl(topParent);
|
||||
jdbcMutableAclService.updateAcl(middleParent);
|
||||
jdbcMutableAclService.updateAcl(child);
|
||||
|
||||
// Let's check if we can read them back correctly
|
||||
Map map = jdbcMutableAclService.readAclsById(new ObjectIdentity[] {topParentOid, middleParentOid, childOid});
|
||||
assertEquals(3, map.size());
|
||||
|
||||
// Replace our current objects with their retrieved versions
|
||||
topParent = (MutableAcl) map.get(topParentOid);
|
||||
middleParent = (MutableAcl) map.get(middleParentOid);
|
||||
child = (MutableAcl) map.get(childOid);
|
||||
|
||||
// Check the retrieved versions has IDs
|
||||
assertNotNull(topParent.getId());
|
||||
assertNotNull(middleParent.getId());
|
||||
assertNotNull(child.getId());
|
||||
|
||||
// Check their parents were correctly persisted
|
||||
assertNull(topParent.getParentAcl());
|
||||
assertEquals(topParentOid, middleParent.getParentAcl().getObjectIdentity());
|
||||
assertEquals(middleParentOid, child.getParentAcl().getObjectIdentity());
|
||||
|
||||
// Check their ACEs were correctly persisted
|
||||
assertEquals(2, topParent.getEntries().length);
|
||||
assertEquals(1, middleParent.getEntries().length);
|
||||
assertEquals(1, child.getEntries().length);
|
||||
|
||||
// Check the retrieved rights are correct
|
||||
assertTrue(topParent.isGranted(new Permission[] {BasePermission.READ}, new Sid[] {new PrincipalSid(auth)}, false));
|
||||
assertFalse(topParent.isGranted(new Permission[] {BasePermission.WRITE}, new Sid[] {new PrincipalSid(auth)}, false));
|
||||
assertTrue(middleParent.isGranted(new Permission[] {BasePermission.DELETE}, new Sid[] {new PrincipalSid(auth)}, false));
|
||||
assertFalse(child.isGranted(new Permission[] {BasePermission.DELETE}, new Sid[] {new PrincipalSid(auth)}, false));
|
||||
|
||||
try {
|
||||
child.isGranted(new Permission[] {BasePermission.ADMINISTRATION}, new Sid[] {new PrincipalSid(auth)}, false);
|
||||
fail("Should have thrown NotFoundException");
|
||||
} catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
// Now check the inherited rights (when not explicitly overridden) also look OK
|
||||
assertTrue(child.isGranted(new Permission[] {BasePermission.READ}, new Sid[] {new PrincipalSid(auth)}, false));
|
||||
assertFalse(child.isGranted(new Permission[] {BasePermission.WRITE}, new Sid[] {new PrincipalSid(auth)}, false));
|
||||
assertFalse(child.isGranted(new Permission[] {BasePermission.DELETE}, new Sid[] {new PrincipalSid(auth)}, false));
|
||||
|
||||
// Next change the child so it doesn't inherit permissions from above
|
||||
child.setEntriesInheriting(false);
|
||||
jdbcMutableAclService.updateAcl(child);
|
||||
child = (MutableAcl) jdbcMutableAclService.readAclById(childOid);
|
||||
assertFalse(child.isEntriesInheriting());
|
||||
|
||||
// Check the child permissions no longer inherit
|
||||
assertFalse(child.isGranted(new Permission[] {BasePermission.DELETE}, new Sid[] {new PrincipalSid(auth)}, true));
|
||||
|
||||
try {
|
||||
child.isGranted(new Permission[] {BasePermission.READ}, new Sid[] {new PrincipalSid(auth)}, true);
|
||||
fail("Should have thrown NotFoundException");
|
||||
} catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
child.isGranted(new Permission[] {BasePermission.WRITE}, new Sid[] {new PrincipalSid(auth)}, true);
|
||||
fail("Should have thrown NotFoundException");
|
||||
} catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
// Let's add an identical permission to the child, but it'll appear AFTER the current permission, so has no impact
|
||||
child.insertAce(1, BasePermission.DELETE, new PrincipalSid(auth), true);
|
||||
|
||||
// Let's also add another permission to the child
|
||||
child.insertAce(2, BasePermission.CREATE, new PrincipalSid(auth), true);
|
||||
|
||||
// Save the changed child
|
||||
jdbcMutableAclService.updateAcl(child);
|
||||
child = (MutableAcl) jdbcMutableAclService.readAclById(childOid);
|
||||
assertEquals(3, child.getEntries().length);
|
||||
|
||||
// Output permissions
|
||||
for (int i = 0; i < child.getEntries().length; i++) {
|
||||
System.out.println(child.getEntries()[i]);
|
||||
}
|
||||
|
||||
// Check the permissions are as they should be
|
||||
assertFalse(child.isGranted(new Permission[] {BasePermission.DELETE}, new Sid[] {new PrincipalSid(auth)}, true)); // as earlier permission overrode
|
||||
assertTrue(child.isGranted(new Permission[] {BasePermission.CREATE}, new Sid[] {new PrincipalSid(auth)}, true));
|
||||
|
||||
// Now check the first ACE (index 0) really is DELETE for our Sid and is non-granting
|
||||
AccessControlEntry entry = child.getEntries()[0];
|
||||
assertEquals(BasePermission.DELETE.getMask(), entry.getPermission().getMask());
|
||||
assertEquals(new PrincipalSid(auth), entry.getSid());
|
||||
assertFalse(entry.isGranting());
|
||||
assertNotNull(entry.getId());
|
||||
|
||||
// Now delete that first ACE
|
||||
child.deleteAce(0);
|
||||
|
||||
// Save and check it worked
|
||||
child = jdbcMutableAclService.updateAcl(child);
|
||||
assertEquals(2, child.getEntries().length);
|
||||
assertTrue(child.isGranted(new Permission[] {BasePermission.DELETE}, new Sid[] {new PrincipalSid(auth)}, false));
|
||||
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method that demonstrates eviction failure from cache - SEC-676
|
||||
*/
|
||||
public void testDeleteAclAlsoDeletesChildren() throws Exception {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
|
||||
|
||||
// Check the childOid really is a child of middleParentOid
|
||||
Acl childAcl = jdbcMutableAclService.readAclById(childOid);
|
||||
assertEquals(middleParentOid, childAcl.getParentAcl().getObjectIdentity());
|
||||
|
||||
// Delete the mid-parent and test if the child was deleted, as well
|
||||
jdbcMutableAclService.deleteAcl(middleParentOid, true);
|
||||
|
||||
try {
|
||||
Acl acl = jdbcMutableAclService.readAclById(middleParentOid);
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
Acl acl = jdbcMutableAclService.readAclById(childOid);
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
Acl acl = jdbcMutableAclService.readAclById(topParentOid);
|
||||
assertNotNull(acl);
|
||||
assertEquals(((MutableAcl) acl).getObjectIdentity(), topParentOid);
|
||||
}
|
||||
|
||||
public void testConstructorRejectsNullParameters() throws Exception {
|
||||
try {
|
||||
JdbcAclService service = new JdbcMutableAclService(null, lookupStrategy, aclCache);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
JdbcAclService service = new JdbcMutableAclService(this.getJdbcTemplate().getDataSource(), null, aclCache);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
JdbcAclService service = new JdbcMutableAclService(this.getJdbcTemplate().getDataSource(), lookupStrategy, null);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testCreateAclRejectsNullParameter() throws Exception {
|
||||
try {
|
||||
jdbcMutableAclService.createAcl(null);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testCreateAclForADuplicateDomainObject() throws Exception {
|
||||
ObjectIdentity duplicateOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
|
||||
// Try to add the same object second time
|
||||
try {
|
||||
jdbcMutableAclService.createAcl(duplicateOid);
|
||||
fail("It should have thrown AlreadyExistsException");
|
||||
}
|
||||
catch (AlreadyExistsException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testDeleteAclRejectsNullParameters() throws Exception {
|
||||
try {
|
||||
jdbcMutableAclService.deleteAcl(null, true);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testDeleteAclWithChildrenThrowsException() throws Exception {
|
||||
try {
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
jdbcMutableAclService.setForeignKeysInDatabase(false); // switch on FK checking in the class, not database
|
||||
jdbcMutableAclService.deleteAcl(topParentOid, false);
|
||||
fail("It should have thrown ChildrenExistException");
|
||||
}
|
||||
catch (ChildrenExistException expected) {
|
||||
assertTrue(true);
|
||||
} finally {
|
||||
jdbcMutableAclService.setForeignKeysInDatabase(true); // restore to the default
|
||||
}
|
||||
}
|
||||
|
||||
public void testDeleteAclRemovesRowsFromDatabase() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ADMINISTRATOR")});
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
|
||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(102));
|
||||
|
||||
// Remove the child and check all related database rows were removed accordingly
|
||||
jdbcMutableAclService.deleteAcl(childOid, false);
|
||||
assertEquals(1, getJdbcTemplate().queryForList(SELECT_ALL_CLASSES, new Object[] {"org.springframework.security.TargetObject"} ).size());
|
||||
assertEquals(0, getJdbcTemplate().queryForList(SELECT_OBJECT_IDENTITY, new Object[] {new Long(102)}).size());
|
||||
assertEquals(2, getJdbcTemplate().queryForList(SELECT_ALL_OBJECT_IDENTITIES).size());
|
||||
assertEquals(3, getJdbcTemplate().queryForList(SELECT_ACL_ENTRY, new Object[] {new Long(103)} ).size());
|
||||
|
||||
// Check the cache
|
||||
assertNull(aclCache.getFromCache(childOid));
|
||||
assertNull(aclCache.getFromCache(new Long(102)));
|
||||
}
|
||||
|
||||
/**
|
||||
* SEC-655
|
||||
*/
|
||||
/* public void testClearChildrenFromCacheWhenParentIsUpdated() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ADMINISTRATOR")});
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity parentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(104));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(105));
|
||||
|
||||
MutableAcl parent = jdbcMutableAclService.createAcl(parentOid);
|
||||
MutableAcl child = jdbcMutableAclService.createAcl(childOid);
|
||||
|
||||
child.setParent(parent);
|
||||
jdbcMutableAclService.updateAcl(child);
|
||||
|
||||
parent = (AclImpl) jdbcMutableAclService.readAclById(parentOid);
|
||||
parent.insertAce(null, BasePermission.READ, new PrincipalSid("ben"), true);
|
||||
jdbcMutableAclService.updateAcl(parent);
|
||||
|
||||
parent = (AclImpl) jdbcMutableAclService.readAclById(parentOid);
|
||||
parent.insertAce(null, BasePermission.READ, new PrincipalSid("scott"), true);
|
||||
jdbcMutableAclService.updateAcl(parent);
|
||||
|
||||
child = (MutableAcl) jdbcMutableAclService.readAclById(childOid);
|
||||
parent = (MutableAcl) child.getParentAcl();
|
||||
|
||||
assertEquals("Fails because child has a stale reference to its parent", 2, parent.getEntries().length);
|
||||
assertEquals(1, parent.getEntries()[0].getPermission().getMask());
|
||||
assertEquals(new PrincipalSid("ben"), parent.getEntries()[0].getSid());
|
||||
assertEquals(1, parent.getEntries()[1].getPermission().getMask());
|
||||
assertEquals(new PrincipalSid("scott"), parent.getEntries()[1].getSid());
|
||||
}*/
|
||||
|
||||
/* public void testCumulativePermissions() {
|
||||
setComplete();
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored", new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ADMINISTRATOR")});
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(110));
|
||||
MutableAcl topParent = jdbcMutableAclService.createAcl(topParentOid);
|
||||
|
||||
// Add an ACE permission entry
|
||||
CumulativePermission cm = new CumulativePermission().set(BasePermission.READ).set(BasePermission.ADMINISTRATION);
|
||||
assertEquals(17, cm.getMask());
|
||||
topParent.insertAce(null, cm, new PrincipalSid(auth), true);
|
||||
assertEquals(1, topParent.getEntries().length);
|
||||
|
||||
// Explictly save the changed ACL
|
||||
topParent = jdbcMutableAclService.updateAcl(topParent);
|
||||
|
||||
// Check the mask was retrieved correctly
|
||||
assertEquals(17, topParent.getEntries()[0].getPermission().getMask());
|
||||
assertTrue(topParent.isGranted(new Permission[] {cm}, new Sid[] {new PrincipalSid(auth)}, true));
|
||||
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
*/
|
||||
}
|
||||
-494
@@ -1,494 +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.acls.jdbc;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.security.acls.TargetObject;
|
||||
import org.springframework.security.acls.domain.AclImpl;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.domain.CumulativePermission;
|
||||
import org.springframework.security.acls.domain.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.domain.PrincipalSid;
|
||||
import org.springframework.security.acls.model.AccessControlEntry;
|
||||
import org.springframework.security.acls.model.Acl;
|
||||
import org.springframework.security.acls.model.AclCache;
|
||||
import org.springframework.security.acls.model.AlreadyExistsException;
|
||||
import org.springframework.security.acls.model.ChildrenExistException;
|
||||
import org.springframework.security.acls.model.MutableAcl;
|
||||
import org.springframework.security.acls.model.NotFoundException;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.Permission;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
|
||||
import org.springframework.test.context.transaction.AfterTransaction;
|
||||
import org.springframework.test.context.transaction.BeforeTransaction;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Integration tests the ACL system using an in-memory database.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Andrei Stefan
|
||||
* @version $Id:JdbcMutableAclServiceTests.java 1754 2006-11-17 02:01:21Z benalex $
|
||||
*/
|
||||
@ContextConfiguration(locations={"/jdbcMutableAclServiceTests-context.xml"})
|
||||
public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4SpringContextTests {
|
||||
//~ Constant fields ================================================================================================
|
||||
|
||||
private static final String TARGET_CLASS = TargetObject.class.getName();
|
||||
|
||||
private final Authentication auth = new TestingAuthenticationToken("ben", "ignored","ROLE_ADMINISTRATOR");
|
||||
|
||||
public static final String SELECT_ALL_CLASSES = "SELECT * FROM acl_class WHERE class = ?";
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(100));
|
||||
private final ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(101));
|
||||
private final ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(102));
|
||||
|
||||
@Autowired
|
||||
private JdbcMutableAclService jdbcMutableAclService;
|
||||
@Autowired
|
||||
private AclCache aclCache;
|
||||
@Autowired
|
||||
private LookupStrategy lookupStrategy;
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
@Autowired
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@BeforeTransaction
|
||||
public void createTables() throws Exception {
|
||||
try {
|
||||
new DatabaseSeeder(dataSource, new ClassPathResource("createAclSchema.sql"));
|
||||
// new DatabaseSeeder(dataSource, new ClassPathResource("createAclSchemaPostgres.sql"));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@AfterTransaction
|
||||
public void clearContextAndData() throws Exception {
|
||||
SecurityContextHolder.clearContext();
|
||||
jdbcTemplate.execute("drop table acl_entry");
|
||||
jdbcTemplate.execute("drop table acl_object_identity");
|
||||
jdbcTemplate.execute("drop table acl_class");
|
||||
jdbcTemplate.execute("drop table acl_sid");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional
|
||||
public void testLifecycle() {
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
MutableAcl topParent = jdbcMutableAclService.createAcl(topParentOid);
|
||||
MutableAcl middleParent = jdbcMutableAclService.createAcl(middleParentOid);
|
||||
MutableAcl child = jdbcMutableAclService.createAcl(childOid);
|
||||
|
||||
// Specify the inheritance hierarchy
|
||||
middleParent.setParent(topParent);
|
||||
child.setParent(middleParent);
|
||||
|
||||
// Now let's add a couple of permissions
|
||||
topParent.insertAce(0, BasePermission.READ, new PrincipalSid(auth), true);
|
||||
topParent.insertAce(1, BasePermission.WRITE, new PrincipalSid(auth), false);
|
||||
middleParent.insertAce(0, BasePermission.DELETE, new PrincipalSid(auth), true);
|
||||
child.insertAce(0, BasePermission.DELETE, new PrincipalSid(auth), false);
|
||||
|
||||
// Explicitly save the changed ACL
|
||||
jdbcMutableAclService.updateAcl(topParent);
|
||||
jdbcMutableAclService.updateAcl(middleParent);
|
||||
jdbcMutableAclService.updateAcl(child);
|
||||
|
||||
// Let's check if we can read them back correctly
|
||||
Map<ObjectIdentity, Acl> map = jdbcMutableAclService.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid));
|
||||
assertEquals(3, map.size());
|
||||
|
||||
// Replace our current objects with their retrieved versions
|
||||
topParent = (MutableAcl) map.get(topParentOid);
|
||||
middleParent = (MutableAcl) map.get(middleParentOid);
|
||||
child = (MutableAcl) map.get(childOid);
|
||||
|
||||
// Check the retrieved versions has IDs
|
||||
assertNotNull(topParent.getId());
|
||||
assertNotNull(middleParent.getId());
|
||||
assertNotNull(child.getId());
|
||||
|
||||
// Check their parents were correctly persisted
|
||||
assertNull(topParent.getParentAcl());
|
||||
assertEquals(topParentOid, middleParent.getParentAcl().getObjectIdentity());
|
||||
assertEquals(middleParentOid, child.getParentAcl().getObjectIdentity());
|
||||
|
||||
// Check their ACEs were correctly persisted
|
||||
assertEquals(2, topParent.getEntries().size());
|
||||
assertEquals(1, middleParent.getEntries().size());
|
||||
assertEquals(1, child.getEntries().size());
|
||||
|
||||
// Check the retrieved rights are correct
|
||||
List<Permission> read = Arrays.asList(BasePermission.READ);
|
||||
List<Permission> write = Arrays.asList(BasePermission.WRITE);
|
||||
List<Permission> delete = Arrays.asList(BasePermission.DELETE);
|
||||
List<Sid> pSid = Arrays.asList((Sid)new PrincipalSid(auth));
|
||||
|
||||
|
||||
assertTrue(topParent.isGranted(read, pSid, false));
|
||||
assertFalse(topParent.isGranted(write, pSid, false));
|
||||
assertTrue(middleParent.isGranted(delete, pSid, false));
|
||||
assertFalse(child.isGranted(delete, pSid, false));
|
||||
|
||||
try {
|
||||
child.isGranted(Arrays.asList(BasePermission.ADMINISTRATION), pSid, false);
|
||||
fail("Should have thrown NotFoundException");
|
||||
} catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
// Now check the inherited rights (when not explicitly overridden) also look OK
|
||||
assertTrue(child.isGranted(read, pSid, false));
|
||||
assertFalse(child.isGranted(write, pSid, false));
|
||||
assertFalse(child.isGranted(delete, pSid, false));
|
||||
|
||||
// Next change the child so it doesn't inherit permissions from above
|
||||
child.setEntriesInheriting(false);
|
||||
jdbcMutableAclService.updateAcl(child);
|
||||
child = (MutableAcl) jdbcMutableAclService.readAclById(childOid);
|
||||
assertFalse(child.isEntriesInheriting());
|
||||
|
||||
// Check the child permissions no longer inherit
|
||||
assertFalse(child.isGranted(delete, pSid, true));
|
||||
|
||||
try {
|
||||
child.isGranted(read, pSid, true);
|
||||
fail("Should have thrown NotFoundException");
|
||||
} catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
child.isGranted(write, pSid, true);
|
||||
fail("Should have thrown NotFoundException");
|
||||
} catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
// Let's add an identical permission to the child, but it'll appear AFTER the current permission, so has no impact
|
||||
child.insertAce(1, BasePermission.DELETE, new PrincipalSid(auth), true);
|
||||
|
||||
// Let's also add another permission to the child
|
||||
child.insertAce(2, BasePermission.CREATE, new PrincipalSid(auth), true);
|
||||
|
||||
// Save the changed child
|
||||
jdbcMutableAclService.updateAcl(child);
|
||||
child = (MutableAcl) jdbcMutableAclService.readAclById(childOid);
|
||||
assertEquals(3, child.getEntries().size());
|
||||
|
||||
// Output permissions
|
||||
for (int i = 0; i < child.getEntries().size(); i++) {
|
||||
System.out.println(child.getEntries().get(i));
|
||||
}
|
||||
|
||||
// Check the permissions are as they should be
|
||||
assertFalse(child.isGranted(delete, pSid, true)); // as earlier permission overrode
|
||||
assertTrue(child.isGranted(Arrays.asList(BasePermission.CREATE), pSid, true));
|
||||
|
||||
// Now check the first ACE (index 0) really is DELETE for our Sid and is non-granting
|
||||
AccessControlEntry entry = child.getEntries().get(0);
|
||||
assertEquals(BasePermission.DELETE.getMask(), entry.getPermission().getMask());
|
||||
assertEquals(new PrincipalSid(auth), entry.getSid());
|
||||
assertFalse(entry.isGranting());
|
||||
assertNotNull(entry.getId());
|
||||
|
||||
// Now delete that first ACE
|
||||
child.deleteAce(0);
|
||||
|
||||
// Save and check it worked
|
||||
child = jdbcMutableAclService.updateAcl(child);
|
||||
assertEquals(2, child.getEntries().size());
|
||||
assertTrue(child.isGranted(delete, pSid, false));
|
||||
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method that demonstrates eviction failure from cache - SEC-676
|
||||
*/
|
||||
@Test
|
||||
@Transactional
|
||||
public void deleteAclAlsoDeletesChildren() throws Exception {
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
jdbcMutableAclService.createAcl(topParentOid);
|
||||
MutableAcl middleParent = jdbcMutableAclService.createAcl(middleParentOid);
|
||||
MutableAcl child = jdbcMutableAclService.createAcl(childOid);
|
||||
child.setParent(middleParent);
|
||||
jdbcMutableAclService.updateAcl(middleParent);
|
||||
jdbcMutableAclService.updateAcl(child);
|
||||
// Check the childOid really is a child of middleParentOid
|
||||
Acl childAcl = jdbcMutableAclService.readAclById(childOid);
|
||||
|
||||
assertEquals(middleParentOid, childAcl.getParentAcl().getObjectIdentity());
|
||||
|
||||
// Delete the mid-parent and test if the child was deleted, as well
|
||||
jdbcMutableAclService.deleteAcl(middleParentOid, true);
|
||||
|
||||
try {
|
||||
jdbcMutableAclService.readAclById(middleParentOid);
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
try {
|
||||
jdbcMutableAclService.readAclById(childOid);
|
||||
fail("It should have thrown NotFoundException");
|
||||
}
|
||||
catch (NotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
Acl acl = jdbcMutableAclService.readAclById(topParentOid);
|
||||
assertNotNull(acl);
|
||||
assertEquals(((MutableAcl) acl).getObjectIdentity(), topParentOid);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorRejectsNullParameters() throws Exception {
|
||||
try {
|
||||
new JdbcMutableAclService(null, lookupStrategy, aclCache);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
|
||||
try {
|
||||
new JdbcMutableAclService(dataSource, null, aclCache);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
|
||||
try {
|
||||
new JdbcMutableAclService(dataSource, lookupStrategy, null);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createAclRejectsNullParameter() throws Exception {
|
||||
try {
|
||||
jdbcMutableAclService.createAcl(null);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional
|
||||
public void createAclForADuplicateDomainObject() throws Exception {
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
ObjectIdentity duplicateOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(100));
|
||||
jdbcMutableAclService.createAcl(duplicateOid);
|
||||
// Try to add the same object second time
|
||||
try {
|
||||
jdbcMutableAclService.createAcl(duplicateOid);
|
||||
fail("It should have thrown AlreadyExistsException");
|
||||
}
|
||||
catch (AlreadyExistsException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional
|
||||
public void deleteAclRejectsNullParameters() throws Exception {
|
||||
try {
|
||||
jdbcMutableAclService.deleteAcl(null, true);
|
||||
fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional
|
||||
public void deleteAclWithChildrenThrowsException() throws Exception {
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
MutableAcl parent = jdbcMutableAclService.createAcl(topParentOid);
|
||||
MutableAcl child = jdbcMutableAclService.createAcl(middleParentOid);
|
||||
|
||||
// Specify the inheritance hierarchy
|
||||
child.setParent(parent);
|
||||
jdbcMutableAclService.updateAcl(child);
|
||||
|
||||
try {
|
||||
jdbcMutableAclService.setForeignKeysInDatabase(false); // switch on FK checking in the class, not database
|
||||
jdbcMutableAclService.deleteAcl(topParentOid, false);
|
||||
fail("It should have thrown ChildrenExistException");
|
||||
}
|
||||
catch (ChildrenExistException expected) {
|
||||
} finally {
|
||||
jdbcMutableAclService.setForeignKeysInDatabase(true); // restore to the default
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional
|
||||
public void deleteAclRemovesRowsFromDatabase() throws Exception {
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
MutableAcl child = jdbcMutableAclService.createAcl(childOid);
|
||||
child.insertAce(0, BasePermission.DELETE, new PrincipalSid(auth), false);
|
||||
jdbcMutableAclService.updateAcl(child);
|
||||
|
||||
// Remove the child and check all related database rows were removed accordingly
|
||||
jdbcMutableAclService.deleteAcl(childOid, false);
|
||||
assertEquals(1, jdbcTemplate.queryForList(SELECT_ALL_CLASSES, new Object[] {TARGET_CLASS} ).size());
|
||||
assertEquals(0, jdbcTemplate.queryForList("select * from acl_object_identity").size());
|
||||
assertEquals(0, jdbcTemplate.queryForList("select * from acl_entry").size());
|
||||
|
||||
// Check the cache
|
||||
assertNull(aclCache.getFromCache(childOid));
|
||||
assertNull(aclCache.getFromCache(Long.valueOf(102)));
|
||||
}
|
||||
|
||||
/** SEC-1107 */
|
||||
@Test
|
||||
@Transactional
|
||||
public void identityWithIntegerIdIsSupportedByCreateAcl() throws Exception {
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
ObjectIdentity oid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(101));
|
||||
jdbcMutableAclService.createAcl(oid);
|
||||
|
||||
assertNotNull(jdbcMutableAclService.readAclById(new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(101))));
|
||||
}
|
||||
|
||||
/**
|
||||
* SEC-655
|
||||
*/
|
||||
@Test
|
||||
@Transactional
|
||||
public void childrenAreClearedFromCacheWhenParentIsUpdated() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored","ROLE_ADMINISTRATOR");
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity parentOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(104));
|
||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(105));
|
||||
|
||||
MutableAcl parent = jdbcMutableAclService.createAcl(parentOid);
|
||||
MutableAcl child = jdbcMutableAclService.createAcl(childOid);
|
||||
|
||||
child.setParent(parent);
|
||||
jdbcMutableAclService.updateAcl(child);
|
||||
|
||||
parent = (AclImpl) jdbcMutableAclService.readAclById(parentOid);
|
||||
parent.insertAce(0, BasePermission.READ, new PrincipalSid("ben"), true);
|
||||
jdbcMutableAclService.updateAcl(parent);
|
||||
|
||||
parent = (AclImpl) jdbcMutableAclService.readAclById(parentOid);
|
||||
parent.insertAce(1, BasePermission.READ, new PrincipalSid("scott"), true);
|
||||
jdbcMutableAclService.updateAcl(parent);
|
||||
|
||||
child = (MutableAcl) jdbcMutableAclService.readAclById(childOid);
|
||||
parent = (MutableAcl) child.getParentAcl();
|
||||
|
||||
assertEquals("Fails because child has a stale reference to its parent", 2, parent.getEntries().size());
|
||||
assertEquals(1, parent.getEntries().get(0).getPermission().getMask());
|
||||
assertEquals(new PrincipalSid("ben"), parent.getEntries().get(0).getSid());
|
||||
assertEquals(1, parent.getEntries().get(1).getPermission().getMask());
|
||||
assertEquals(new PrincipalSid("scott"), parent.getEntries().get(1).getSid());
|
||||
}
|
||||
|
||||
/**
|
||||
* SEC-655
|
||||
*/
|
||||
@Test
|
||||
@Transactional
|
||||
public void childrenAreClearedFromCacheWhenParentisUpdated2() throws Exception {
|
||||
Authentication auth = new TestingAuthenticationToken("system", "secret","ROLE_IGNORED");
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
ObjectIdentityImpl rootObject = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(1));
|
||||
|
||||
MutableAcl parent = jdbcMutableAclService.createAcl(rootObject);
|
||||
MutableAcl child = jdbcMutableAclService.createAcl(new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(2)));
|
||||
child.setParent(parent);
|
||||
jdbcMutableAclService.updateAcl(child);
|
||||
|
||||
parent.insertAce(0, BasePermission.ADMINISTRATION, new GrantedAuthoritySid("ROLE_ADMINISTRATOR"), true);
|
||||
jdbcMutableAclService.updateAcl(parent);
|
||||
|
||||
parent.insertAce(1, BasePermission.DELETE, new PrincipalSid("terry"), true);
|
||||
jdbcMutableAclService.updateAcl(parent);
|
||||
|
||||
child = (MutableAcl) jdbcMutableAclService.readAclById(new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(2)));
|
||||
|
||||
parent = (MutableAcl) child.getParentAcl();
|
||||
|
||||
assertEquals(2, parent.getEntries().size());
|
||||
assertEquals(16, parent.getEntries().get(0).getPermission().getMask());
|
||||
assertEquals(new GrantedAuthoritySid("ROLE_ADMINISTRATOR"), parent.getEntries().get(0).getSid());
|
||||
assertEquals(8, parent.getEntries().get(1).getPermission().getMask());
|
||||
assertEquals(new PrincipalSid("terry"), parent.getEntries().get(1).getSid());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional
|
||||
public void cumulativePermissions() {
|
||||
Authentication auth = new TestingAuthenticationToken("ben", "ignored", "ROLE_ADMINISTRATOR");
|
||||
auth.setAuthenticated(true);
|
||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||
|
||||
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(110));
|
||||
MutableAcl topParent = jdbcMutableAclService.createAcl(topParentOid);
|
||||
|
||||
// Add an ACE permission entry
|
||||
Permission cm = new CumulativePermission().set(BasePermission.READ).set(BasePermission.ADMINISTRATION);
|
||||
assertEquals(17, cm.getMask());
|
||||
Sid benSid = new PrincipalSid(auth);
|
||||
topParent.insertAce(0, cm, benSid, true);
|
||||
assertEquals(1, topParent.getEntries().size());
|
||||
|
||||
// Explicitly save the changed ACL
|
||||
topParent = jdbcMutableAclService.updateAcl(topParent);
|
||||
|
||||
// Check the mask was retrieved correctly
|
||||
assertEquals(17, topParent.getEntries().get(0).getPermission().getMask());
|
||||
assertTrue(topParent.isGranted(Arrays.asList(cm), Arrays.asList(benSid), true));
|
||||
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
}
|
||||
+1
-6
@@ -1,9 +1,4 @@
|
||||
package org.springframework.security.acls.domain;
|
||||
|
||||
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
|
||||
import org.springframework.security.acls.model.ObjectIdentity;
|
||||
import org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy;
|
||||
package org.springframework.security.acls.objectidentity;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
package org.springframework.security.acls.objectidentity;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.acls.IdentityUnavailableException;
|
||||
|
||||
/**
|
||||
* Tests for {@link ObjectIdentityImpl}.
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
*/
|
||||
public class ObjectIdentityTests extends TestCase {
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void testConstructorsRequiredFields() throws Exception {
|
||||
// Check one-argument constructor required field
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(null);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// Check String-Serializable constructor required field
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl("", new Long(1));
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// Check Serializable parameter is not null
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", null);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// The correct way of using String-Serializable constructor
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject",
|
||||
new Long(1));
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
Assert.fail("It shouldn't have thrown IllegalArgumentException");
|
||||
}
|
||||
|
||||
// Check the Class-Serializable constructor
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(MockIdDomainObject.class, null);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetIdMethodConstraints() throws Exception {
|
||||
// Check the getId() method is present
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl("A_STRING_OBJECT");
|
||||
Assert.fail("It should have thrown IdentityUnavailableException");
|
||||
}
|
||||
catch (IdentityUnavailableException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// getId() should return a non-null value
|
||||
MockIdDomainObject mockId = new MockIdDomainObject();
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(mockId);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// getId() should return a Serializable object
|
||||
mockId.setId(new MockIdDomainObject());
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(mockId);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
// getId() should return a Serializable object
|
||||
mockId.setId(new Long(100));
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(mockId);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
Assert.fail("It shouldn't have thrown IllegalArgumentException");
|
||||
}
|
||||
}
|
||||
|
||||
public void testConstructorInvalidClassParameter() throws Exception {
|
||||
try {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl("not.a.Class", new Long(1));
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
return;
|
||||
}
|
||||
Assert.fail("It should have thrown IllegalStateException");
|
||||
}
|
||||
|
||||
public void testEquals() throws Exception {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", new Long(1));
|
||||
MockIdDomainObject mockObj = new MockIdDomainObject();
|
||||
mockObj.setId(new Long(1));
|
||||
|
||||
String string = "SOME_STRING";
|
||||
Assert.assertNotSame(obj, string);
|
||||
Assert.assertTrue(!obj.equals(null));
|
||||
Assert.assertTrue(!obj.equals("DIFFERENT_OBJECT_TYPE"));
|
||||
Assert.assertTrue(!obj
|
||||
.equals(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject",
|
||||
new Long(2))));
|
||||
Assert.assertTrue(!obj.equals(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockOtherIdDomainObject",
|
||||
new Long(1))));
|
||||
Assert.assertEquals(
|
||||
new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject",
|
||||
new Long(1)), obj);
|
||||
Assert.assertTrue(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", new Long(1))
|
||||
.equals(obj));
|
||||
Assert.assertTrue(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", new Long(1))
|
||||
.equals(new ObjectIdentityImpl(mockObj)));
|
||||
}
|
||||
|
||||
public void testHashCode() throws Exception {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", new Long(1));
|
||||
Assert.assertEquals(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", new Long(1))
|
||||
.hashCode(), obj.hashCode());
|
||||
Assert.assertTrue(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockOtherIdDomainObject",
|
||||
new Long(1)).hashCode() != obj.hashCode());
|
||||
Assert.assertTrue(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", new Long(2))
|
||||
.hashCode() != obj.hashCode());
|
||||
}
|
||||
|
||||
/* public void testHashCodeDifferentSerializableTypes() throws Exception {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", new Long(1));
|
||||
Assert.assertEquals(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", "1")
|
||||
.hashCode(), obj.hashCode());
|
||||
Assert.assertEquals(new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject",
|
||||
new Integer(1)).hashCode(), obj.hashCode());
|
||||
}*/
|
||||
|
||||
public void testGetters() throws Exception {
|
||||
ObjectIdentity obj = new ObjectIdentityImpl(
|
||||
"org.springframework.security.acls.objectidentity.ObjectIdentityTests$MockIdDomainObject", new Long(1));
|
||||
Assert.assertEquals(new Long(1), obj.getIdentifier());
|
||||
Assert.assertEquals(MockIdDomainObject.class, obj.getJavaType());
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class MockIdDomainObject {
|
||||
private Object id;
|
||||
|
||||
public Object getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Object id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
private class MockOtherIdDomainObject {
|
||||
private Object id;
|
||||
|
||||
public Object getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Object id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
-47
@@ -1,66 +1,40 @@
|
||||
package org.springframework.security.acls.sid;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.acls.domain.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.domain.PrincipalSid;
|
||||
import org.springframework.security.acls.domain.SidRetrievalStrategyImpl;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.acls.model.SidRetrievalStrategy;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.providers.TestingAuthenticationToken;
|
||||
|
||||
/**
|
||||
* Tests for {@link SidRetrievalStrategyImpl}
|
||||
*
|
||||
*
|
||||
* @author Andrei Stefan
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class SidRetrievalStrategyTests {
|
||||
Authentication authentication = new TestingAuthenticationToken("scott", "password", "A", "B", "C");
|
||||
public class SidRetrievalStrategyTests extends TestCase {
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@Test
|
||||
public void correctSidsAreRetrieved() throws Exception {
|
||||
public void testSidsRetrieval() throws Exception {
|
||||
Authentication authentication = new TestingAuthenticationToken("scott", "password", new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_1"), new GrantedAuthorityImpl("ROLE_2"), new GrantedAuthorityImpl("ROLE_3") });
|
||||
SidRetrievalStrategy retrStrategy = new SidRetrievalStrategyImpl();
|
||||
List<Sid> sids = retrStrategy.getSids(authentication);
|
||||
Sid[] sids = retrStrategy.getSids(authentication);
|
||||
|
||||
assertNotNull(sids);
|
||||
assertEquals(4, sids.size());
|
||||
assertNotNull(sids.get(0));
|
||||
assertTrue(sids.get(0) instanceof PrincipalSid);
|
||||
assertEquals(4, sids.length);
|
||||
assertNotNull(sids[0]);
|
||||
assertTrue(sids[0] instanceof PrincipalSid);
|
||||
|
||||
for (int i = 1; i < sids.size(); i++) {
|
||||
assertTrue(sids.get(i) instanceof GrantedAuthoritySid);
|
||||
for (int i = 1; i < sids.length; i++) {
|
||||
assertTrue(sids[i] instanceof GrantedAuthoritySid);
|
||||
}
|
||||
|
||||
assertEquals("scott", ((PrincipalSid) sids.get(0)).getPrincipal());
|
||||
assertEquals("A", ((GrantedAuthoritySid) sids.get(1)).getGrantedAuthority());
|
||||
assertEquals("B", ((GrantedAuthoritySid) sids.get(2)).getGrantedAuthority());
|
||||
assertEquals("C", ((GrantedAuthoritySid) sids.get(3)).getGrantedAuthority());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void roleHierarchyIsUsedWhenSet() throws Exception {
|
||||
RoleHierarchy rh = mock(RoleHierarchy.class);
|
||||
List<GrantedAuthority> rhAuthorities = AuthorityUtils.createAuthorityList("D");
|
||||
when(rh.getReachableGrantedAuthorities(anyList())).thenReturn(rhAuthorities);
|
||||
SidRetrievalStrategy strat = new SidRetrievalStrategyImpl(rh);
|
||||
|
||||
List<Sid> sids = strat.getSids(authentication);
|
||||
assertEquals(2, sids.size());
|
||||
assertNotNull(sids.get(0));
|
||||
assertTrue(sids.get(0) instanceof PrincipalSid);
|
||||
assertEquals("D", ((GrantedAuthoritySid) sids.get(1)).getGrantedAuthority());
|
||||
Assert.assertEquals("scott", ((PrincipalSid) sids[0]).getPrincipal());
|
||||
Assert.assertEquals("ROLE_1", ((GrantedAuthoritySid) sids[1]).getGrantedAuthority());
|
||||
Assert.assertEquals("ROLE_2", ((GrantedAuthoritySid) sids[2]).getGrantedAuthority());
|
||||
Assert.assertEquals("ROLE_3", ((GrantedAuthoritySid) sids[3]).getGrantedAuthority());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@ package org.springframework.security.acls.sid;
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.acls.domain.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.domain.PrincipalSid;
|
||||
import org.springframework.security.acls.model.Sid;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.GrantedAuthorityImpl;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.acls.sid.GrantedAuthoritySid;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.security.providers.TestingAuthenticationToken;
|
||||
|
||||
public class SidTests extends TestCase {
|
||||
|
||||
@@ -19,7 +19,7 @@ public class SidTests extends TestCase {
|
||||
// Check one String-argument constructor
|
||||
try {
|
||||
String string = null;
|
||||
new PrincipalSid(string);
|
||||
Sid principalSid = new PrincipalSid(string);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
@@ -27,7 +27,7 @@ public class SidTests extends TestCase {
|
||||
}
|
||||
|
||||
try {
|
||||
new PrincipalSid("");
|
||||
Sid principalSid = new PrincipalSid("");
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
@@ -35,7 +35,7 @@ public class SidTests extends TestCase {
|
||||
}
|
||||
|
||||
try {
|
||||
new PrincipalSid("johndoe");
|
||||
Sid principalSid = new PrincipalSid("johndoe");
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
@@ -45,7 +45,7 @@ public class SidTests extends TestCase {
|
||||
// Check one Authentication-argument constructor
|
||||
try {
|
||||
Authentication authentication = null;
|
||||
new PrincipalSid(authentication);
|
||||
Sid principalSid = new PrincipalSid(authentication);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
@@ -54,7 +54,7 @@ public class SidTests extends TestCase {
|
||||
|
||||
try {
|
||||
Authentication authentication = new TestingAuthenticationToken(null, "password");
|
||||
new PrincipalSid(authentication);
|
||||
Sid principalSid = new PrincipalSid(authentication);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
@@ -63,7 +63,7 @@ public class SidTests extends TestCase {
|
||||
|
||||
try {
|
||||
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
|
||||
new PrincipalSid(authentication);
|
||||
Sid principalSid = new PrincipalSid(authentication);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
@@ -75,7 +75,7 @@ public class SidTests extends TestCase {
|
||||
// Check one String-argument constructor
|
||||
try {
|
||||
String string = null;
|
||||
new GrantedAuthoritySid(string);
|
||||
Sid gaSid = new GrantedAuthoritySid(string);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
@@ -83,7 +83,7 @@ public class SidTests extends TestCase {
|
||||
}
|
||||
|
||||
try {
|
||||
new GrantedAuthoritySid("");
|
||||
Sid gaSid = new GrantedAuthoritySid("");
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
@@ -91,7 +91,7 @@ public class SidTests extends TestCase {
|
||||
}
|
||||
|
||||
try {
|
||||
new GrantedAuthoritySid("ROLE_TEST");
|
||||
Sid gaSid = new GrantedAuthoritySid("ROLE_TEST");
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
@@ -101,7 +101,7 @@ public class SidTests extends TestCase {
|
||||
// Check one GrantedAuthority-argument constructor
|
||||
try {
|
||||
GrantedAuthority ga = null;
|
||||
new GrantedAuthoritySid(ga);
|
||||
Sid gaSid = new GrantedAuthoritySid(ga);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
@@ -110,7 +110,7 @@ public class SidTests extends TestCase {
|
||||
|
||||
try {
|
||||
GrantedAuthority ga = new GrantedAuthorityImpl(null);
|
||||
new GrantedAuthoritySid(ga);
|
||||
Sid gaSid = new GrantedAuthoritySid(ga);
|
||||
Assert.fail("It should have thrown IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
@@ -119,7 +119,7 @@ public class SidTests extends TestCase {
|
||||
|
||||
try {
|
||||
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
|
||||
new GrantedAuthoritySid(ga);
|
||||
Sid gaSid = new GrantedAuthoritySid(ga);
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
catch (IllegalArgumentException notExpected) {
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
|
||||
|
||||
<!--
|
||||
- Application context containing business beans.
|
||||
-
|
||||
- Used by all artifacts.
|
||||
-
|
||||
- $Id:applicationContext-test.xml 1754 2006-11-17 02:01:21Z benalex $
|
||||
-->
|
||||
|
||||
<beans>
|
||||
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
</bean>
|
||||
|
||||
<bean id="aclCache" class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
|
||||
<property name="cacheManager">
|
||||
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
|
||||
</property>
|
||||
<property name="cacheName" value="aclCache"/>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
|
||||
<constructor-arg ref="dataSource"/>
|
||||
<constructor-arg ref="aclCache"/>
|
||||
<constructor-arg ref="aclAuthorizationStrategy"/>
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
|
||||
<constructor-arg value="ROLE_ADMINISTRATOR"/>
|
||||
</bean>
|
||||
<bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
|
||||
<constructor-arg value="ROLE_ADMINISTRATOR"/>
|
||||
</bean>
|
||||
<bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
|
||||
<constructor-arg value="ROLE_ADMINISTRATOR"/>
|
||||
</bean>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="aclService" class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
|
||||
<constructor-arg ref="dataSource"/>
|
||||
<constructor-arg ref="lookupStrategy"/>
|
||||
<constructor-arg ref="aclCache"/>
|
||||
|
||||
<!-- Uncomment to use PostgreSQL
|
||||
<property name="classIdentityQuery" value="select currval(pg_get_serial_sequence('acl_class', 'id'))"/>
|
||||
<property name="sidIdentityQuery" value="select currval(pg_get_serial_sequence('acl_sid', 'id'))"/>
|
||||
-->
|
||||
</bean>
|
||||
|
||||
<!-- PostgreSQL DataSource configuration
|
||||
|
||||
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
||||
<property name="driverClassName" value="org.postgresql.Driver"/>
|
||||
<property name="url" value="jdbc:postgresql://localhost:5432/acltest"/>
|
||||
<property name="username" value="acltest"/>
|
||||
<property name="password" value="acltest"/>
|
||||
</bean>
|
||||
-->
|
||||
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
||||
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
|
||||
<property name="url" value="jdbc:hsqldb:mem:acltest"/>
|
||||
<property name="username" value="sa"/>
|
||||
<property name="password" value=""/>
|
||||
</bean>
|
||||
|
||||
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
+6
-8
@@ -8,14 +8,12 @@ Ignored-Existing-Headers:
|
||||
Export-Package
|
||||
Import-Template:
|
||||
org.apache.commons.logging.*;version="[1.0.4, 2.0.0)",
|
||||
org.springframework.security.core.*;version="[${version}, 3.1.0)",
|
||||
org.springframework.security.access.*;version="[${version}, 3.1.0)",
|
||||
org.springframework.security.util.*;version="[${version}, 3.1.0)",
|
||||
org.springframework.context.*;version="[3.0.0, 3.1.0)";resolution:=optional,
|
||||
org.springframework.dao.*;version="[3.0.0, 3.1.0)";resolution:=optional,
|
||||
org.springframework.jdbc.core.*;version="[3.0.0, 3.1.0)";resolution:=optional,
|
||||
org.springframework.transaction.support.*;version="[3.0.0, 3.1.0)";resolution:=optional,
|
||||
org.springframework.util.*;version="[3.0.0, 3.1.0)";resolution:=optional,
|
||||
org.springframework.security.*;version="[${version}, ${version}]",
|
||||
org.springframework.context.*;version="[2.0.8, 3.1.0)";resolution:=optional,
|
||||
org.springframework.dao.*;version="[2.0.8, 3.1.0)";resolution:=optional,
|
||||
org.springframework.jdbc.core.*;version="[2.0.8, 3.1.0)";resolution:=optional,
|
||||
org.springframework.transaction.support.*;version="[2.0.8, 3.1.0)";resolution:=optional,
|
||||
org.springframework.util.*;version="[2.0.8, 3.1.0)";resolution:=optional,
|
||||
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
|
||||
javax.sql.*;version="0";resolution:=optional
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
target
|
||||
@@ -0,0 +1,5 @@
|
||||
target
|
||||
.settings
|
||||
.classpath
|
||||
.project
|
||||
.wtpmodules
|
||||
@@ -0,0 +1,22 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.5.CI-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-catalina</artifactId>
|
||||
<name>Spring Security - Catalina adapter</name>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>tomcat</groupId>
|
||||
<artifactId>catalina</artifactId>
|
||||
<version>4.1.9</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
/* 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.adapters.catalina;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthenticationException;
|
||||
import org.springframework.security.AuthenticationManager;
|
||||
|
||||
import org.springframework.security.adapters.PrincipalSpringSecurityUserToken;
|
||||
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
|
||||
import org.apache.catalina.Container;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.realm.RealmBase;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.support.FileSystemXmlApplicationContext;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Adapter to enable Catalina (Tomcat) to authenticate via the Spring Security.<p>Returns a {@link
|
||||
* PrincipalSpringSecurityUserToken} to Catalina's authentication system, which is subsequently available via
|
||||
* <code>HttpServletRequest.getUserPrincipal()</code>.</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id:CatalinaSpringSecurityUserRealm.java 2151 2007-09-22 11:54:13Z luke_t $
|
||||
*/
|
||||
public class CatalinaSpringSecurityUserRealm extends RealmBase {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(CatalinaSpringSecurityUserRealm.class);
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
private Container container;
|
||||
private String appContextLocation;
|
||||
private String key;
|
||||
protected final String name = "CatalinaSpringUserRealm / $Id:CatalinaSpringSecurityUserRealm.java 2151 2007-09-22 11:54:13Z luke_t $";
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public Principal authenticate(String username, String credentials) {
|
||||
if (username == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (credentials == null) {
|
||||
credentials = "";
|
||||
}
|
||||
|
||||
Authentication request = new UsernamePasswordAuthenticationToken(username, credentials);
|
||||
Authentication response = null;
|
||||
|
||||
try {
|
||||
response = authenticationManager.authenticate(request);
|
||||
} catch (AuthenticationException failed) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Authentication request for user: " + username + " failed: " + failed.toString());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return new PrincipalSpringSecurityUserToken(this.key, response.getPrincipal().toString(),
|
||||
response.getCredentials().toString(), response.getAuthorities(), response.getPrincipal());
|
||||
}
|
||||
|
||||
public Principal authenticate(String username, byte[] credentials) {
|
||||
return authenticate(username, new String(credentials));
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported, returns null
|
||||
*
|
||||
* @param username DOCUMENT ME!
|
||||
* @param digest DOCUMENT ME!
|
||||
* @param nonce DOCUMENT ME!
|
||||
* @param nc DOCUMENT ME!
|
||||
* @param cnonce DOCUMENT ME!
|
||||
* @param qop DOCUMENT ME!
|
||||
* @param realm DOCUMENT ME!
|
||||
* @param md5a2 DOCUMENT ME!
|
||||
*
|
||||
* @return DOCUMENT ME!
|
||||
*/
|
||||
public java.security.Principal authenticate(java.lang.String username, java.lang.String digest,
|
||||
java.lang.String nonce, java.lang.String nc, java.lang.String cnonce, java.lang.String qop,
|
||||
java.lang.String realm, java.lang.String md5a2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported, returns null
|
||||
*
|
||||
* @param x509Certificates DOCUMENT ME!
|
||||
*
|
||||
* @return DOCUMENT ME!
|
||||
*/
|
||||
public Principal authenticate(X509Certificate[] x509Certificates) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getAppContextLocation() {
|
||||
return appContextLocation;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
protected String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns null (we override authenticate methods)
|
||||
*
|
||||
* @param arg0 DOCUMENT ME!
|
||||
*
|
||||
* @return DOCUMENT ME!
|
||||
*/
|
||||
protected String getPassword(String arg0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns null (we override authenticate methods)
|
||||
*
|
||||
* @param arg0 DOCUMENT ME!
|
||||
*
|
||||
* @return DOCUMENT ME!
|
||||
*/
|
||||
protected Principal getPrincipal(String arg0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hasRole(Principal principal, String role) {
|
||||
if ((principal == null) || (role == null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(principal instanceof PrincipalSpringSecurityUserToken)) {
|
||||
logger.warn("Expected passed principal to be of type PrincipalSpringSecurityUserToken but was "
|
||||
+ principal.getClass().getName());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
PrincipalSpringSecurityUserToken test = (PrincipalSpringSecurityUserToken) principal;
|
||||
|
||||
return test.isUserInRole(role);
|
||||
}
|
||||
|
||||
public void setAppContextLocation(String appContextLocation) {
|
||||
this.appContextLocation = appContextLocation;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the method that Catalina will use to start the container.
|
||||
*
|
||||
* @throws LifecycleException if a problem is detected
|
||||
*/
|
||||
public void start() throws LifecycleException {
|
||||
this.start(true);
|
||||
}
|
||||
|
||||
private void start(boolean startParent) throws LifecycleException {
|
||||
if (startParent) {
|
||||
super.start();
|
||||
}
|
||||
|
||||
if ((appContextLocation == null) || "".equals(appContextLocation)) {
|
||||
throw new LifecycleException("appContextLocation must be defined");
|
||||
}
|
||||
|
||||
if ((key == null) || "".equals(key)) {
|
||||
throw new LifecycleException("key must be defined");
|
||||
}
|
||||
|
||||
File xml = new File(System.getProperty("catalina.base"), appContextLocation);
|
||||
|
||||
if (!xml.exists()) {
|
||||
throw new LifecycleException("appContextLocation does not seem to exist in " + xml.toString());
|
||||
}
|
||||
|
||||
FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext("file:" + xml.getAbsolutePath());
|
||||
Map beans = ctx.getBeansOfType(AuthenticationManager.class, true, true);
|
||||
|
||||
if (beans.size() == 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Bean context must contain at least one bean of type AuthenticationManager");
|
||||
}
|
||||
|
||||
String beanName = (String) beans.keySet().iterator().next();
|
||||
authenticationManager = (AuthenticationManager) beans.get(beanName);
|
||||
logger.info("CatalinaSpringSecurityUserRealm Started");
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a method to load the container adapter without delegating to the superclass, which cannot
|
||||
* operate outside the Catalina container.
|
||||
*
|
||||
* @throws LifecycleException if a problem is detected
|
||||
*/
|
||||
protected void startForTest() throws LifecycleException {
|
||||
this.start(false);
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
Adapter to Catalina web container (Tomcat).
|
||||
<p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
|
||||
<!--
|
||||
* Copyright 2004 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.
|
||||
*
|
||||
*
|
||||
* $Id$
|
||||
-->
|
||||
|
||||
<beans>
|
||||
|
||||
<!-- Data access object which stores authentication information -->
|
||||
<bean id="inMemoryDaoImpl" class="org.springframework.security.userdetails.memory.InMemoryDaoImpl">
|
||||
<property name="userMap">
|
||||
<value>
|
||||
rod=koala,ROLE_TELLER,ROLE_SUPERVISOR
|
||||
dianne=emu,ROLE_TELLER
|
||||
scott=wombat,ROLE_TELLER
|
||||
peter=opal,disabled,ROLE_TELLER
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- The authentication manager is deliberately missing in order to test error detection -->
|
||||
|
||||
</beans>
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
|
||||
<!--
|
||||
* Copyright 2004 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.
|
||||
*
|
||||
*
|
||||
* $Id$
|
||||
-->
|
||||
|
||||
<beans>
|
||||
|
||||
<!-- Data access object which stores authentication information -->
|
||||
<bean id="inMemoryDaoImpl" class="org.springframework.security.userdetails.memory.InMemoryDaoImpl">
|
||||
<property name="userMap">
|
||||
<value>
|
||||
rod=koala,ROLE_TELLER,ROLE_SUPERVISOR
|
||||
dianne=emu,ROLE_TELLER
|
||||
scott=wombat,ROLE_TELLER
|
||||
peter=opal,disabled,ROLE_TELLER
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Authentication provider that queries our data access object -->
|
||||
<bean id="daoAuthenticationProvider" class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
|
||||
<property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property>
|
||||
<property name="forcePrincipalAsString"><value>true</value></property>
|
||||
</bean>
|
||||
|
||||
<!-- The authentication manager that iterates through our only authentication provider -->
|
||||
<bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
|
||||
<property name="providers">
|
||||
<list>
|
||||
<ref bean="daoAuthenticationProvider"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
+275
@@ -0,0 +1,275 @@
|
||||
/* 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.adapters.catalina;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
|
||||
import org.springframework.security.adapters.PrincipalSpringSecurityUserToken;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link CatalinaSpringSecurityUserRealm}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id:CatalinaSpringSecurityUserRealmTests.java 2151 2007-09-22 11:54:13Z luke_t $
|
||||
*/
|
||||
public class CatalinaSpringSecurityUserRealmTests extends TestCase {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final String ADAPTER_KEY = "my_key";
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public CatalinaSpringSecurityUserRealmTests() {
|
||||
super();
|
||||
}
|
||||
|
||||
public CatalinaSpringSecurityUserRealmTests(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(CatalinaSpringSecurityUserRealmTests.class);
|
||||
}
|
||||
|
||||
private CatalinaSpringSecurityUserRealm makeAdapter(String fileName)
|
||||
throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
|
||||
URL url = Thread.currentThread().getContextClassLoader().getResource("org/springframework/security/adapters/" + fileName);
|
||||
|
||||
if (url == null) {
|
||||
throw new Exception("Could not find " + fileName + " - cannot continue");
|
||||
}
|
||||
|
||||
File file = new File(url.getFile());
|
||||
|
||||
System.setProperty("catalina.base", file.getParentFile().getAbsolutePath());
|
||||
System.out.println("catalina.base set to: " + System.getProperty("catalina.base"));
|
||||
adapter.setAppContextLocation(fileName);
|
||||
adapter.setKey(ADAPTER_KEY);
|
||||
adapter.startForTest();
|
||||
|
||||
return adapter;
|
||||
}
|
||||
|
||||
public final void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
public void testAdapterAbortsIfAppContextDoesNotContainAnAuthenticationBean()
|
||||
throws Exception {
|
||||
try {
|
||||
CatalinaSpringSecurityUserRealm adapter = makeAdapter("catalinaAdapterTest-invalid.xml");
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testAdapterAbortsIfNoAppContextSpecified()
|
||||
throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
|
||||
adapter.setKey("KEY");
|
||||
|
||||
try {
|
||||
adapter.startForTest();
|
||||
fail("Should have thrown LifecycleException");
|
||||
} catch (LifecycleException expected) {
|
||||
assertEquals("appContextLocation must be defined", expected.getMessage());
|
||||
}
|
||||
|
||||
adapter.setAppContextLocation("");
|
||||
|
||||
try {
|
||||
adapter.startForTest();
|
||||
fail("Should have thrown LifecycleException");
|
||||
} catch (LifecycleException expected) {
|
||||
assertEquals("appContextLocation must be defined", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testAdapterAbortsIfNoKeySpecified() throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
|
||||
adapter.setAppContextLocation("SOMETHING");
|
||||
|
||||
try {
|
||||
adapter.startForTest();
|
||||
fail("Should have thrown LifecycleException");
|
||||
} catch (LifecycleException expected) {
|
||||
assertEquals("key must be defined", expected.getMessage());
|
||||
}
|
||||
|
||||
adapter.setKey("");
|
||||
|
||||
try {
|
||||
adapter.startForTest();
|
||||
fail("Should have thrown LifecycleException");
|
||||
} catch (LifecycleException expected) {
|
||||
assertEquals("key must be defined", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testAdapterAbortsWithIncorrectApplicationContextLocation()
|
||||
throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
adapter.setAppContextLocation("SOME_INVALID_PATH");
|
||||
adapter.setKey("KEY");
|
||||
|
||||
try {
|
||||
adapter.startForTest();
|
||||
fail("Should have thrown LifecycleException");
|
||||
} catch (LifecycleException expected) {
|
||||
assertTrue(expected.getMessage().startsWith("appContextLocation does not seem to exist in"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testAdapterIdentifiesItself() throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
assertTrue(adapter.getName().lastIndexOf("CatalinaSpringUserRealm") != -1);
|
||||
}
|
||||
|
||||
public void testAdapterStartsUpSuccess() throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
public void testAuthenticateManyParamsReturnsNull() {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
assertEquals(null, adapter.authenticate(null, null, null, null, null, null, null, null));
|
||||
}
|
||||
|
||||
public void testAuthenticateX509ReturnsNull() {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
assertEquals(null, adapter.authenticate(null));
|
||||
}
|
||||
|
||||
public void testAuthenticationFailsForIncorrectPassword()
|
||||
throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
|
||||
assertEquals(null, adapter.authenticate("rod", "kangaroo"));
|
||||
}
|
||||
|
||||
public void testAuthenticationFailsForIncorrectUserName()
|
||||
throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
|
||||
assertEquals(null, adapter.authenticate("melissa", "koala"));
|
||||
}
|
||||
|
||||
public void testAuthenticationUsingByteArrayForCredentials()
|
||||
throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
|
||||
byte[] credentials = {'k', 'o', 'a', 'l', 'a'};
|
||||
Principal result = adapter.authenticate("rod", credentials);
|
||||
|
||||
if (!(result instanceof PrincipalSpringSecurityUserToken)) {
|
||||
fail("Should have returned PrincipalSpringSecurityUserToken");
|
||||
}
|
||||
|
||||
PrincipalSpringSecurityUserToken castResult = (PrincipalSpringSecurityUserToken) result;
|
||||
assertEquals("rod", castResult.getPrincipal());
|
||||
assertEquals("koala", castResult.getCredentials());
|
||||
assertEquals("ROLE_TELLER", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
|
||||
}
|
||||
|
||||
public void testAuthenticationUsingStringForCredentials()
|
||||
throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
|
||||
Principal result = adapter.authenticate("rod", "koala");
|
||||
|
||||
if (!(result instanceof PrincipalSpringSecurityUserToken)) {
|
||||
fail("Should have returned PrincipalSpringSecurityUserToken");
|
||||
}
|
||||
|
||||
PrincipalSpringSecurityUserToken castResult = (PrincipalSpringSecurityUserToken) result;
|
||||
assertEquals("rod", castResult.getPrincipal());
|
||||
assertEquals("koala", castResult.getCredentials());
|
||||
assertEquals("ROLE_TELLER", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
|
||||
}
|
||||
|
||||
public void testAuthenticationWithNullPasswordHandledGracefully()
|
||||
throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
|
||||
assertEquals(null, adapter.authenticate("rod", (String) null));
|
||||
}
|
||||
|
||||
public void testAuthenticationWithNullUserNameHandledGracefully()
|
||||
throws Exception {
|
||||
CatalinaSpringSecurityUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
|
||||
assertEquals(null, adapter.authenticate(null, "koala"));
|
||||
}
|
||||
|
||||
public void testGetPasswordReturnsNull() {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
assertEquals(null, adapter.getPassword(null));
|
||||
}
|
||||
|
||||
public void testGetPrincipalReturnsNull() {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
assertEquals(null, adapter.getPrincipal(null));
|
||||
}
|
||||
|
||||
public void testGetters() {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
adapter.setKey("KEY");
|
||||
assertEquals("KEY", adapter.getKey());
|
||||
adapter.setAppContextLocation("SOME_LOCATION");
|
||||
assertEquals("SOME_LOCATION", adapter.getAppContextLocation());
|
||||
}
|
||||
|
||||
public void testHasRoleWithANullPrincipalFails() {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
assertTrue(!adapter.hasRole(null, "ROLE_ONE"));
|
||||
}
|
||||
|
||||
public void testHasRoleWithAPrincipalTheAdapterDidNotCreateFails() {
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
assertTrue(!adapter.hasRole(new Principal() {
|
||||
public String getName() {
|
||||
return "MockPrincipal";
|
||||
}
|
||||
}, "ROLE_ONE"));
|
||||
}
|
||||
|
||||
public void testHasRoleWithPrincipalAcegiUserToken() {
|
||||
PrincipalSpringSecurityUserToken token = new PrincipalSpringSecurityUserToken("KEY", "Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO")},
|
||||
null);
|
||||
CatalinaSpringSecurityUserRealm adapter = new CatalinaSpringSecurityUserRealm();
|
||||
assertTrue(adapter.hasRole(token, "ROLE_ONE"));
|
||||
assertTrue(adapter.hasRole(token, "ROLE_TWO"));
|
||||
assertTrue(!adapter.hasRole(token, "ROLE_WE_DO_NOT_HAVE"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
target
|
||||
.settings
|
||||
.classpath
|
||||
.project
|
||||
.wtpmodules
|
||||
@@ -0,0 +1,26 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-adapters</artifactId>
|
||||
<version>2.0.5.CI-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-security-jboss</artifactId>
|
||||
<name>Spring Security - JBoss adapter</name>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>jboss</groupId>
|
||||
<artifactId>jbosssx</artifactId>
|
||||
<version>3.2.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
/* 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.adapters.jboss;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.context.HttpSessionContextIntegrationFilter;
|
||||
import org.springframework.security.context.SecurityContext;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Populates a {@link SecurityContext} from JBoss' <code>java:comp/env/security/subject</code>.
|
||||
* <p>This filter <b>never</b> preserves the <code>Authentication</code> on the <code>ContextHolder</code> -
|
||||
* it is replaced every request.</p>
|
||||
* <p>See {@link HttpSessionContextIntegrationFilter} for further information.</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class JbossIntegrationFilter implements Filter {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(JbossIntegrationFilter.class);
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* Does nothing. We use IoC container lifecycle services instead.
|
||||
*/
|
||||
public void destroy() {}
|
||||
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
Object principal = extractFromContainer(request);
|
||||
|
||||
if ((principal != null) && principal instanceof Authentication) {
|
||||
SecurityContextHolder.getContext().setAuthentication((Authentication) principal);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("ContextHolder updated with Authentication from container: '" + principal + "'");
|
||||
}
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("ContextHolder not set with new Authentication as Principal was: '" + principal + "'");
|
||||
}
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
private Object extractFromContainer(ServletRequest request) {
|
||||
Subject subject = null;
|
||||
|
||||
try {
|
||||
Context lc = this.getLookupContext();
|
||||
|
||||
if (lc == null) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Could not obtain a Context to perform lookup");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Object result = lc.lookup("java:comp/env/security/subject");
|
||||
|
||||
if (result instanceof Subject) {
|
||||
subject = (Subject) result;
|
||||
}
|
||||
} catch (NamingException ne) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Lookup on Subject failed " + ne.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if ((subject != null) && (subject.getPrincipals() != null)) {
|
||||
Iterator principals = subject.getPrincipals().iterator();
|
||||
|
||||
while (principals.hasNext()) {
|
||||
Principal p = (Principal) principals.next();
|
||||
|
||||
if (p instanceof Authentication) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provided so that unit tests can override.
|
||||
*
|
||||
* @return a <code>Context</code> that can be used for lookup
|
||||
*
|
||||
* @throws NamingException DOCUMENT ME!
|
||||
*/
|
||||
protected Context getLookupContext() throws NamingException {
|
||||
return new InitialContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing. We use IoC container lifecycle services instead.
|
||||
*
|
||||
* @param arg0 ignored
|
||||
*
|
||||
* @throws ServletException ignored
|
||||
*/
|
||||
public void init(FilterConfig arg0) throws ServletException {}
|
||||
}
|
||||
+302
@@ -0,0 +1,302 @@
|
||||
/* 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.adapters.jboss;
|
||||
|
||||
import org.springframework.security.AccountExpiredException;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthenticationException;
|
||||
import org.springframework.security.AuthenticationManager;
|
||||
import org.springframework.security.CredentialsExpiredException;
|
||||
|
||||
import org.springframework.security.adapters.PrincipalSpringSecurityUserToken;
|
||||
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
|
||||
import org.jboss.security.SimpleGroup;
|
||||
import org.jboss.security.SimplePrincipal;
|
||||
import org.jboss.security.auth.spi.AbstractServerLoginModule;
|
||||
|
||||
import org.springframework.beans.factory.access.BeanFactoryLocator;
|
||||
import org.springframework.beans.factory.access.BeanFactoryReference;
|
||||
import org.springframework.beans.factory.access.SingletonBeanFactoryLocator;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.security.acl.Group;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.NameCallback;
|
||||
import javax.security.auth.callback.PasswordCallback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import javax.security.auth.login.FailedLoginException;
|
||||
import javax.security.auth.login.LoginException;
|
||||
|
||||
|
||||
/**
|
||||
* Adapter to enable JBoss to authenticate via the Spring Security System for Spring.
|
||||
* <p>Returns a {@link PrincipalSpringSecurityUserToken} to JBoss' authentication system,
|
||||
* which is subsequently available from <code>java:comp/env/security/subject</code>.</p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Sergio Bern
|
||||
* @version $Id:JbossSpringSecurityLoginModule.java 2151 2007-09-22 11:54:13Z luke_t $
|
||||
*/
|
||||
public class JbossSpringSecurityLoginModule extends AbstractServerLoginModule {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private AuthenticationManager authenticationManager;
|
||||
private Principal identity;
|
||||
private String key;
|
||||
private char[] credential;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
protected Principal getIdentity() {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
protected Group[] getRoleSets() throws LoginException {
|
||||
SimpleGroup roles = new SimpleGroup("Roles");
|
||||
Group[] roleSets = {roles};
|
||||
|
||||
if (this.identity instanceof Authentication) {
|
||||
Authentication user = (Authentication) this.identity;
|
||||
|
||||
for (int i = 0; i < user.getAuthorities().length; i++) {
|
||||
roles.addMember(new SimplePrincipal(user.getAuthorities()[i].getAuthority()));
|
||||
}
|
||||
}
|
||||
|
||||
return roleSets;
|
||||
}
|
||||
|
||||
protected String[] getUsernameAndPassword() throws LoginException {
|
||||
String[] info = {null, null};
|
||||
|
||||
// prompt for a username and password
|
||||
if (callbackHandler == null) {
|
||||
throw new LoginException("Error: no CallbackHandler available " + "to collect authentication information");
|
||||
}
|
||||
|
||||
NameCallback nc = new NameCallback("User name: ", "guest");
|
||||
PasswordCallback pc = new PasswordCallback("Password: ", false);
|
||||
Callback[] callbacks = {nc, pc};
|
||||
String username = null;
|
||||
String password = null;
|
||||
|
||||
try {
|
||||
callbackHandler.handle(callbacks);
|
||||
username = nc.getName();
|
||||
|
||||
char[] tmpPassword = pc.getPassword();
|
||||
|
||||
if (tmpPassword != null) {
|
||||
credential = new char[tmpPassword.length];
|
||||
System.arraycopy(tmpPassword, 0, credential, 0, tmpPassword.length);
|
||||
pc.clearPassword();
|
||||
password = new String(credential);
|
||||
}
|
||||
} catch (java.io.IOException ioe) {
|
||||
throw new LoginException(ioe.toString());
|
||||
} catch (UnsupportedCallbackException uce) {
|
||||
throw new LoginException("CallbackHandler does not support: " + uce.getCallback());
|
||||
}
|
||||
|
||||
info[0] = username;
|
||||
info[1] = password;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
|
||||
super.initialize(subject, callbackHandler, sharedState, options);
|
||||
|
||||
if (super.log.isInfoEnabled()) {
|
||||
super.log.info("initializing jboss login module");
|
||||
}
|
||||
|
||||
this.key = (String) options.get("key");
|
||||
|
||||
if ((key == null) || "".equals(key)) {
|
||||
throw new IllegalArgumentException("key must be defined");
|
||||
}
|
||||
|
||||
String singletonId = (String) options.get("singletonId");
|
||||
|
||||
String appContextLocation = (String) options.get("appContextLocation");
|
||||
|
||||
if ((((singletonId == null) || "".equals(singletonId)) && (appContextLocation == null))
|
||||
|| "".equals(appContextLocation)) {
|
||||
throw new IllegalArgumentException("appContextLocation must be defined");
|
||||
}
|
||||
|
||||
String beanName = (String) options.get("authenticationManager");
|
||||
|
||||
// Attempt to find the appContextLocation only if no singletonId was defined
|
||||
if ((singletonId == null) || "".equals(singletonId)) {
|
||||
if (Thread.currentThread().getContextClassLoader().getResource(appContextLocation) == null) {
|
||||
if (super.log.isInfoEnabled()) {
|
||||
super.log.info("cannot locate " + appContextLocation);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Cannot locate " + appContextLocation);
|
||||
}
|
||||
}
|
||||
|
||||
ApplicationContext ctx = null;
|
||||
|
||||
if ((singletonId == null) || "".equals(singletonId)) {
|
||||
try {
|
||||
ctx = new ClassPathXmlApplicationContext(appContextLocation);
|
||||
} catch (Exception e) {
|
||||
if (super.log.isInfoEnabled()) {
|
||||
super.log.info("error loading spring context " + appContextLocation + " " + e);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("error loading spring context " + appContextLocation + " " + e);
|
||||
}
|
||||
} else {
|
||||
if (super.log.isInfoEnabled()) {
|
||||
super.log.debug("retrieving singleton instance " + singletonId);
|
||||
}
|
||||
|
||||
BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance();
|
||||
BeanFactoryReference bf = bfl.useBeanFactory(singletonId);
|
||||
ctx = (ApplicationContext) bf.getFactory();
|
||||
|
||||
if (ctx == null) {
|
||||
if (super.log.isInfoEnabled()) {
|
||||
super.log.info("singleton " + beanName + " does not exists");
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("singleton " + singletonId + " does not exists");
|
||||
}
|
||||
}
|
||||
|
||||
if ((beanName == null) || "".equals(beanName)) {
|
||||
Map beans = null;
|
||||
|
||||
try {
|
||||
beans = ctx.getBeansOfType(AuthenticationManager.class, true, true);
|
||||
} catch (Exception e) {
|
||||
if (super.log.isInfoEnabled()) {
|
||||
super.log.info("exception in getBeansOfType " + e);
|
||||
}
|
||||
|
||||
throw new IllegalStateException("spring error in get beans by class");
|
||||
}
|
||||
|
||||
if (beans.size() == 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Bean context must contain at least one bean of type AuthenticationManager");
|
||||
}
|
||||
|
||||
beanName = (String) beans.keySet().iterator().next();
|
||||
}
|
||||
|
||||
authenticationManager = (AuthenticationManager) ctx.getBean(beanName);
|
||||
|
||||
if (super.log.isInfoEnabled()) {
|
||||
super.log.info("Successfully started JbossSpringLoginModule");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean login() throws LoginException {
|
||||
super.loginOk = false;
|
||||
|
||||
String[] info = getUsernameAndPassword();
|
||||
String username = info[0];
|
||||
String password = info[1];
|
||||
|
||||
if ((username == null) && (password == null)) {
|
||||
identity = null;
|
||||
super.log.trace("Authenticating as unauthenticatedIdentity=" + identity);
|
||||
}
|
||||
|
||||
if (username == null) {
|
||||
username = "";
|
||||
}
|
||||
|
||||
if (password == null) {
|
||||
password = "";
|
||||
}
|
||||
|
||||
if (super.log.isDebugEnabled()) {
|
||||
super.log.debug("checking identity");
|
||||
}
|
||||
|
||||
if (identity == null) {
|
||||
super.log.debug("creating usernamepassword token");
|
||||
|
||||
Authentication request = new UsernamePasswordAuthenticationToken(username, password);
|
||||
Authentication response = null;
|
||||
|
||||
try {
|
||||
if (super.log.isDebugEnabled()) {
|
||||
super.log.debug("attempting authentication");
|
||||
}
|
||||
|
||||
response = authenticationManager.authenticate(request);
|
||||
|
||||
if (super.log.isDebugEnabled()) {
|
||||
super.log.debug("authentication succeded");
|
||||
}
|
||||
} catch (CredentialsExpiredException cee) {
|
||||
if (super.log.isDebugEnabled()) {
|
||||
super.log.debug("Credential has expired");
|
||||
}
|
||||
|
||||
throw new javax.security.auth.login.CredentialExpiredException(
|
||||
"The credential used to identify the user has expired");
|
||||
} catch (AccountExpiredException cee) {
|
||||
if (super.log.isDebugEnabled()) {
|
||||
super.log.debug("Account has expired, throwing jaas exception");
|
||||
}
|
||||
|
||||
throw new javax.security.auth.login.AccountExpiredException(
|
||||
"The account specified in login has expired");
|
||||
} catch (AuthenticationException failed) {
|
||||
if (super.log.isDebugEnabled()) {
|
||||
super.log.debug("Bad password for username=" + username);
|
||||
}
|
||||
|
||||
throw new FailedLoginException("Password Incorrect/Password Required");
|
||||
}
|
||||
|
||||
super.log.debug("user is logged. redirecting to jaas classes");
|
||||
|
||||
identity = new PrincipalSpringSecurityUserToken(this.key, response.getName(), response.getCredentials().toString(),
|
||||
response.getAuthorities(), response.getPrincipal());
|
||||
}
|
||||
|
||||
if (getUseFirstPass() == true) {
|
||||
// Add the username and password to the shared state map
|
||||
sharedState.put("javax.security.auth.login.name", username);
|
||||
sharedState.put("javax.security.auth.login.password", credential);
|
||||
}
|
||||
|
||||
super.loginOk = true;
|
||||
super.log.trace("User '" + identity + "' authenticated, loginOk=" + loginOk);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
Adapter to JBoss.
|
||||
<p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+184
@@ -0,0 +1,184 @@
|
||||
/* 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.adapters.jboss;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
|
||||
import org.springframework.security.adapters.PrincipalSpringSecurityUserToken;
|
||||
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.context.SecurityContextImpl;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.naming.Context;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link JbossIntegrationFilter}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id:JbossIntegrationFilterTests.java 2151 2007-09-22 11:54:13Z luke_t $
|
||||
*/
|
||||
public class JbossIntegrationFilterTests extends TestCase {
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public JbossIntegrationFilterTests() {
|
||||
super();
|
||||
}
|
||||
|
||||
public JbossIntegrationFilterTests(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
private void executeFilterInContainerSimulator(FilterConfig filterConfig, Filter filter, ServletRequest request,
|
||||
ServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
filter.init(filterConfig);
|
||||
filter.doFilter(request, response, filterChain);
|
||||
filter.destroy();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(JbossIntegrationFilterTests.class);
|
||||
}
|
||||
|
||||
private Subject makeIntoSubject(Principal principal) {
|
||||
Set principals = new HashSet();
|
||||
principals.add(principal);
|
||||
|
||||
return new Subject(false, principals, new HashSet(), new HashSet());
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
SecurityContextHolder.setContext(new SecurityContextImpl());
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
SecurityContextHolder.setContext(new SecurityContextImpl());
|
||||
}
|
||||
|
||||
public void testCorrectOperation() throws Exception {
|
||||
PrincipalSpringSecurityUserToken principal = new PrincipalSpringSecurityUserToken("key", "someone", "password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_ROLE")}, null);
|
||||
|
||||
JbossIntegrationFilter filter = new MockJbossIntegrationFilter(new MockInitialContext(makeIntoSubject(principal)));
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockFilterChain chain = new MockFilterChain();
|
||||
|
||||
filter.doFilter(request, null, chain);
|
||||
|
||||
assertEquals(principal, SecurityContextHolder.getContext().getAuthentication());
|
||||
SecurityContextHolder.setContext(new SecurityContextImpl());
|
||||
}
|
||||
|
||||
public void testReturnsNullIfContextReturnsSomethingOtherThanASubject()
|
||||
throws Exception {
|
||||
JbossIntegrationFilter filter = new MockJbossIntegrationFilter(new MockInitialContext("THIS_IS_NOT_A_SUBJECT"));
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockFilterChain chain = new MockFilterChain();
|
||||
|
||||
filter.doFilter(request, null, chain);
|
||||
assertNull(SecurityContextHolder.getContext().getAuthentication());
|
||||
}
|
||||
|
||||
public void testReturnsNullIfInitialContextHasNullPrincipal()
|
||||
throws Exception {
|
||||
JbossIntegrationFilter filter = new MockJbossIntegrationFilter(new MockInitialContext(makeIntoSubject(null)));
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockFilterChain chain = new MockFilterChain();
|
||||
|
||||
filter.doFilter(request, null, chain);
|
||||
assertNull(SecurityContextHolder.getContext().getAuthentication());
|
||||
}
|
||||
|
||||
public void testReturnsNullIfInitialContextHasNullSubject()
|
||||
throws Exception {
|
||||
JbossIntegrationFilter filter = new MockJbossIntegrationFilter(new MockInitialContext(null));
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockFilterChain chain = new MockFilterChain();
|
||||
|
||||
filter.doFilter(request, null, chain);
|
||||
assertNull(SecurityContextHolder.getContext().getAuthentication());
|
||||
}
|
||||
|
||||
public void testReturnsNullIfInitialContextIsNull()
|
||||
throws Exception {
|
||||
JbossIntegrationFilter filter = new MockJbossIntegrationFilter(null);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockFilterChain chain = new MockFilterChain();
|
||||
|
||||
filter.doFilter(request, null, chain);
|
||||
assertNull(SecurityContextHolder.getContext().getAuthentication());
|
||||
}
|
||||
|
||||
public void testReturnsNullIfPrincipalNotAnAuthenticationImplementation()
|
||||
throws Exception {
|
||||
JbossIntegrationFilter filter = new MockJbossIntegrationFilter(new MockInitialContext(makeIntoSubject(
|
||||
new Principal() {
|
||||
public String getName() {
|
||||
return "MockPrincipal";
|
||||
}
|
||||
})));
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockFilterChain chain = new MockFilterChain();
|
||||
|
||||
filter.doFilter(request, null, chain);
|
||||
assertNull(SecurityContextHolder.getContext().getAuthentication());
|
||||
}
|
||||
|
||||
public void testTestingObjectReturnsInitialContext()
|
||||
throws Exception {
|
||||
JbossIntegrationFilter filter = new JbossIntegrationFilter();
|
||||
assertTrue(filter.getLookupContext() instanceof Context);
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class MockFilterChain implements FilterChain {
|
||||
public void doFilter(ServletRequest arg0, ServletResponse arg1)
|
||||
throws IOException, ServletException {}
|
||||
}
|
||||
}
|
||||
+356
@@ -0,0 +1,356 @@
|
||||
/* 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.adapters.jboss;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.security.adapters.PrincipalSpringSecurityUserToken;
|
||||
|
||||
import org.jboss.security.SimplePrincipal;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.security.acl.Group;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.NameCallback;
|
||||
import javax.security.auth.callback.PasswordCallback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
import javax.security.auth.login.FailedLoginException;
|
||||
import javax.security.auth.login.LoginException;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link JbossSpringSecurityLoginModule}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id:JbossSpringSecurityLoginModuleTests.java 2151 2007-09-22 11:54:13Z luke_t $
|
||||
*/
|
||||
public class JbossSpringSecurityLoginModuleTests extends TestCase {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final String ADAPTER_KEY = "my_key";
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public JbossSpringSecurityLoginModuleTests() {
|
||||
super();
|
||||
}
|
||||
|
||||
public JbossSpringSecurityLoginModuleTests(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(JbossSpringSecurityLoginModuleTests.class);
|
||||
}
|
||||
|
||||
public final void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
public void testAdapterAbortsIfAppContextDoesNotContainAnAuthenticationBean()
|
||||
throws Exception {
|
||||
JbossSpringSecurityLoginModule adapter = new JbossSpringSecurityLoginModule();
|
||||
Properties props = new Properties();
|
||||
props.put("key", ADAPTER_KEY);
|
||||
props.put("appContextLocation", "org/springframework/security/adapters/adaptertest-invalid.xml");
|
||||
|
||||
try {
|
||||
adapter.initialize(null, null, null, props);
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testAdapterAbortsIfNoAppContextSpecified()
|
||||
throws Exception {
|
||||
JbossSpringSecurityLoginModule adapter = new JbossSpringSecurityLoginModule();
|
||||
|
||||
Properties props = new Properties();
|
||||
props.put("key", ADAPTER_KEY);
|
||||
|
||||
try {
|
||||
adapter.initialize(null, null, null, props);
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertEquals("appContextLocation must be defined", expected.getMessage());
|
||||
}
|
||||
|
||||
props = new Properties();
|
||||
props.put("key", ADAPTER_KEY);
|
||||
props.put("appContextLocation", "");
|
||||
|
||||
try {
|
||||
adapter.initialize(null, null, null, props);
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertEquals("appContextLocation must be defined", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testAdapterAbortsIfNoKeySpecified() throws Exception {
|
||||
JbossSpringSecurityLoginModule adapter = new JbossSpringSecurityLoginModule();
|
||||
|
||||
Properties props = new Properties();
|
||||
props.put("appContextLocation", "org/springframework/security/adapters/adaptertest-valid.xml");
|
||||
|
||||
try {
|
||||
adapter.initialize(null, null, null, props);
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertEquals("key must be defined", expected.getMessage());
|
||||
}
|
||||
|
||||
props = new Properties();
|
||||
props.put("key", "");
|
||||
props.put("appContextLocation", "org/springframework/security/adapters/adaptertest-valid.xml");
|
||||
|
||||
try {
|
||||
adapter.initialize(null, null, null, props);
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertEquals("key must be defined", expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testAdapterAbortsWithIncorrectApplicationContextLocation()
|
||||
throws Exception {
|
||||
JbossSpringSecurityLoginModule adapter = new JbossSpringSecurityLoginModule();
|
||||
|
||||
Properties props = new Properties();
|
||||
props.put("key", ADAPTER_KEY);
|
||||
props.put("appContextLocation", "INVALID_PATH");
|
||||
|
||||
try {
|
||||
adapter.initialize(null, null, null, props);
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue("Cannot locate INVALID_PATH".equals(expected.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
public void testAdapterFailsToAuthenticateIfNoCallbackHandlerAvailable()
|
||||
throws Exception {
|
||||
JbossSpringSecurityLoginModule adapter = new JbossSpringSecurityLoginModule();
|
||||
Properties props = new Properties();
|
||||
props.put("key", ADAPTER_KEY);
|
||||
props.put("appContextLocation", "org/springframework/security/adapters/adaptertest-valid.xml");
|
||||
|
||||
Subject subject = new Subject();
|
||||
|
||||
adapter.initialize(subject, null, null, props);
|
||||
|
||||
try {
|
||||
adapter.login();
|
||||
} catch (LoginException loginException) {
|
||||
assertEquals("Error: no CallbackHandler available to collect authentication information",
|
||||
loginException.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testAdapterStartsUpSuccess() throws Exception {
|
||||
JbossSpringSecurityLoginModule adapter = new JbossSpringSecurityLoginModule();
|
||||
Properties props = new Properties();
|
||||
props.put("key", ADAPTER_KEY);
|
||||
props.put("appContextLocation", "org/springframework/security/adapters/adaptertest-valid.xml");
|
||||
adapter.initialize(null, null, null, props);
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
public void testAuthenticationFailsForIncorrectPassword()
|
||||
throws Exception {
|
||||
JbossSpringSecurityLoginModule adapter = new JbossSpringSecurityLoginModule();
|
||||
Properties props = new Properties();
|
||||
props.put("key", ADAPTER_KEY);
|
||||
props.put("appContextLocation", "org/springframework/security/adapters/adaptertest-valid.xml");
|
||||
|
||||
Subject subject = new Subject();
|
||||
CallbackHandler callback = new MockCallbackHandler("rod", "kangaroo");
|
||||
|
||||
adapter.initialize(subject, callback, null, props);
|
||||
|
||||
try {
|
||||
adapter.login();
|
||||
fail("Should have thrown FailedLoginException");
|
||||
} catch (FailedLoginException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testAuthenticationFailsForIncorrectUserName()
|
||||
throws Exception {
|
||||
JbossSpringSecurityLoginModule adapter = new JbossSpringSecurityLoginModule();
|
||||
Properties props = new Properties();
|
||||
props.put("key", ADAPTER_KEY);
|
||||
props.put("appContextLocation", "org/springframework/security/adapters/adaptertest-valid.xml");
|
||||
|
||||
Subject subject = new Subject();
|
||||
CallbackHandler callback = new MockCallbackHandler("melissa", "koala");
|
||||
|
||||
adapter.initialize(subject, callback, null, props);
|
||||
|
||||
try {
|
||||
adapter.login();
|
||||
fail("Should have thrown FailedLoginException");
|
||||
} catch (FailedLoginException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testAuthenticationSuccess() throws Exception {
|
||||
JbossSpringSecurityLoginModule adapter = new JbossSpringSecurityLoginModule();
|
||||
Properties props = new Properties();
|
||||
props.put("key", ADAPTER_KEY);
|
||||
props.put("appContextLocation", "org/springframework/security/adapters/adaptertest-valid.xml");
|
||||
|
||||
Subject subject = new Subject();
|
||||
CallbackHandler callback = new MockCallbackHandler("rod", "koala");
|
||||
|
||||
adapter.initialize(subject, callback, null, props);
|
||||
assertTrue(adapter.login());
|
||||
|
||||
Principal result = adapter.getIdentity();
|
||||
|
||||
if (!(result instanceof PrincipalSpringSecurityUserToken)) {
|
||||
fail("Should have returned PrincipalSpringSecurityUserToken");
|
||||
}
|
||||
|
||||
PrincipalSpringSecurityUserToken castResult = (PrincipalSpringSecurityUserToken) result;
|
||||
assertEquals("rod", castResult.getPrincipal());
|
||||
assertEquals("koala", castResult.getCredentials());
|
||||
assertEquals("ROLE_TELLER", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
|
||||
}
|
||||
|
||||
public void testAuthenticationWithNullPasswordHandledGracefully()
|
||||
throws Exception {
|
||||
JbossSpringSecurityLoginModule adapter = new JbossSpringSecurityLoginModule();
|
||||
Properties props = new Properties();
|
||||
props.put("key", ADAPTER_KEY);
|
||||
props.put("appContextLocation", "org/springframework/security/adapters/adaptertest-valid.xml");
|
||||
|
||||
Subject subject = new Subject();
|
||||
CallbackHandler callback = new MockCallbackHandler("rod", null);
|
||||
|
||||
adapter.initialize(subject, callback, null, props);
|
||||
|
||||
try {
|
||||
adapter.login();
|
||||
fail("Should have thrown FailedLoginException");
|
||||
} catch (FailedLoginException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testAuthenticationWithNullUserNameAndNullPasswordHandledGracefully()
|
||||
throws Exception {
|
||||
JbossSpringSecurityLoginModule adapter = new JbossSpringSecurityLoginModule();
|
||||
Properties props = new Properties();
|
||||
props.put("key", ADAPTER_KEY);
|
||||
props.put("appContextLocation", "org/springframework/security/adapters/adaptertest-valid.xml");
|
||||
|
||||
Subject subject = new Subject();
|
||||
CallbackHandler callback = new MockCallbackHandler(null, null);
|
||||
|
||||
adapter.initialize(subject, callback, null, props);
|
||||
|
||||
try {
|
||||
adapter.login();
|
||||
fail("Should have thrown FailedLoginException");
|
||||
} catch (FailedLoginException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testAuthenticationWithNullUserNameHandledGracefully()
|
||||
throws Exception {
|
||||
JbossSpringSecurityLoginModule adapter = new JbossSpringSecurityLoginModule();
|
||||
Properties props = new Properties();
|
||||
props.put("key", ADAPTER_KEY);
|
||||
props.put("appContextLocation", "org/springframework/security/adapters/adaptertest-valid.xml");
|
||||
|
||||
Subject subject = new Subject();
|
||||
CallbackHandler callback = new MockCallbackHandler(null, "kangaroo");
|
||||
|
||||
adapter.initialize(subject, callback, null, props);
|
||||
|
||||
try {
|
||||
adapter.login();
|
||||
fail("Should have thrown FailedLoginException");
|
||||
} catch (FailedLoginException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetRoleSets() throws Exception {
|
||||
JbossSpringSecurityLoginModule adapter = new JbossSpringSecurityLoginModule();
|
||||
Properties props = new Properties();
|
||||
props.put("key", ADAPTER_KEY);
|
||||
props.put("appContextLocation", "org/springframework/security/adapters/adaptertest-valid.xml");
|
||||
|
||||
Subject subject = new Subject();
|
||||
CallbackHandler callback = new MockCallbackHandler("rod", "koala");
|
||||
|
||||
adapter.initialize(subject, callback, null, props);
|
||||
assertTrue(adapter.login());
|
||||
|
||||
Group[] result = adapter.getRoleSets();
|
||||
// Expect Roles group.
|
||||
assertEquals(1, result.length);
|
||||
|
||||
Group roles = result[0];
|
||||
assertTrue(roles.isMember(new SimplePrincipal("ROLE_TELLER")));
|
||||
assertTrue(roles.isMember(new SimplePrincipal("ROLE_SUPERVISOR")));
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
private class MockCallbackHandler implements CallbackHandler {
|
||||
private String password;
|
||||
private String username;
|
||||
|
||||
public MockCallbackHandler(String username, String password) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
|
||||
for (int i = 0; i < callbacks.length; i++) {
|
||||
if (callbacks[i] instanceof NameCallback) {
|
||||
((NameCallback) callbacks[i]).setName(username);
|
||||
} else if (callbacks[i] instanceof PasswordCallback) {
|
||||
if (this.password == null) {
|
||||
((PasswordCallback) callbacks[i]).setPassword(null);
|
||||
} else {
|
||||
((PasswordCallback) callbacks[i]).setPassword(password.toCharArray());
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedCallbackException(callbacks[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user