1
0
mirror of synced 2026-07-13 22:55:10 +00:00

Compare commits

..

43 Commits

Author SHA1 Message Date
Luke Taylor 55fbfc5285 Updated site index page 2008-04-15 15:53:38 +00:00
Luke Taylor b75ea4e622 [maven-release-plugin] copy for tag acegi-security-parent-1.0.7 2008-04-15 11:38:16 +00:00
Luke Taylor f626d5ec47 SEC-678: Merged changes from trunk. 2008-02-18 20:44:09 +00:00
Luke Taylor 1b07b5e616 SEC-537: Merged changes from trunk. 2008-02-18 12:21:29 +00:00
Luke Taylor 22aaf34499 SEC-577: Correct javadocs for switch user 2008-02-15 14:35:16 +00:00
Luke Taylor 62093067cb SEC-581: Copy authentication details to CAS result token 2008-02-15 14:03:52 +00:00
Ben Alex be3d309905 SEC-656: Provide ability to dependency inject additional exception to event mappings, rather than require subclassing. 2008-02-15 11:56:36 +00:00
Luke Taylor 065e2b6fa2 SEC-575: Added getter/setter for LdapUserDetailsMapper 2008-02-14 18:58:08 +00:00
Luke Taylor b253510127 SEC-418: Applied patch from issue. 2008-01-28 19:24:45 +00:00
Luke Taylor e41860d944 [maven-release-plugin] prepare for next development iteration 2007-12-24 17:13:29 +00:00
Luke Taylor e9b5ada0c4 [maven-release-plugin] prepare release release_1_0_6 2007-12-24 17:12:43 +00:00
Luke Taylor 0a7d6225f7 Corrected tagBase url 2007-12-24 17:08:52 +00:00
Luke Taylor 75360d1358 Corrected tagBase url 2007-12-24 17:06:50 +00:00
Luke Taylor a84b405744 [maven-release-plugin] rollback the release of release_1_0_6 2007-12-24 16:54:36 +00:00
Luke Taylor 4c8f61ec90 [maven-release-plugin] prepare release release_1_0_6 2007-12-24 16:41:24 +00:00
Luke Taylor c2a13b0aa8 [maven-release-plugin] rollback the release of release_1_0_6 2007-12-24 16:32:46 +00:00
Luke Taylor ad45967cef [maven-release-plugin] prepare release release_1_0_6 2007-12-24 16:26:44 +00:00
Luke Taylor bdd78ced7f Corrected scm element 2007-12-24 16:15:11 +00:00
Luke Taylor 9174fb7746 Removed scm element from core and core-tiger 2007-12-24 16:10:34 +00:00
Luke Taylor b5ac6e42e3 Reinstated version as 1.0.6-SNAPSHOT after mvn release plugin failure 2007-12-24 16:07:24 +00:00
Luke Taylor e3247231d7 [maven-release-plugin] prepare release release_1_0_6 2007-12-24 16:00:00 +00:00
Luke Taylor ab022a5ed3 testing svn commit 2007-12-24 15:56:53 +00:00
Luke Taylor 18d8084744 Fix jetty plugin version at 6.1.6. 2007-12-24 14:51:50 +00:00
Luke Taylor 1216673deb Fix jetty plugin version at 6.1.6. 2007-12-24 14:48:45 +00:00
Luke Taylor 8e6e373a3b Removed unused import. 2007-12-07 16:20:31 +00:00
Luke Taylor 2b0ee23396 SEC-618: Move copyDetails method into ProviderManager and call it before checking with ConcurrentSessionController. 2007-12-07 16:17:59 +00:00
Luke Taylor 89cde2507d SEC-594: Set password on UserDetails object returned by BindAuthenticator. 2007-12-07 16:04:43 +00:00
Luke Taylor ac0e308354 Updated spring and acegi version numbers in petclinic tutorial file. 2007-12-03 23:15:29 +00:00
Ben Alex 724b9e23ba Remove OrderedUtils (was used for old namespace testing). 2007-12-03 05:05:30 +00:00
Ben Alex 99c5479f9a SEC-584: Require user to explicitly set SessionRegistry, so the implementation can benefit from application context services. 2007-12-02 03:00:26 +00:00
Ben Alex c3dc3a3a4f SEC-610: Reauthenticate even if AnonymousAuthenticationToken is present. 2007-12-02 02:15:18 +00:00
Ben Alex 859ce607cd Now using mvn eclipse:eclipse instead; do not check these back in. 2007-12-02 00:47:38 +00:00
Ben Alex d6fd9980bd Remove configuration from sandbox; this support exists in 2.0 trunk. 2007-12-01 23:52:52 +00:00
Luke Taylor 831981ac69 Changed forum description. 2007-11-20 16:50:12 +00:00
Scott Battaglia 7b981d3e84 SEC-592
implemented NullStatelessTicketCache and test cases and made it the default for CasAuthenticationProvider.
2007-11-07 21:55:59 +00:00
Luke Taylor 38a0bf7ca4 SEC-564: Documented checkout of 1.0.x branch and trunk separately. 2007-11-07 00:24:02 +00:00
Luke Taylor e243855822 SEC-557: Reinstated default AccessDeniedHandler (AccessDeniedHandlerImpl) which had been removed by mistake. 2007-09-19 16:41:06 +00:00
Luke Taylor e6e461d9a0 SEC-549: Merged fix from trunk (trim space from username). 2007-09-14 14:32:19 +00:00
Luke Taylor 0ff8662f12 SEC-556: Removed namespace meta-inf file from 1.0 branch. 2007-09-12 21:37:07 +00:00
Luke Taylor 0878d7d563 Changed release notes to include deployment in tomcat *and* Jetty (after jstl issues with tutorial). 2007-09-12 21:19:02 +00:00
Luke Taylor ae4b5907b9 Merged website style changes from trunk. 2007-09-12 21:12:29 +00:00
Luke Taylor 5da9a0c0c0 Removed unnecessary repository declarations. 2007-09-12 21:10:29 +00:00
Luke Taylor 95d5c61115 SEC-554: Added jstl jars to tutorial pom. 2007-09-12 21:04:17 +00:00
1877 changed files with 75710 additions and 92061 deletions
+7
View File
@@ -0,0 +1,7 @@
dist
target
build.properties
*.log
.clover
*.keystore
server-work
-11
View File
@@ -1,11 +0,0 @@
target/
.classpath
.project
.settings/
build/
*.log
*.log.1
.DS_Store
*.iml
.gradle/
gradle.properties
+57
View File
@@ -0,0 +1,57 @@
#Mon Nov 07 22:01:53 EST 2005
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.5
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.autoboxing=warning
org.eclipse.jdt.core.compiler.problem.deprecation=ignore
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=ignore
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
org.eclipse.jdt.core.compiler.problem.unusedLocal=ignore
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=ignore
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.source=1.5
+3
View File
@@ -0,0 +1,3 @@
#Mon Nov 07 21:58:48 EST 2005
eclipse.preferences.version=1
internal.default.compliance=default
+205
View File
@@ -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>
-14
View File
@@ -1,14 +0,0 @@
// Acl Module build file
dependencies {
compile project(':spring-security-core'),
"net.sf.ehcache:ehcache:$ehcacheVersion",
"org.springframework:spring-aop:$springVersion",
"org.springframework:spring-context:$springVersion",
"org.springframework:spring-tx:$springVersion",
"org.springframework:spring-jdbc:$springVersion"
testCompile "org.springframework:spring-beans:$springVersion",
"org.springframework:spring-context-support:$springVersion",
"org.springframework:spring-test:$springVersion"
}
-68
View File
@@ -1,68 +0,0 @@
<?xml version="1.0"?>
<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">
<parent>
<artifactId>spring-security-parent</artifactId>
<groupId>org.springframework.security</groupId>
<version>3.0.3.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-acl</artifactId>
<name>Spring Security - ACL module</name>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<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>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>hsqldb</groupId>
<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>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -1,243 +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;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
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;
/**
* <p>
* Given a domain object instance passed as a method argument, ensures the principal has appropriate permission
* as indicated by the {@link AclService}.
* <p>
* The <tt>AclService</tt> is used to retrieve the access control list (ACL) permissions associated with a
* domain object instance for the current <tt>Authentication</tt> object.
* <p>
* 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
* 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.
* <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>:
* <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>
* <li>Process domain object class <code>BankAccount</code>, configuration attribute
* <code>VOTE_ACL_BANK_ACCOUNT_WRITE</code>, require permission list <code>BasePermission.WRITE</code> and
* <code>BasePermission.CREATE</code> (allowing the principal to have <b>either</b> of these two permissions)</li>
* <li>Process domain object class <code>Customer</code>, configuration attribute
* <code>VOTE_ACL_CUSTOMER_READ</code>, require permission <code>BasePermission.READ</code></li>
* <li>Process domain object class <code>Customer</code>, configuration attribute
* <code>VOTE_ACL_CUSTOMER_WRITE</code>, require permission list <code>BasePermission.WRITE</code> and
* <code>BasePermission.CREATE</code></li>
* </ul>
* Alternatively, you could have used a common superclass or interface for the {@link #processDomainObjectClass}
* if both <code>BankAccount</code> and <code>Customer</code> had common parents.</p>
* <p>If the principal does not have sufficient permissions, the voter will vote to deny access.</p>
* <p>All comparisons and prefixes are case sensitive.</p>
*
* @author Ben Alex
*/
public class AclEntryVoter extends AbstractAclVoter {
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(AclEntryVoter.class);
//~ Instance fields ================================================================================================
private AclService aclService;
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
private String internalMethod;
private String processConfigAttribute;
private List<Permission> requirePermission;
//~ Constructors ===================================================================================================
public AclEntryVoter(AclService aclService, String processConfigAttribute, Permission[] requirePermission) {
Assert.notNull(processConfigAttribute, "A processConfigAttribute is mandatory");
Assert.notNull(aclService, "An AclService is mandatory");
if ((requirePermission == null) || (requirePermission.length == 0)) {
throw new IllegalArgumentException("One or more requirePermission entries is mandatory");
}
this.aclService = aclService;
this.processConfigAttribute = processConfigAttribute;
this.requirePermission = Arrays.asList(requirePermission);
}
//~ Methods ========================================================================================================
/**
* Optionally specifies a method of the domain object that will be used to obtain a contained domain
* object. That contained domain object will be used for the ACL evaluation. This is useful if a domain object
* contains a parent that an ACL evaluation should be targeted for, instead of the child domain object (which
* perhaps is being created and as such does not yet have any ACL permissions)
*
* @return <code>null</code> to use the domain object, or the name of a method (that requires no arguments) that
* should be invoked to obtain an <code>Object</code> which will be the domain object used for ACL
* evaluation
*/
protected String getInternalMethod() {
return internalMethod;
}
public void setInternalMethod(String internalMethod) {
this.internalMethod = internalMethod;
}
protected String getProcessConfigAttribute() {
return processConfigAttribute;
}
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
Assert.notNull(objectIdentityRetrievalStrategy, "ObjectIdentityRetrievalStrategy required");
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
public boolean supports(ConfigAttribute attribute) {
if ((attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute())) {
return true;
} else {
return false;
}
}
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
for(ConfigAttribute attr : attributes) {
if (!this.supports(attr)) {
continue;
}
// Need to make an access decision on this invocation
// Attempt to locate the domain object instance to process
Object domainObject = getDomainObjectInstance(object);
// If domain object is null, vote to abstain
if (domainObject == null) {
if (logger.isDebugEnabled()) {
logger.debug("Voting to abstain - domainObject is null");
}
return ACCESS_ABSTAIN;
}
// Evaluate if we are required to use an inner domain object
if (StringUtils.hasText(internalMethod)) {
try {
Class<?> clazz = domainObject.getClass();
Method method = clazz.getMethod(internalMethod, new Class[0]);
domainObject = method.invoke(domainObject, new Object[0]);
} catch (NoSuchMethodException nsme) {
throw new AuthorizationServiceException("Object of class '" + domainObject.getClass()
+ "' does not provide the requested internalMethod: " + internalMethod);
} catch (IllegalAccessException iae) {
logger.debug("IllegalAccessException", iae);
throw new AuthorizationServiceException("Problem invoking internalMethod: " + internalMethod
+ " for object: " + domainObject);
} catch (InvocationTargetException ite) {
logger.debug("InvocationTargetException", ite);
throw new AuthorizationServiceException("Problem invoking internalMethod: " + internalMethod
+ " for object: " + domainObject);
}
}
// Obtain the OID applicable to the domain object
ObjectIdentity objectIdentity = objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
// Obtain the SIDs applicable to the principal
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
Acl acl;
try {
// Lookup only ACLs for SIDs we're interested in
acl = aclService.readAclById(objectIdentity, sids);
} catch (NotFoundException nfe) {
if (logger.isDebugEnabled()) {
logger.debug("Voting to deny access - no ACLs apply for this principal");
}
return ACCESS_DENIED;
}
try {
if (acl.isGranted(requirePermission, sids, false)) {
if (logger.isDebugEnabled()) {
logger.debug("Voting to grant access");
}
return ACCESS_GRANTED;
} else {
if (logger.isDebugEnabled()) {
logger.debug(
"Voting to deny access - ACLs returned, but insufficient permissions for this principal");
}
return ACCESS_DENIED;
}
} catch (NotFoundException nfe) {
if (logger.isDebugEnabled()) {
logger.debug("Voting to deny access - no ACLs apply for this principal");
}
return ACCESS_DENIED;
}
}
// No configuration attribute matched, so abstain
return ACCESS_ABSTAIN;
}
}
@@ -1,145 +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
* @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;
}
}
@@ -1,123 +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.afterinvocation;
import java.util.Collection;
import java.util.List;
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;
/**
* <p>
* Given a <code>Collection</code> of domain object instances returned from a secure object invocation, remove
* any <code>Collection</code> elements the principal does not have appropriate permission to access as defined by the
* {@link AclService}.
* <p>
* The <code>AclService</code> is used to retrieve the access control list (ACL) permissions associated with
* each <code>Collection</code> domain object instance element for the current <code>Authentication</code> object.
* <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.model.Acl#isGranted(List, List, boolean) Acl.isGranted()}
* 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
* <code>Collection</code>.
* <p>
* Often users will setup a <code>BasicAclEntryAfterInvocationProvider</code> with a {@link
* #processConfigAttribute} of <code>AFTER_ACL_COLLECTION_READ</code> and a {@link #requirePermission} of
* <code>BasePermission.READ</code>. These are also the defaults.
* <p>
* If the provided <code>returnObject</code> is <code>null</code>, a <code>null</code><code>Collection</code>
* will be returned. If the provided <code>returnObject</code> is not a <code>Collection</code>, an {@link
* AuthorizationServiceException} will be thrown.
* <p>
* All comparisons and prefixes are case sensitive.
*
* @author Ben Alex
* @author Paulo Neves
*/
public class AclEntryAfterInvocationCollectionFilteringProvider extends AbstractAclProvider {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationCollectionFilteringProvider.class);
//~ Constructors ===================================================================================================
public AclEntryAfterInvocationCollectionFilteringProvider(AclService aclService, List<Permission> requirePermission) {
super(aclService, "AFTER_ACL_COLLECTION_READ", requirePermission);
}
//~ Methods ========================================================================================================
@SuppressWarnings("unchecked")
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
Object returnedObject) throws AccessDeniedException {
if (returnedObject == null) {
if (logger.isDebugEnabled()) {
logger.debug("Return object is null, skipping");
}
return null;
}
for (ConfigAttribute attr : config) {
if (!this.supports(attr)) {
continue;
}
// Need to process the Collection for this invocation
Filterer filterer;
if (returnedObject instanceof Collection) {
filterer = new CollectionFilterer((Collection) returnedObject);
} else if (returnedObject.getClass().isArray()) {
filterer = new ArrayFilterer((Object[]) returnedObject);
} else {
throw new AuthorizationServiceException("A Collection or an array (or null) was required as the "
+ "returnedObject, but the returnedObject was: " + returnedObject);
}
// Locate unauthorised Collection elements
for (Object domainObject : filterer) {
// Ignore nulls or entries which aren't instances of the configured domain object class
if (domainObject == null || !getProcessDomainObjectClass().isAssignableFrom(domainObject.getClass())) {
continue;
}
if(!hasPermission(authentication, domainObject)) {
filterer.remove(domainObject);
if (logger.isDebugEnabled()) {
logger.debug("Principal is NOT authorised for element: " + domainObject);
}
}
}
return filterer.getFilteredObject();
}
return returnedObject;
}
}
@@ -1,122 +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.afterinvocation;
import java.util.Collection;
import java.util.List;
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;
/**
* Given a domain object instance returned from a secure object invocation, ensures the principal has
* appropriate permission as defined by the {@link AclService}.
* <p>
* The <code>AclService</code> is used to retrieve the access control list (ACL) permissions associated with a
* domain object instance for the current <code>Authentication</code> object.
* <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.model.Acl#isGranted(List, List, boolean)
* Acl.isGranted(List, List, boolean)} when presenting the {@link #requirePermission} array to that method.
* <p>
* Often users will set up an <code>AclEntryAfterInvocationProvider</code> with a {@link
* #processConfigAttribute} of <code>AFTER_ACL_READ</code> and a {@link #requirePermission} of
* <code>BasePermission.READ</code>. These are also the defaults.
* <p>
* If the principal does not have sufficient permissions, an <code>AccessDeniedException</code> will be thrown.
* <p>
* If the provided <tt>returnedObject</tt> is <code>null</code>, permission will always be granted and
* <code>null</code> will be returned.
* <p>
* All comparisons and prefixes are case sensitive.
*/
public class AclEntryAfterInvocationProvider extends AbstractAclProvider implements MessageSourceAware {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationProvider.class);
//~ Instance fields ================================================================================================
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
//~ Constructors ===================================================================================================
public AclEntryAfterInvocationProvider(AclService aclService, List<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,
Object returnedObject) throws AccessDeniedException {
if (returnedObject == null) {
// AclManager interface contract prohibits nulls
// As they have permission to null/nothing, grant access
if (logger.isDebugEnabled()) {
logger.debug("Return object is null, skipping");
}
return null;
}
if (!getProcessDomainObjectClass().isAssignableFrom(returnedObject.getClass())) {
if (logger.isDebugEnabled()) {
logger.debug("Return object is not applicable for this provider, skipping");
}
return returnedObject;
}
for (ConfigAttribute attr : config) {
if (!this.supports(attr)) {
continue;
}
// Need to make an access decision on this invocation
if (hasPermission(authentication, returnedObject)) {
return returnedObject;
}
logger.debug("Denying access");
throw new AccessDeniedException(messages.getMessage("BasicAclEntryAfterInvocationProvider.noPermission",
new Object[] {authentication.getName(), returnedObject},
"Authentication {0} has NO permissions to the domain object {1}"));
}
return returnedObject;
}
public void setMessageSource(MessageSource messageSource) {
this.messages = new MessageSourceAccessor(messageSource);
}
}
@@ -1,6 +0,0 @@
/**
* After-invocation providers for collection and array filtering. Consider using a {@code PostFilter} annotation in
* preference.
*/
package org.springframework.security.acls.afterinvocation;
@@ -1,72 +0,0 @@
package org.springframework.security.acls.domain;
import org.springframework.security.acls.model.Permission;
/**
* Provides an abstract superclass for {@link Permission} implementations.
*
* @author Ben Alex
* @since 2.0.3
*/
public abstract class AbstractPermission implements Permission {
//~ Instance fields ================================================================================================
protected char code;
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;
}
//~ Methods ========================================================================================================
public final boolean equals(Object arg0) {
if (arg0 == null) {
return false;
}
if (!(arg0 instanceof Permission)) {
return false;
}
Permission rhs = (Permission) arg0;
return (this.mask == rhs.getMask());
}
public final int getMask() {
return mask;
}
public String getPattern() {
return AclFormattingUtils.printBinary(mask, code);
}
public final String toString() {
return this.getClass().getSimpleName() + "[" + getPattern() + "=" + mask + "]";
}
public final int hashCode() {
return this.mask;
}
}
@@ -1,44 +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 org.springframework.security.acls.model.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
*/
public class BasePermission extends AbstractPermission {
public static final Permission READ = new BasePermission(1 << 0, 'R'); // 1
public static final Permission WRITE = new BasePermission(1 << 1, 'W'); // 2
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 BasePermission(int mask) {
super(mask);
}
protected BasePermission(int mask, char code) {
super(mask, code);
}
}
@@ -1,146 +0,0 @@
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.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.
*
* @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>();
/**
* 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.
*
* @param clazz a {@link Permission} class with public static fields to register
*/
protected void registerPublicPermissions(Class<? extends Permission> clazz) {
Assert.notNull(clazz, "Class required");
Field[] fields = clazz.getFields();
for (int i = 0; i < fields.length; i++) {
try {
Object fieldValue = fields[i].get(null);
if (Permission.class.isAssignableFrom(fieldValue.getClass())) {
// 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 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));
}
// To get this far, we have to use a CumulativePermission
CumulativePermission permission = new CumulativePermission();
for (int i = 0; i < 32; i++) {
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.set(p);
}
}
return permission;
}
public Permission buildFromName(String name) {
Permission p = registeredPermissionsByName.get(name);
if (p == null) {
throw new IllegalArgumentException("Unknown permission '" + name + "'");
}
return p;
}
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));
}
return permissions;
}
}
@@ -1,31 +0,0 @@
package org.springframework.security.acls.domain;
import java.util.List;
import org.springframework.security.acls.model.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);
Permission buildFromName(String name);
List<Permission> buildFromNames(List<String> names);
}
@@ -1,65 +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
*/
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;
}
}
@@ -1,5 +0,0 @@
/**
* Basic implementation of access control lists (ACLs) interfaces.
*/
package org.springframework.security.acls.domain;
@@ -1,636 +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 java.io.Serializable;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.sql.DataSource;
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.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.util.FieldUtils;
import org.springframework.util.Assert;
/**
* 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.
*
* @author Ben Alex
*/
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 ===================================================================================================
/**
* Constructor accepting mandatory arguments
*
* @param dataSource to access the database
* @param aclCache the cache where fully-loaded elements can be stored
* @param aclAuthorizationStrategy authorization strategy (required)
*/
public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
AclAuthorizationStrategy aclAuthorizationStrategy, AuditLogger auditLogger) {
Assert.notNull(dataSource, "DataSource required");
Assert.notNull(aclCache, "AclCache required");
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
Assert.notNull(auditLogger, "AuditLogger required");
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";
final String startSql = selectClause;
final String endSql = orderByClause;
StringBuilder sqlStringBldr =
new StringBuilder(startSql.length() + endSql.length() + requiredRepetitions * (repeatingSql.length() + 4));
sqlStringBldr.append(startSql);
for (int i = 1; i <= requiredRepetitions; i++) {
sqlStringBldr.append(repeatingSql);
if (i != requiredRepetitions) {
sqlStringBldr.append(" or ");
}
}
sqlStringBldr.append(endSql);
return sqlStringBldr.toString();
}
@SuppressWarnings("unchecked")
private List<AccessControlEntryImpl> readAces(AclImpl acl) {
try {
return (List<AccessControlEntryImpl>) fieldAces.get(acl);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Could not obtain AclImpl.aces field", e);
}
}
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);
}
}
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);
}
}
/**
* 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>();
for (int i = 0; i < objects.size(); i++) {
final ObjectIdentity oid = objects.get(i);
boolean aclFound = false;
// Check we don't already have this ACL in the results
if (result.containsKey(oid)) {
aclFound = true;
}
// Check cache for the present ACL entry
if (!aclFound) {
Acl acl = aclCache.getFromCache(oid);
// 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(oid);
}
// 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, sids);
// Add loaded batch (all elements 100% initialized) to results
result.putAll(loadedBatch);
// Add the loaded batch to the cache
for (Acl loadedAcl : loadedBatch.values()) {
aclCache.putInCache((AclImpl) loadedAcl);
}
currentBatchToLoad.clear();
}
}
}
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.
*
*/
private Map<ObjectIdentity, Acl> lookupObjectIdentities(final Collection<ObjectIdentity> objectIdentities, List<Sid> sids) {
Assert.notEmpty(objectIdentities, "Must provide identities to lookup");
final Map<Serializable, Acl> acls = new HashMap<Serializable, Acl>(); // contains Acls with StubAclParents
// Make the "acls" map contain all requested objectIdentities
// (including markers to each parent in the hierarchy)
String sql = computeRepeatingSql(lookupObjectIdentitiesWhereClause, objectIdentities.size());
Set<Long> parentsToLookup = jdbcTemplate.query(sql,
new PreparedStatementSetter() {
public void setValues(PreparedStatement ps) throws SQLException {
int i = 0;
for (ObjectIdentity oid : objectIdentities) {
// Determine prepared statement values for this iteration
String type = oid.getType();
// No need to check for nulls, as guaranteed non-null by ObjectIdentity.getIdentifier() interface contract
String identifier = oid.getIdentifier().toString();
long id = (Long.valueOf(identifier)).longValue();
// Inject values
ps.setLong((2 * i) + 1, id);
ps.setString((2 * i) + 2, type);
i++;
}
}
}, 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);
}
// Finally, convert our "acls" containing StubAclParents into true Acls
Map<ObjectIdentity, Acl> resultMap = new HashMap<ObjectIdentity, Acl>();
for (Acl inputAcl : acls.values()) {
Assert.isInstanceOf(AclImpl.class, inputAcl, "Map should have contained an AclImpl");
Assert.isInstanceOf(Long.class, ((AclImpl) inputAcl).getId(), "Acl.getId() must be Long");
Acl result = convert(acls, (Long) ((AclImpl) inputAcl).getId());
resultMap.put(result.getObjectIdentity(), result);
}
return resultMap;
}
/**
* The final phase of converting the <code>Map</code> of <code>AclImpl</code> instances which contain
* <code>StubAclParent</code>s into proper, valid <code>AclImpl</code>s with correct ACL parents.
*
* @param inputMap the unconverted <code>AclImpl</code>s
* @param currentIdentity the current<code>Acl</code> that we wish to convert (this may be
*
*/
private AclImpl convert(Map<Serializable, Acl> inputMap, Long currentIdentity) {
Assert.notEmpty(inputMap, "InputMap required");
Assert.notNull(currentIdentity, "CurrentIdentity required");
// Retrieve this Acl from the InputMap
Acl uncastAcl = inputMap.get(currentIdentity);
Assert.isInstanceOf(AclImpl.class, uncastAcl, "The inputMap contained a non-AclImpl");
AclImpl inputAcl = (AclImpl) uncastAcl;
Acl parent = inputAcl.getParentAcl();
if ((parent != null) && parent instanceof StubAclParent) {
// Lookup the parent
StubAclParent stubAclParent = (StubAclParent) parent;
parent = convert(inputMap, stubAclParent.getId());
}
// Now we have the parent (if there is one), create the true AclImpl
AclImpl result = new AclImpl(inputAcl.getObjectIdentity(), (Long) inputAcl.getId(), aclAuthorizationStrategy,
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;
}
/**
* Sets the {@code PermissionFactory} instance which will be used to convert loaded permission
* data values to {@code Permission}s. A {@code DefaultPermissionFactory} will be used by default.
*
* @param permissionFactory
*/
public void setPermissionFactory(PermissionFactory permissionFactory) {
this.permissionFactory = permissionFactory;
}
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;
public ProcessResultSet(Map<Serializable, Acl> acls, List<Sid> sids) {
Assert.notNull(acls, "ACLs cannot be null");
this.acls = acls;
this.sids = sids; // can be null
}
/**
* Implementation of {@link ResultSetExtractor#extractData(ResultSet)}.
* Creates an {@link Acl} for each row in the {@link ResultSet} and
* ensures it is in member field <tt>acls</tt>. Any {@link Acl} with
* a parent will have the parents id returned in a set. The returned
* set of ids may requires further processing.
* @param rs The {@link ResultSet} to be processed
* @return a list of parent IDs remaining to be looked up (may be empty, but never <tt>null</tt>)
* @throws SQLException
* @throws DataAccessException
*/
public Set<Long> extractData(ResultSet rs) throws SQLException, DataAccessException {
Set<Long> parentIdsToLookup = new HashSet<Long>(); // Set of parent_id Longs
while (rs.next()) {
// Convert current row into an Acl (albeit with a StubAclParent)
convertCurrentResultIntoObject(acls, rs);
// Figure out if this row means we need to lookup another parent
long parentId = rs.getLong("parent_object");
if (parentId != 0) {
// See if it's already in the "acls"
if (acls.containsKey(new Long(parentId))) {
continue; // skip this while iteration
}
// Now try to find it in the cache
MutableAcl cached = aclCache.getFromCache(new Long(parentId));
if ((cached == null) || !cached.isSidLoaded(sids)) {
parentIdsToLookup.add(new Long(parentId));
} else {
// Pop into the acls map, so our convert method doesn't
// need to deal with an unsynchronized AclCache
acls.put(cached.getId(), cached);
}
}
}
// Return the parents left to lookup to the caller
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 {
private Long id;
public StubAclParent(Long id) {
this.id = id;
}
public List<AccessControlEntry> getEntries() {
throw new UnsupportedOperationException("Stub only");
}
public Long getId() {
return id;
}
public ObjectIdentity getObjectIdentity() {
throw new UnsupportedOperationException("Stub only");
}
public Sid getOwner() {
throw new UnsupportedOperationException("Stub only");
}
public Acl getParentAcl() {
throw new UnsupportedOperationException("Stub only");
}
public boolean isEntriesInheriting() {
throw new UnsupportedOperationException("Stub only");
}
public boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
throws NotFoundException, UnloadedSidException {
throw new UnsupportedOperationException("Stub only");
}
public boolean isSidLoaded(List<Sid> sids) {
throw new UnsupportedOperationException("Stub only");
}
}
}
@@ -1,130 +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 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
* {@link org.springframework.security.acls.domain.AccessControlEntryImpl} to be set, so that the implementation can
* detect changed parameters easily.
*
* @author Ben Alex
*/
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 "
+ "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 = ("
+ "select id FROM acl_class where acl_class.class = ?)";
//~ Instance fields ================================================================================================
protected JdbcTemplate jdbcTemplate;
private LookupStrategy lookupStrategy;
private String findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL;
//~ Constructors ===================================================================================================
public JdbcAclService(DataSource dataSource, LookupStrategy lookupStrategy) {
Assert.notNull(dataSource, "DataSource required");
Assert.notNull(lookupStrategy, "LookupStrategy required");
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.lookupStrategy = lookupStrategy;
}
//~ 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 {
String javaType = rs.getString("class");
Long identifier = new Long(rs.getLong("obj_id"));
return new ObjectIdentityImpl(javaType, identifier);
}
});
if (objects.size() == 0) {
return null;
}
return objects;
}
public Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException {
Map<ObjectIdentity, Acl> map = readAclsById(Arrays.asList(object), sids);
Assert.isTrue(map.containsKey(object), "There should have been an Acl entry for ObjectIdentity " + object);
return (Acl) map.get(object);
}
public Acl readAclById(ObjectIdentity object) throws NotFoundException {
return readAclById(object, null);
}
public Map<ObjectIdentity, Acl> readAclsById(List<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);
// 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))) {
throw new NotFoundException("Unable to find ACL information for object identity '"
+ objects.get(i) + "'");
}
}
return result;
}
/**
* Allows customization of the SQL query used to find child object identities.
*
* @param findChildrenSql
*/
public void setFindChildrenQuery(String findChildrenSql) {
this.findChildrenSql = findChildrenSql;
}
}
@@ -1,435 +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 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.
*
* @author Ben Alex
* @author Johannes Zlattinger
*/
public class JdbcMutableAclService extends JdbcAclService implements MutableAclService {
//~ Instance fields ================================================================================================
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 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)"
+ "values (?, ?, ?, ?, ?, ?, ?)";
private String insertObjectIdentity = "insert into acl_object_identity "
+ "(object_id_class, object_id_identity, owner_sid, entries_inheriting) " + "values (?, ?, ?, ?)";
private String insertSid = "insert into acl_sid (principal, sid) values (?, ?)";
private String selectClassPrimaryKey = "select id from acl_class where class=?";
private String selectObjectIdentityPrimaryKey = "select acl_object_identity.id from acl_object_identity, acl_class "
+ "where acl_object_identity.object_id_class = acl_class.id and acl_class.class=? "
+ "and acl_object_identity.object_id_identity = ?";
private String selectSidPrimaryKey = "select id from acl_sid where principal=? and sid=?";
private String updateObjectIdentity = "update acl_object_identity set "
+ "parent_object = ?, owner_sid = ?, entries_inheriting = ?" + " where id = ?";
//~ Constructors ===================================================================================================
public JdbcMutableAclService(DataSource dataSource, LookupStrategy lookupStrategy, AclCache aclCache) {
super(dataSource, lookupStrategy);
Assert.notNull(aclCache, "AclCache required");
this.aclCache = aclCache;
}
//~ Methods ========================================================================================================
public MutableAcl createAcl(ObjectIdentity objectIdentity) throws AlreadyExistsException {
Assert.notNull(objectIdentity, "Object Identity required");
// Check this object identity hasn't already been persisted
if (retrieveObjectIdentityPrimaryKey(objectIdentity) != null) {
throw new AlreadyExistsException("Object identity '" + objectIdentity + "' already exists");
}
// Need to retrieve the current principal, in order to know who "owns" this ACL (can be changed later on)
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
PrincipalSid sid = new PrincipalSid(auth);
// Create the acl_object_identity row
createObjectIdentity(objectIdentity, sid);
// Retrieve the ACL via superclass (ensures cache registration, proper retrieval etc)
Acl acl = readAclById(objectIdentity);
Assert.isInstanceOf(MutableAcl.class, acl, "MutableAcl should be been returned");
return (MutableAcl) acl;
}
/**
* Creates a new row in acl_entry for every ACE defined in the passed MutableAcl object.
*
* @param acl containing the ACEs to insert
*/
protected void createEntries(final MutableAcl acl) {
jdbcTemplate.batchUpdate(insertEntry,
new BatchPreparedStatementSetter() {
public int getBatchSize() {
return acl.getEntries().size();
}
public void setValues(PreparedStatement stmt, int i) throws SQLException {
AccessControlEntry entry_ = acl.getEntries().get(i);
Assert.isTrue(entry_ instanceof AccessControlEntryImpl, "Unknown ACE class");
AccessControlEntryImpl entry = (AccessControlEntryImpl) entry_;
stmt.setLong(1, ((Long) acl.getId()).longValue());
stmt.setInt(2, i);
stmt.setLong(3, createOrRetrieveSidPrimaryKey(entry.getSid(), true).longValue());
stmt.setInt(4, entry.getPermission().getMask());
stmt.setBoolean(5, entry.isGranting());
stmt.setBoolean(6, entry.isAuditSuccess());
stmt.setBoolean(7, entry.isAuditFailure());
}
});
}
/**
* Creates an entry in the acl_object_identity table for the passed ObjectIdentity. The Sid is also
* necessary, as acl_object_identity has defined the sid column as non-null.
*
* @param object to represent an acl_object_identity for
* @param owner for the SID column (will be created if there is no acl_sid entry for this particular Sid already)
*/
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);
}
/**
* Retrieves the primary key from {@code acl_class}, creating a new row if needed and the
* {@code allowCreate} property is {@code true}.
*
* @param type to find or create an entry for (often the fully-qualified class name)
* @param allowCreate true if creation is permitted if not found
*
* @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);
if (!classIds.isEmpty()) {
return classIds.get(0);
}
if (allowCreate) {
jdbcTemplate.update(insertClass, type);
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
"Transaction must be running");
return new Long(jdbcTemplate.queryForLong(classIdentityQuery));
}
return null;
}
/**
* Retrieves the primary key from acl_sid, creating a new row if needed and the allowCreate property is
* true.
*
* @param sid to find or create
* @param allowCreate true if creation is permitted if not found
*
* @return the primary key or null if not found
*
* @throws IllegalArgumentException if the <tt>Sid</tt> is not a recognized implementation.
*/
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
Assert.notNull(sid, "Sid required");
String sidName = null;
boolean sidIsPrincipal = true;
if (sid instanceof PrincipalSid) {
sidName = ((PrincipalSid) sid).getPrincipal();
} else if (sid instanceof GrantedAuthoritySid) {
sidName = ((GrantedAuthoritySid) sid).getGrantedAuthority();
sidIsPrincipal = false;
} else {
throw new IllegalArgumentException("Unsupported implementation of Sid");
}
List<Long> sidIds = jdbcTemplate.queryForList(selectSidPrimaryKey,
new Object[] {Boolean.valueOf(sidIsPrincipal), sidName}, Long.class);
if (!sidIds.isEmpty()) {
return sidIds.get(0);
}
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;
}
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);
}
}
} 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()
+ " children)");
}
}
}
Long oidPrimaryKey = retrieveObjectIdentityPrimaryKey(objectIdentity);
// Delete this ACL's ACEs in the acl_entry table
deleteEntries(oidPrimaryKey);
// Delete this ACL's acl_object_identity row
deleteObjectIdentity(oidPrimaryKey);
// Clear the cache
aclCache.evictFromCache(objectIdentity);
}
/**
* Deletes all ACEs defined in the acl_entry table belonging to the presented ObjectIdentity primary key.
*
* @param oidPrimaryKey the rows in acl_entry to delete
*/
protected void deleteEntries(Long oidPrimaryKey) {
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.
*
* @param oidPrimaryKey to delete the acl_object_identity
*/
protected void deleteObjectIdentity(Long oidPrimaryKey) {
// Delete the acl_object_identity row
jdbcTemplate.update(deleteObjectIdentityByPrimaryKey, new Object[] {oidPrimaryKey});
}
/**
* Retrieves the primary key from the acl_object_identity table for the passed ObjectIdentity. Unlike some
* other methods in this implementation, this method will NOT create a row (use {@link
* #createObjectIdentity(ObjectIdentity, Sid)} instead).
*
* @param oid to find
*
* @return the object identity or null if not found
*/
protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
try {
return new Long(jdbcTemplate.queryForLong(selectObjectIdentityPrimaryKey,
new Object[] {oid.getType(), oid.getIdentifier()}));
} catch (DataAccessException notFound) {
return null;
}
}
/**
* 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}.
*/
public MutableAcl updateAcl(MutableAcl acl) throws NotFoundException {
Assert.notNull(acl.getId(), "Object Identity doesn't provide an identifier");
// Delete this ACL's ACEs in the acl_entry table
deleteEntries(retrieveObjectIdentityPrimaryKey(acl.getObjectIdentity()));
// Create this ACL's ACEs in the acl_entry table
createEntries(acl);
// Change the mutable columns in acl_object_identity
updateObjectIdentity(acl);
// Clear the cache, including children
clearCacheIncludingChildren(acl.getObjectIdentity());
// 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);
if (children != null) {
for (int i = 0; i < children.size(); i++) {
clearCacheIncludingChildren(children.get(i));
}
}
aclCache.evictFromCache(objectIdentity);
}
/**
* Updates an existing acl_object_identity row, with new information presented in the passed MutableAcl
* object. Also will create an acl_sid entry if needed for the Sid that owns the MutableAcl.
*
* @param acl to modify (a row must already exist in acl_object_identity)
*
* @throws NotFoundException if the ACL could not be found to update.
*/
protected void updateObjectIdentity(MutableAcl acl) {
Long parentId = null;
if (acl.getParentAcl() != null) {
Assert.isInstanceOf(ObjectIdentityImpl.class, acl.getParentAcl().getObjectIdentity(),
"Implementation only supports ObjectIdentityImpl");
ObjectIdentityImpl oii = (ObjectIdentityImpl) acl.getParentAcl().getObjectIdentity();
parentId = retrieveObjectIdentityPrimaryKey(oii);
}
Assert.notNull(acl.getOwner(), "Owner is required in this implementation");
Long ownerSid = createOrRetrieveSidPrimaryKey(acl.getOwner(), true);
int count = jdbcTemplate.update(updateObjectIdentity,
new Object[] {parentId, ownerSid, new Boolean(acl.isEntriesInheriting()), acl.getId()});
if (count != 1) {
throw new NotFoundException("Unable to locate ACL to update");
}
}
/**
* 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;
}
/**
* 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;
}
}
@@ -1,5 +0,0 @@
/**
* JDBC-based persistence of ACL information
*/
package org.springframework.security.acls.jdbc;
@@ -1,168 +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.model;
import java.io.Serializable;
import java.util.List;
/**
* Represents an access control list (ACL) for a domain object.
*
* <p>
* An <tt>Acl</tt> represents all ACL entries for a given domain object. In
* 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.
* </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}
* instances. Therefore, an instance may NOT necessarily contain ALL <tt>Sid</tt>s
* for a given domain object.
* </p>
*
* @author Ben Alex
*/
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.
*
* <p>This method is typically used for administrative purposes.</p>
*
* <p>The order that entries appear in the array is important for methods declared in the
* {@link MutableAcl} interface. Furthermore, some implementations MAY use ordering as
* 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>
*
* <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
* <tt>Sid</tt>s is represented.</p>
*
* @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();
/**
* Obtains the domain object this <tt>Acl</tt> provides entries for. This is immutable once an
* <tt>Acl</tt> is created.
*
* @return the object identity (never <tt>null</tt>)
*/
ObjectIdentity getObjectIdentity();
/**
* Determines the owner of the <tt>Acl</tt>. The meaning of ownership varies by implementation and is
* unspecified.
*
* @return the owner (may be <tt>null</tt> if the implementation does not use ownership concepts)
*/
Sid getOwner();
/**
* A domain object may have a parent for the purpose of ACL inheritance. If there is a parent, its ACL can
* be accessed via this method. In turn, the parent's parent (grandparent) can be accessed and so on.
*
* <p>This method solely represents the presence of a navigation hierarchy between the parent <tt>Acl</tt> and this
* <tt>Acl</tt>. For actual inheritance to take place, the {@link #isEntriesInheriting()} must also be
* <tt>true</tt>.</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
* <tt>Sid</tt>s is represented.</p>
*
* @return the parent <tt>Acl</tt> (may be <tt>null</tt> if this <tt>Acl</tt> does not have a parent)
*/
Acl getParentAcl();
/**
* Indicates whether the ACL entries from the {@link #getParentAcl()} should flow down into the current
* <tt>Acl</tt>.<p>The mere link between an <tt>Acl</tt> and a parent <tt>Acl</tt> on its own
* is insufficient to cause ACL entries to inherit down. This is because a domain object may wish to have entirely
* independent entries, but maintain the link with the parent for navigation purposes. Thus, this method denotes
* whether or not the navigation relationship also extends to the actual inheritance of entries.</p>
*
* @return <tt>true</tt> if parent ACL entries inherit into the current <tt>Acl</tt>
*/
boolean isEntriesInheriting();
/**
* This is the actual authorization logic method, and must be used whenever ACL authorization decisions are
* required.
*
* <p>An array of <tt>Sid</tt>s are presented, representing security identifies of the current
* principal. In addition, an array of <tt>Permission</tt>s is presented which will have one or more bits set
* in order to indicate the permissions needed for an affirmative authorization decision. An array is presented
* because holding <em>any</em> of the <tt>Permission</tt>s inside the array will be sufficient for an
* affirmative authorization.</p>
*
* <p>The actual approach used to make authorization decisions is left to the implementation and is not
* specified by this interface. For example, an implementation <em>MAY</em> search the current ACL in the order
* the ACL entries have been stored. If a single entry is found that has the same active bits as are shown in a
* passed <tt>Permission</tt>, that entry's grant or deny state may determine the authorization decision. If
* the case of a deny state, the deny decision will only be relevant if all other <tt>Permission</tt>s passed
* in the array have also been unsuccessfully searched. If no entry is found that match the bits in the current
* ACL, provided that {@link #isEntriesInheriting()} is <tt>true</tt>, the authorization decision may be
* passed to the parent ACL. If there is no matching entry, the implementation MAY throw an exception, or make a
* predefined authorization decision.</p>
*
* <p>This method must operate correctly even if the <tt>Acl</tt> only represents a subset of <tt>Sid</tt>s,
* although the implementation is permitted to throw one of the signature-defined exceptions if the method
* is called requesting an authorization decision for a {@link Sid} that was never loaded in this <tt>Acl</tt>.
* </p>
*
* @param permission the permission or permissions required (at least one entry required)
* @param sids the security identities held by the principal (at least one entry required)
* @param administrativeMode if <tt>true</tt> denotes the query is for administrative purposes and no logging
* or auditing (if supported by the implementation) should be undertaken
*
* @return <tt>true</tt> if authorization is granted
*
* @throws NotFoundException MUST be thrown if an implementation cannot make an authoritative authorization
* decision, usually because there is no ACL information for this particular permission and/or SID
* @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)
throws NotFoundException, UnloadedSidException;
/**
* For efficiency reasons an <tt>Acl</tt> may be loaded and <em>not</em> contain entries for every
* <tt>Sid</tt> in the system. If an <tt>Acl</tt> has been loaded and does not represent every
* <tt>Sid</tt>, all methods of the <tt>Acl</tt> can only be used within the limited scope of the
* <tt>Sid</tt> instances it actually represents.
* <p>
* It is normal to load an <tt>Acl</tt> for only particular <tt>Sid</tt>s if read-only authorization
* decisions are being made. However, if user interface reporting or modification of <tt>Acl</tt>s are
* desired, an <tt>Acl</tt> should be loaded with all <tt>Sid</tt>s. This method denotes whether or
* not the specified <tt>Sid</tt>s have been loaded or not.
* </p>
*
* @param sids one or more security identities the caller is interest in knowing whether this <tt>Sid</tt>
* supports
*
* @return <tt>true</tt> if every passed <tt>Sid</tt> is represented by this <tt>Acl</tt> instance
*/
boolean isSidLoaded(List<Sid> sids);
}
@@ -1,31 +0,0 @@
package org.springframework.security.acls.model;
/**
* Abstract base class for Acl data operations.
*
* @author Luke Taylor
* @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 cause 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);
}
}
@@ -1,98 +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.model;
import java.util.List;
import java.util.Map;
/**
* Provides retrieval of {@link Acl} instances.
*
* @author Ben Alex
*/
public interface AclService {
//~ Methods ========================================================================================================
/**
* Locates all object identities that use the specified parent. This is useful for administration tools.
*
* @param parentIdentity to locate children of
*
* @return the children (or <tt>null</tt> if none were found)
*/
List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity);
/**
* Same as {@link #readAclsById(List)} 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>
*
* @param object to locate an {@link Acl} for
*
* @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) throws NotFoundException;
/**
* Same as {@link #readAclsById(List, List)} 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
* (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;
/**
* Obtains all the <tt>Acl</tt>s that apply for the passed <tt>Object</tt>s.<p>The returned map is
* keyed on the passed objects, with the values being the <tt>Acl</tt> instances. Any unknown objects will not
* have a map key.</p>
*
* @param objects the objects to find {@link Acl} information for
*
* @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) throws NotFoundException;
/**
* Obtains all the <tt>Acl</tt>s that apply for the passed <tt>Object</tt>s, but only for the
* security identifies passed.<p>Implementations <em>MAY</em> provide a subset of the ACLs via this method
* although this is NOT a requirement. This is intended to allow performance optimisations within implementations.
* Callers should therefore use this method in preference to the alternative overloaded version which does not
* have performance optimisation opportunities.</p>
* <p>The returned map is keyed on the passed objects, with the values being the <tt>Acl</tt>
* instances. Any unknown objects (or objects for which the interested <tt>Sid</tt>s do not have entries) will
* 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
* (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;
}
@@ -1,71 +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.model;
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
* 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
* reference-equality of <tt>identity1==identity2</tt>.
* </p>
*
* @author Ben Alex
*/
public interface ObjectIdentity extends Serializable {
//~ Methods ========================================================================================================
/**
* @param obj to be compared
*
* @return <tt>true</tt> if the objects are equal, <tt>false</tt> otherwise
* @see Object#equals(Object)
*/
boolean equals(Object obj);
/**
* 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
* subsystem data.</p>
*
* @return the identifier (unique within this <tt>type</tt>; never <tt>null</tt>)
*/
Serializable getIdentifier();
/**
* Obtains the "type" metadata for the domain object. This will often be a Java type name (an interface or a class)
* &ndash; traditionally it is the name of the domain object implementation class.
*
* @return the "type" of the domain object (never <tt>null</tt>).
*/
String getType();
/**
* @return a hash code representation of the <tt>ObjectIdentity</tt>
* @see Object#hashCode()
*/
int hashCode();
}
@@ -1,26 +0,0 @@
package org.springframework.security.acls.model;
import java.io.Serializable;
/**
* Strategy which creates an {@link ObjectIdentity} 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
* @since 3.0
*/
public interface ObjectIdentityGenerator {
/**
*
* @param id the identifier of the domain object, not null
* @param type the type of the object (often a class name), not null
* @return the identity constructed using the supplied identifier and type information.
*/
ObjectIdentity createObjectIdentity(Serializable id, String type);
}
@@ -1,5 +0,0 @@
/**
* Interfaces and shared classes to manage access control lists (ACLs) for domain object instances.
*/
package org.springframework.security.acls.model;
@@ -1,9 +0,0 @@
/**
* The Spring Security ACL package which implements instance-based security for domain objects.
* <p>
* Consider using the annotation based approach ({@code @PreAuthorize}, {@code @PostFilter} annotations) combined
* with a {@link org.springframework.security.acls.AclPermissionEvaluator} in preference to the older and more verbose
* attribute/voter/after-invocation approach from versions before Spring Security 3.0.
*/
package org.springframework.security.acls;
@@ -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)
);
-39
View File
@@ -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
@@ -1,127 +0,0 @@
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;
/**
* Tests for {@link AclFormattingUtils}.
*
* @author Andrei Stefan
*/
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);
}
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", "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));
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", "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");
}
}
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'));
}
}
@@ -1,39 +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
* @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,10 +0,0 @@
package org.springframework.security.acls;
/**
* Dummy domain object class
*
* @author Luke Taylor
*/
public final class TargetObject {
}
@@ -1,104 +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
*/
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,567 +0,0 @@
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;
/**
* 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);
// ~ Methods ========================================================================================================
@Before
public void setUp() throws Exception {
SecurityContextHolder.getContext().setAuthentication(auth);
mockAuthzStrategy = mock(AclAuthorizationStrategy.class);
mockAuditLogger = mock(AuditLogger.class);;
auth.setAuthenticated(true);
}
@After
public void tearDown() throws Exception {
SecurityContextHolder.clearContext();
}
@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);
}
@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"));
fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
}
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"));
fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
}
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"));
try {
acl.insertAce(0, null, new GrantedAuthoritySid("ROLE_IGNORED"), true);
fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
}
try {
acl.insertAce(0, BasePermission.READ, null, true);
fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
}
}
@Test
public void insertAceAddsElementAtCorrectIndex() throws Exception {
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid("joe"));
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"));
// 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"));
// 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());
// 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"));
}
@Test(expected=NotFoundException.class)
public void insertAceFailsForNonExistentElement() throws Exception {
MutableAcl acl = new AclImpl(objectIdentity,1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid(
"joe"));
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);
}
@Test
public void deleteAceKeepsInitialOrdering() throws Exception {
MutableAcl acl = new AclImpl(objectIdentity,1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid(
"joe"));
MockAclService service = new MockAclService();
// Add several permissions
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST1"), true);
acl.insertAce(1, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST2"), true);
acl.insertAce(2, BasePermission.READ, new GrantedAuthoritySid("ROLE_TEST3"), true);
service.updateAcl(acl);
// 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"));
// 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"));
// Remove remaining permissions
acl.deleteAce(1);
acl.deleteAce(0);
assertEquals(0, acl.getEntries().size());
}
@Test
public void deleteAceFailsForNonExistentElement() throws Exception {
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"));
try {
acl.deleteAce(99);
fail("It should have thrown NotFoundException");
}
catch (NotFoundException expected) {
}
}
@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");
try {
acl.isGranted(new ArrayList<Permission>(0), Arrays.asList(ben) , false);
fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
}
try {
acl.isGranted(READ, new ArrayList<Sid>(0), false);
fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
}
}
@Test
public void isGrantingGrantsAccessForAclWithNoParent() throws Exception {
Authentication auth = new TestingAuthenticationToken("ben", "ignored", "ROLE_GENERAL","ROLE_GUEST");
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
ObjectIdentity rootOid = new ObjectIdentityImpl(TARGET_CLASS, 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"));
// Grant some permissions
rootAcl.insertAce(0, BasePermission.READ, new PrincipalSid("ben"), false);
rootAcl.insertAce(1, BasePermission.WRITE, new PrincipalSid("scott"), true);
rootAcl.insertAce(2, BasePermission.WRITE, new PrincipalSid("rod"), false);
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"));
assertFalse(rootAcl.isGranted(permissions, sids, false));
try {
rootAcl.isGranted(permissions, SCOTT, false);
fail("It should have thrown NotFoundException");
}
catch (NotFoundException expected) {
}
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));
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);
fail("It should have thrown NotFoundException");
}
catch (NotFoundException expected) {
}
}
@Test
public void isGrantingGrantsAccessForInheritableAcls() throws Exception {
Authentication auth = new TestingAuthenticationToken("ben", "ignored","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);
// 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"));
// Create hierarchies
childAcl2.setParent(childAcl1);
childAcl1.setParent(parentAcl1);
parentAcl2.setParent(grandParentAcl);
parentAcl1.setParent(grandParentAcl);
// Add some permissions
grandParentAcl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
grandParentAcl.insertAce(1, BasePermission.WRITE, new PrincipalSid("ben"), true);
grandParentAcl.insertAce(2, BasePermission.DELETE, new PrincipalSid("ben"), false);
grandParentAcl.insertAce(3, BasePermission.DELETE, new PrincipalSid("scott"), true);
parentAcl1.insertAce(0, BasePermission.READ, new PrincipalSid("scott"), true);
parentAcl1.insertAce(1, BasePermission.DELETE, new PrincipalSid("scott"), false);
parentAcl2.insertAce(0, BasePermission.CREATE, new PrincipalSid("ben"), true);
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));
// Check granting process for parent2
assertTrue(parentAcl2.isGranted(CREATE, BEN, false));
assertTrue(parentAcl2.isGranted(WRITE, BEN, false));
assertFalse(parentAcl2.isGranted(DELETE, BEN, false));
// Check granting process for child1
assertTrue(childAcl1.isGranted(CREATE, SCOTT,
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));
fail("It should have thrown NotFoundException");
}
catch (NotFoundException expected) {
assertTrue(true);
}
try {
assertTrue(childAcl2.isGranted(CREATE, Arrays.asList((Sid)new PrincipalSid("joe")), false));
fail("It should have thrown NotFoundException");
}
catch (NotFoundException expected) {
assertTrue(true);
}
}
@Test
public void updatedAceValuesAreCorrectlyReflectedInAcl() throws Exception {
Authentication auth = new TestingAuthenticationToken("ben", "ignored","ROLE_GENERAL");
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, false, new PrincipalSid(
"joe"));
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);
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);
// Change each permission
acl.updateAce(0, BasePermission.CREATE);
acl.updateAce(1, BasePermission.DELETE);
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);
}
@Test
public void auditableEntryFlagsAreUpdatedCorrectly() throws Exception {
Authentication auth = new TestingAuthenticationToken("ben", "ignored", "ROLE_AUDITING", "ROLE_GENERAL");
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, false, new PrincipalSid(
"joe"));
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());
// 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());
}
@Test
public void gettersAndSettersAreConsistent() 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"));
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.getObjectIdentity(), identity);
assertEquals(acl.getOwner(), new PrincipalSid("joe"));
assertNull(acl.getParentAcl());
assertTrue(acl.isEntriesInheriting());
assertEquals(2, acl.getEntries().size());
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"));
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(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"))));
}
@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 ==================================================================================================
private class MockAclService implements MutableAclService {
public MutableAcl createAcl(ObjectIdentity objectIdentity) throws AlreadyExistsException {
return null;
}
public void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren) throws ChildrenExistException {
}
/*
* 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();
Field acesField = FieldUtils.getField(AclImpl.class, "aces");
acesField.setAccessible(true);
List newAces;
try {
newAces = (List) acesField.get(acl);
newAces.clear();
for (int i = 0; i < oldAces.size(); i++) {
AccessControlEntry ac = oldAces.get(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
.isGranting(), ((AuditableAccessControlEntry) ac).isAuditSuccess(),
((AuditableAccessControlEntry) ac).isAuditFailure()));
}
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
return acl;
}
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
return null;
}
public Acl readAclById(ObjectIdentity object) throws NotFoundException {
return null;
}
public Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException {
return null;
}
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects) throws NotFoundException {
return null;
}
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) throws NotFoundException {
return null;
}
}
}
@@ -1,260 +0,0 @@
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;
/**
* 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 ========================================================================================================
protected void setUp() throws Exception {
SecurityContextHolder.clearContext();
}
protected void tearDown() throws Exception {
SecurityContextHolder.clearContext();
}
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(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());
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_GENERAL);
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_AUDITING);
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
// 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) {
}
}
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);
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") });
// 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);
// The CHANGE_GENERAL test should pass as the principal has ROLE_GENERAL
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_GENERAL);
// 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) {
}
// 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) {
}
// 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 test should pass as there is one ACE with
// granting access
aclAuthorizationStrategy.securityCheck(aclFirstAllow, AclAuthorizationStrategy.CHANGE_AUDITING);
// 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 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");
}
}
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);
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") });
// 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());
// 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);
}
// 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");
}
}
}
@@ -1,91 +0,0 @@
package org.springframework.security.acls.domain;
import static org.junit.Assert.*;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
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;
/**
* Test class for {@link ConsoleAuditLogger}.
*
* @author Andrei Stefan
*/
public class AuditLoggerTests {
//~ 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;
//~ 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));
}};
console = System.out;
System.setOut(new PrintStream(bytes));
}
@After
public void tearDown() throws Exception {
System.setOut(console);
bytes.reset();
}
@Test
public void nonAuditableAceIsIgnored() {
AccessControlEntry ace = jmock.mock(AccessControlEntry.class);
logger.logIfNeeded(true, ace);
assertEquals(0, bytes.size());
}
@Test
public void successIsNotLoggedIfAceDoesntRequireSuccessAudit() throws Exception {
jmock.checking(aceDoesntRequireAudit);
logger.logIfNeeded(true, ace);
assertEquals(0, bytes.size());
}
@Test
public void successIsLoggedIfAceRequiresSuccessAudit() throws Exception {
jmock.checking(aceRequiresAudit);
logger.logIfNeeded(true, ace);
assertTrue(bytes.toString().startsWith("GRANTED due to ACE"));
}
@Test
public void failureIsntLoggedIfAceDoesntRequireFailureAudit() throws Exception {
jmock.checking(aceDoesntRequireAudit);
logger.logIfNeeded(false, ace);
assertEquals(0, bytes.size());
}
@Test
public void failureIsLoggedIfAceRequiresFailureAudit() throws Exception {
jmock.checking(aceRequiresAudit);
logger.logIfNeeded(false, ace);
assertTrue(bytes.toString().startsWith("DENIED due to ACE"));
}
}
@@ -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
*/
@SuppressWarnings("unused")
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;
}
}
private class MockOtherIdDomainObject {
private Object id;
public Object getId() {
return id;
}
public void setId(Object id) {
this.id = id;
}
}
}
@@ -1,42 +0,0 @@
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;
import junit.framework.TestCase;
/**
* Tests for {@link ObjectIdentityRetrievalStrategyImpl}
*
* @author Andrei Stefan
*/
public class ObjectIdentityRetrievalStrategyImplTests extends TestCase {
//~ Methods ========================================================================================================
public void testObjectIdentityCreation() throws Exception {
MockIdDomainObject domain = new MockIdDomainObject();
domain.setId(new Integer(1));
ObjectIdentityRetrievalStrategy retStrategy = new ObjectIdentityRetrievalStrategyImpl();
ObjectIdentity identity = retStrategy.getObjectIdentity(domain);
assertNotNull(identity);
assertEquals(identity, new ObjectIdentityImpl(domain));
}
//~ Inner Classes ==================================================================================================
@SuppressWarnings("unused")
private class MockIdDomainObject {
private Object id;
public Object getId() {
return id;
}
public void setId(Object id) {
this.id = id;
}
}
}
@@ -1,100 +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 static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.security.acls.model.Permission;
/**
* Tests classes associated with Permission.
*
* @author Ben Alex
*/
public class PermissionTests {
private DefaultPermissionFactory permissionFactory;
@Before
public void createPermissionfactory() {
permissionFactory = new DefaultPermissionFactory();
}
@Test
public void basePermissionTest() {
Permission p = permissionFactory.buildFromName("WRITE");
assertNotNull(p);
}
@Test
public void expectedIntegerValues() {
assertEquals(1, BasePermission.READ.getMask());
assertEquals(16, BasePermission.ADMINISTRATION.getMask());
assertEquals(7,
new CumulativePermission().set(BasePermission.READ).set(BasePermission.WRITE).set(BasePermission.CREATE)
.getMask());
assertEquals(17,
new CumulativePermission().set(BasePermission.READ).set(BasePermission.ADMINISTRATION).getMask());
}
@Test
public void fromInteger() {
Permission permission = permissionFactory.buildFromMask(7);
System.out.println("7 = " + permission.toString());
permission = permissionFactory.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());
System.out.println("A = " + BasePermission.ADMINISTRATION.toString());
assertEquals("BasePermission[...........................A....=16]", BasePermission.ADMINISTRATION.toString());
System.out.println("R = " + new CumulativePermission().set(BasePermission.READ).toString());
assertEquals("CumulativePermission[...............................R=1]",
new CumulativePermission().set(BasePermission.READ).toString());
System.out.println("A = " + new CumulativePermission().set(SpecialPermission.ENTER).set(BasePermission.ADMINISTRATION).toString());
assertEquals("CumulativePermission[..........................EA....=48]",
new CumulativePermission().set(SpecialPermission.ENTER).set(BasePermission.ADMINISTRATION).toString());
System.out.println("RA = "
+ new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ).toString());
assertEquals("CumulativePermission[...........................A...R=17]",
new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ).toString());
System.out.println("R = "
+ new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ)
.clear(BasePermission.ADMINISTRATION).toString());
assertEquals("CumulativePermission[...............................R=1]",
new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ)
.clear(BasePermission.ADMINISTRATION).toString());
System.out.println("0 = "
+ new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ)
.clear(BasePermission.ADMINISTRATION).clear(BasePermission.READ).toString());
assertEquals("CumulativePermission[................................=0]",
new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ)
.clear(BasePermission.ADMINISTRATION).clear(BasePermission.READ).toString());
}
}
@@ -1,312 +0,0 @@
package org.springframework.security.acls.jdbc;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import junit.framework.Assert;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
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.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.DefaultPermissionFactory;
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.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 static CacheManager cacheManager;
//~ Methods ========================================================================================================
@BeforeClass
public static void initCacheManaer() {
cacheManager = new CacheManager();
cacheManager.addCache(new Cache("basiclookuptestcache", 500, false, false, 30, 30));
}
@BeforeClass
public static void createDatabase() throws Exception {
dataSource = new SingleConnectionDataSource("jdbc:hsqldb:mem:lookupstrategytest", "sa", "", true);
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
jdbcTemplate = new JdbcTemplate(dataSource);
Resource resource = new ClassPathResource("createAclSchema.sql");
String sql = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()));
jdbcTemplate.execute(sql);
}
@AfterClass
public static void dropDatabase() throws Exception {
dataSource.destroy();
}
@AfterClass
public static void shutdownCacheManager() {
cacheManager.removalAll();
cacheManager.shutdown();
}
@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_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);"
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (1,1,0,1,1,1,0,0);"
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (2,1,1,1,2,0,0,0);"
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (3,2,0,1,8,1,0,0);"
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (4,3,0,1,8,0,0,0);";
jdbcTemplate.execute(query);
}
@Before
public void initializeBeans() {
EhCacheBasedAclCache cache = new EhCacheBasedAclCache(getCache());
AclAuthorizationStrategy authorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_ADMINISTRATOR"), new GrantedAuthorityImpl("ROLE_ADMINISTRATOR"),
new GrantedAuthorityImpl("ROLE_ADMINISTRATOR") });
strategy = new BasicLookupStrategy(dataSource, cache, authorizationStrategy, new ConsoleAuditLogger());
strategy.setPermissionFactory(new DefaultPermissionFactory());
}
@After
public void emptyDatabase() {
String query = "DELETE FROM acl_entry;" + "DELETE FROM acl_object_identity WHERE ID = 7;"
+ "DELETE FROM acl_object_identity WHERE ID = 6;" + "DELETE FROM acl_object_identity WHERE ID = 5;"
+ "DELETE FROM acl_object_identity WHERE ID = 4;" + "DELETE FROM acl_object_identity WHERE ID = 3;"
+ "DELETE FROM acl_object_identity WHERE ID = 2;" + "DELETE FROM acl_object_identity WHERE ID = 1;"
+ "DELETE FROM acl_class;" + "DELETE FROM acl_sid;";
jdbcTemplate.execute(query);
}
private Ehcache getCache() {
Ehcache cache = cacheManager.getCache("basiclookuptestcache");
cache.removeAll();
return cache;
}
@Test
public void testAclsRetrievalWithDefaultBatchSize() throws Exception {
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, 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));
Map<ObjectIdentity, Acl> map = this.strategy.readAclsById(Arrays.asList(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));
// Objects were put in cache
strategy.readAclsById(Arrays.asList(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);
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));
// 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);
checkEntries(topParentOid, middleParentOid, childOid, map);
}
private void checkEntries(ObjectIdentity topParentOid, ObjectIdentity middleParentOid, ObjectIdentity childOid,
Map<ObjectIdentity, Acl> map) throws Exception {
Assert.assertEquals(3, map.size());
MutableAcl topParent = (MutableAcl) map.get(topParentOid);
MutableAcl middleParent = (MutableAcl) map.get(middleParentOid);
MutableAcl child = (MutableAcl) map.get(childOid);
// Check the retrieved versions has IDs
Assert.assertNotNull(topParent.getId());
Assert.assertNotNull(middleParent.getId());
Assert.assertNotNull(child.getId());
// Check their parents were correctly retrieved
Assert.assertNull(topParent.getParentAcl());
Assert.assertEquals(topParentOid, middleParent.getParentAcl().getObjectIdentity());
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());
// Check object identities were correctly retrieved
Assert.assertEquals(topParentOid, topParent.getObjectIdentity());
Assert.assertEquals(middleParentOid, middleParent.getObjectIdentity());
Assert.assertEquals(childOid, child.getObjectIdentity());
// Check each entry
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().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.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.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());
}
@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));
// Retrieve the child
Map<ObjectIdentity, Acl> map = this.strategy.readAclsById(Arrays.asList(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());
Assert.assertNotNull(map.get(middleParentOid));
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));
}
/**
* Test created from SEC-590.
*/
@Test
public void testReadAllObjectIdentitiesWhenLastElementIsAlreadyCached() 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,104,null,1,1);"
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (5,2,105,4,1,1);"
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (6,2,106,4,1,1);"
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (7,2,107,5,1,1);"
+ "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));
// 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);
Acl foundChildAcl = (Acl) foundAcls.get(childOid);
Assert.assertNotNull(foundChildAcl);
Assert.assertTrue(foundChildAcl.isGranted(checkPermission, sids, false));
// 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);
try {
foundAcls = strategy.readAclsById(allOids, sids);
Assert.assertTrue(true);
} catch (NotFoundException notExpected) {
Assert.fail("It shouldn't have thrown NotFoundException");
}
Acl foundParent2Acl = (Acl) foundAcls.get(parent2Oid);
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));
}
}
@@ -1,266 +0,0 @@
package org.springframework.security.acls.jdbc;
import static org.junit.Assert.*;
import java.io.File;
import java.io.FileInputStream;
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;
import net.sf.ehcache.Ehcache;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
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.util.FieldUtils;
/**
* Tests {@link EhCacheBasedAclCache}
*
* @author Andrei Stefan
*/
public class EhCacheBasedAclCacheTests {
private static final String TARGET_CLASS = "org.springframework.security.acls.TargetObject";
private static CacheManager cacheManager;
@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));
}
@AfterClass
public static void shutdownCacheManager() {
cacheManager.removalAll();
cacheManager.shutdown();
}
@After
public void clearContext() {
SecurityContextHolder.clearContext();
}
private Ehcache getCache() {
Ehcache cache = cacheManager.getCache("ehcachebasedacltests");
cache.removeAll();
return cache;
}
@Test(expected=IllegalArgumentException.class)
public void constructorRejectsNullParameters() throws Exception {
new EhCacheBasedAclCache(null);
}
@Test
public void methodsRejectNullParameters() throws Exception {
Ehcache cache = new MockEhcache();
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
try {
Serializable id = null;
myCache.evictFromCache(id);
fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
assertTrue(true);
}
try {
ObjectIdentity obj = null;
myCache.evictFromCache(obj);
fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
assertTrue(true);
}
try {
Serializable id = null;
myCache.getFromCache(id);
fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
assertTrue(true);
}
try {
ObjectIdentity obj = null;
myCache.getFromCache(obj);
fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
assertTrue(true);
}
try {
MutableAcl acl = null;
myCache.putInCache(acl);
fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
assertTrue(true);
}
}
// SEC-527
@Test
public void testDiskSerializationOfMutableAclObjectInstance() throws Exception {
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") });
MutableAcl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
// 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();
assertEquals(acl, retrieved);
Object retrieved1 = FieldUtils.getProtectedFieldValue("aclAuthorizationStrategy", retrieved);
assertEquals(null, retrieved1);
Object retrieved2 = FieldUtils.getProtectedFieldValue("auditLogger", retrieved);
assertEquals(null, retrieved2);
}
@Test
public void cacheOperationsAclWithoutParent() throws Exception {
Ehcache cache = getCache();
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
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") });
MutableAcl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
assertEquals(0, cache.getDiskStoreSize());
myCache.putInCache(acl);
assertEquals(cache.getSize(), 2);
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));
MutableAcl acl2 = new AclImpl(identity2, new Long(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
myCache.putInCache(acl2);
assertEquals(cache.getSize(), 4);
assertEquals(4, cache.getDiskStoreSize());
// Try to evict an entry that doesn't exist
myCache.evictFromCache(new Long(3));
myCache.evictFromCache(new ObjectIdentityImpl(TARGET_CLASS, new Long(102)));
assertEquals(cache.getSize(), 4);
assertEquals(4, cache.getDiskStoreSize());
myCache.evictFromCache(new Long(1));
assertEquals(cache.getSize(), 2);
assertEquals(2, cache.getDiskStoreSize());
// Check the second object inserted
assertEquals(myCache.getFromCache(new Long(2)), acl2);
assertEquals(myCache.getFromCache(identity2), acl2);
myCache.evictFromCache(identity2);
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));
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());
myCache.putInCache(acl);
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));
}
//~ Inner Classes ==================================================================================================
private class MockEhcache extends Cache {
public MockEhcache() {
super("cache", 0, true, true, 0, 0);
}
}
}
@@ -1,493 +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
*/
@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,66 +0,0 @@
package org.springframework.security.acls.sid;
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
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;
/**
* Tests for {@link SidRetrievalStrategyImpl}
*
* @author Andrei Stefan
* @author Luke Taylor
*/
@SuppressWarnings("unchecked")
public class SidRetrievalStrategyTests {
Authentication authentication = new TestingAuthenticationToken("scott", "password", "A", "B", "C");
//~ Methods ========================================================================================================
@Test
public void correctSidsAreRetrieved() throws Exception {
SidRetrievalStrategy retrStrategy = new SidRetrievalStrategyImpl();
List<Sid> sids = retrStrategy.getSids(authentication);
assertNotNull(sids);
assertEquals(4, sids.size());
assertNotNull(sids.get(0));
assertTrue(sids.get(0) instanceof PrincipalSid);
for (int i = 1; i < sids.size(); i++) {
assertTrue(sids.get(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());
}
}
@@ -1,190 +0,0 @@
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;
public class SidTests extends TestCase {
//~ Methods ========================================================================================================
public void testPrincipalSidConstructorsRequiredFields() throws Exception {
// Check one String-argument constructor
try {
String string = null;
new PrincipalSid(string);
Assert.fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
Assert.assertTrue(true);
}
try {
new PrincipalSid("");
Assert.fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
Assert.assertTrue(true);
}
try {
new PrincipalSid("johndoe");
Assert.assertTrue(true);
}
catch (IllegalArgumentException notExpected) {
Assert.fail("It shouldn't have thrown IllegalArgumentException");
}
// Check one Authentication-argument constructor
try {
Authentication authentication = null;
new PrincipalSid(authentication);
Assert.fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
Assert.assertTrue(true);
}
try {
Authentication authentication = new TestingAuthenticationToken(null, "password");
new PrincipalSid(authentication);
Assert.fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
Assert.assertTrue(true);
}
try {
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
new PrincipalSid(authentication);
Assert.assertTrue(true);
}
catch (IllegalArgumentException notExpected) {
Assert.fail("It shouldn't have thrown IllegalArgumentException");
}
}
public void testGrantedAuthoritySidConstructorsRequiredFields() throws Exception {
// Check one String-argument constructor
try {
String string = null;
new GrantedAuthoritySid(string);
Assert.fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
Assert.assertTrue(true);
}
try {
new GrantedAuthoritySid("");
Assert.fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
Assert.assertTrue(true);
}
try {
new GrantedAuthoritySid("ROLE_TEST");
Assert.assertTrue(true);
}
catch (IllegalArgumentException notExpected) {
Assert.fail("It shouldn't have thrown IllegalArgumentException");
}
// Check one GrantedAuthority-argument constructor
try {
GrantedAuthority ga = null;
new GrantedAuthoritySid(ga);
Assert.fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
Assert.assertTrue(true);
}
try {
GrantedAuthority ga = new GrantedAuthorityImpl(null);
new GrantedAuthoritySid(ga);
Assert.fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
Assert.assertTrue(true);
}
try {
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
new GrantedAuthoritySid(ga);
Assert.assertTrue(true);
}
catch (IllegalArgumentException notExpected) {
Assert.fail("It shouldn't have thrown IllegalArgumentException");
}
}
public void testPrincipalSidEquals() throws Exception {
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
Sid principalSid = new PrincipalSid(authentication);
Assert.assertFalse(principalSid.equals(null));
Assert.assertFalse(principalSid.equals("DIFFERENT_TYPE_OBJECT"));
Assert.assertTrue(principalSid.equals(principalSid));
Assert.assertTrue(principalSid.equals(new PrincipalSid(authentication)));
Assert.assertTrue(principalSid.equals(new PrincipalSid(new TestingAuthenticationToken("johndoe", null))));
Assert.assertFalse(principalSid.equals(new PrincipalSid(new TestingAuthenticationToken("scott", null))));
Assert.assertTrue(principalSid.equals(new PrincipalSid("johndoe")));
Assert.assertFalse(principalSid.equals(new PrincipalSid("scott")));
}
public void testGrantedAuthoritySidEquals() throws Exception {
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
Sid gaSid = new GrantedAuthoritySid(ga);
Assert.assertFalse(gaSid.equals(null));
Assert.assertFalse(gaSid.equals("DIFFERENT_TYPE_OBJECT"));
Assert.assertTrue(gaSid.equals(gaSid));
Assert.assertTrue(gaSid.equals(new GrantedAuthoritySid(ga)));
Assert.assertTrue(gaSid.equals(new GrantedAuthoritySid(new GrantedAuthorityImpl("ROLE_TEST"))));
Assert.assertFalse(gaSid.equals(new GrantedAuthoritySid(new GrantedAuthorityImpl("ROLE_NOT_EQUAL"))));
Assert.assertTrue(gaSid.equals(new GrantedAuthoritySid("ROLE_TEST")));
Assert.assertFalse(gaSid.equals(new GrantedAuthoritySid("ROLE_NOT_EQUAL")));
}
public void testPrincipalSidHashCode() throws Exception {
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
Sid principalSid = new PrincipalSid(authentication);
Assert.assertTrue(principalSid.hashCode() == new String("johndoe").hashCode());
Assert.assertTrue(principalSid.hashCode() == new PrincipalSid("johndoe").hashCode());
Assert.assertTrue(principalSid.hashCode() != new PrincipalSid("scott").hashCode());
Assert.assertTrue(principalSid.hashCode() != new PrincipalSid(new TestingAuthenticationToken("scott", "password")).hashCode());
}
public void testGrantedAuthoritySidHashCode() throws Exception {
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
Sid gaSid = new GrantedAuthoritySid(ga);
Assert.assertTrue(gaSid.hashCode() == new String("ROLE_TEST").hashCode());
Assert.assertTrue(gaSid.hashCode() == new GrantedAuthoritySid("ROLE_TEST").hashCode());
Assert.assertTrue(gaSid.hashCode() != new GrantedAuthoritySid("ROLE_TEST_2").hashCode());
Assert.assertTrue(gaSid.hashCode() != new GrantedAuthoritySid(new GrantedAuthorityImpl("ROLE_TEST_2")).hashCode());
}
public void testGetters() throws Exception {
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
PrincipalSid principalSid = new PrincipalSid(authentication);
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
GrantedAuthoritySid gaSid = new GrantedAuthoritySid(ga);
Assert.assertTrue("johndoe".equals(principalSid.getPrincipal()));
Assert.assertFalse("scott".equals(principalSid.getPrincipal()));
Assert.assertTrue("ROLE_TEST".equals(gaSid.getGrantedAuthority()));
Assert.assertFalse("ROLE_TEST2".equals(gaSid.getGrantedAuthority()));
}
}
@@ -1,83 +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.
-
-->
<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>
-21
View File
@@ -1,21 +0,0 @@
Bundle-SymbolicName: org.springframework.security.acls
Bundle-Name: Spring Security Acls
Bundle-Vendor: SpringSource
Bundle-Version: ${version}
Bundle-ManifestVersion: 2
Ignored-Existing-Headers:
Import-Package,
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="[${spring.version}, 3.1.0)";resolution:=optional,
org.springframework.dao.*;version="[${spring.version}, 3.1.0)";resolution:=optional,
org.springframework.jdbc.core.*;version="[${spring.version}, 3.1.0)";resolution:=optional,
org.springframework.transaction.support.*;version="[${spring.version}, 3.1.0)";resolution:=optional,
org.springframework.util.*;version="[${spring.version}, 3.1.0)";resolution:=optional,
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
javax.sql.*;version="0";resolution:=optional
+1
View File
@@ -0,0 +1 @@
target
+5
View File
@@ -0,0 +1,5 @@
target
.settings
.classpath
.project
.wtpmodules
+26
View File
@@ -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.acegisecurity</groupId>
<artifactId>acegi-security-adapters</artifactId>
<version>1.0.7</version>
</parent>
<artifactId>acegi-security-cas</artifactId>
<name>Acegi Security System for Spring - CAS adapter</name>
<dependencies>
<dependency>
<groupId>cas</groupId>
<artifactId>cas-server</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>cas</groupId>
<artifactId>cas</artifactId>
<version>2.0.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,102 @@
/* 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.acegisecurity.adapters.cas;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import javax.servlet.ServletRequest;
/**
* Provides actual CAS authentication by delegation to an <code>AuthenticationManager</code>.<P>Do not use this
* class directly. Instead configure CAS to use the {@link CasPasswordHandlerProxy}.</p>
*
* @author Ben Alex
* @version $Id$
*/
public final class CasPasswordHandler implements InitializingBean {
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(CasPasswordHandler.class);
//~ Instance fields ================================================================================================
private AuthenticationManager authenticationManager;
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
if (this.authenticationManager == null) {
throw new IllegalArgumentException("An AuthenticationManager is required");
}
}
/**
* Called by <code>CasPasswordHandlerProxy</code> for individual authentication requests.<P>Delegates to
* the configured <code>AuthenticationManager</code>.</p>
*
* @param servletRequest as provided by CAS
* @param username provided to CAS
* @param password provided to CAS
*
* @return whether authentication was successful or not
*/
public boolean authenticate(ServletRequest servletRequest, String username, String password) {
if ((username == null) || "".equals(username)) {
return false;
}
if (password == null) {
password = "";
}
Authentication request = new UsernamePasswordAuthenticationToken(username.toString(), password.toString());
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 false;
}
if (logger.isDebugEnabled()) {
logger.debug("Authentication request for user: " + username + " successful");
}
return true;
}
public AuthenticationManager getAuthenticationManager() {
return authenticationManager;
}
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
}
@@ -0,0 +1,113 @@
/* 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.acegisecurity.adapters.cas;
import edu.yale.its.tp.cas.auth.PasswordHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import java.util.Map;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
/**
* Enables CAS to use the Acegi Security System for authentication.<P>This class works along with {@link
* CasPasswordHandler} to enable users to easily migrate from stand-alone Acegi Security System deployments to
* enterprise-wide CAS deployments.</p>
* <p>It should be noted that the Acegi Security System will operate as a CAS client irrespective of the
* <code>PasswordHandler</code> used on the CAS server. In other words, this class need <B>not</B> be used on the CAS
* server if not desired. It exists solely for the convenience of users wishing have CAS delegate to an Acegi Security
* System-based <code>AuthenticationManager</code>.</p>
* <p>This class works requires a properly configured <code>CasPasswordHandler</code>. On the first authentication
* request, the class will use Spring's {@link WebApplicationContextUtils#getWebApplicationContext(ServletContext sc)}
* method to obtain an <code>ApplicationContext</code> instance, inside which must be a configured
* <code>CasPasswordHandler</code> instance. The <code>CasPasswordHandlerProxy</code> will then delegate
* authentication requests to that instance.</p>
* <p>To configure CAS to use this class, edit CAS' <code>web.xml</code> and define the
* <code>edu.yale.its.tp.cas.authHandler</code> context parameter with the value
* <code>org.acegisecurity.adapters.cas.CasPasswordHandlerProxy</code>.</p>
*
* @author Ben Alex
* @version $Id$
*/
public class CasPasswordHandlerProxy implements PasswordHandler {
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(CasPasswordHandlerProxy.class);
//~ Instance fields ================================================================================================
private ApplicationContext ctx;
private CasPasswordHandler handler;
//~ Methods ========================================================================================================
/**
* Called by CAS when authentication is required.<P>Delegates to the <code>CasPasswordHandler</code>.</p>
*
* @param request as provided by CAS
* @param username provided to CAS
* @param password provided to CAS
*
* @return whether authentication was successful or not
*
* @throws IllegalArgumentException if the application context does not contain a <code>CasPasswordHandler</code>
* or the <code>ServletRequest</code> was not of type <code>HttpServletRequest</code>
*/
public boolean authenticate(ServletRequest request, String username, String password) {
if (ctx == null) {
if (!(request instanceof HttpServletRequest)) {
throw new IllegalArgumentException("Can only process HttpServletRequest");
}
HttpServletRequest httpRequest = (HttpServletRequest) request;
ctx = this.getContext(httpRequest);
}
if (handler == null) {
Map beans = ctx.getBeansOfType(CasPasswordHandler.class, true, true);
if (beans.size() == 0) {
throw new IllegalArgumentException(
"Bean context must contain at least one bean of type CasPasswordHandler");
}
String beanName = (String) beans.keySet().iterator().next();
handler = (CasPasswordHandler) beans.get(beanName);
}
return handler.authenticate(request, username, password);
}
/**
* Allows test cases to override where application context obtained from.
*
* @param httpRequest which can be used to find the <code>ServletContext</code>
*
* @return the Spring application context
*/
protected ApplicationContext getContext(HttpServletRequest httpRequest) {
return WebApplicationContextUtils.getRequiredWebApplicationContext(httpRequest.getSession().getServletContext());
}
}
@@ -0,0 +1,7 @@
<html>
<body>
Adapter to Yale Central Authentication Service (CAS).
<p>
</body>
</html>
@@ -0,0 +1,91 @@
/* 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.acegisecurity.adapters.cas3;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.cas.authentication.handler.AuthenticationException;
import org.jasig.cas.authentication.handler.AuthenticationHandler;
import org.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;
import org.springframework.util.Assert;
/**
* <p>Provides JA-SIG CAS 3 authentication by delegating to the Acegi <code>AuthenticationManager</code>.</p>
* <p>This class would be configured in the <code>webapp/WEB-INF/deployerConfigContext.xml</code> file in the CAS
* distribution.</p>
*
* @author Scott Battaglia
* @version $Id$
*
* @see AuthenticationHandler
* @see AuthenticationManager
*/
public final class CasAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {
//~ Instance fields ================================================================================================
private AuthenticationManager authenticationManager;
private Log log = LogFactory.getLog(this.getClass());
//~ Methods ========================================================================================================
protected void afterPropertiesSetInternal() throws Exception {
Assert.notNull(this.authenticationManager, "authenticationManager cannot be null.");
}
protected boolean authenticateUsernamePasswordInternal(final UsernamePasswordCredentials credentials)
throws AuthenticationException {
final Authentication authenticationRequest = new UsernamePasswordAuthenticationToken(credentials.getUsername(),
credentials.getPassword());
if (log.isDebugEnabled()) {
log.debug("Attempting to authenticate for user: " + credentials.getUsername());
}
try {
this.authenticationManager.authenticate(authenticationRequest);
} catch (final org.acegisecurity.AuthenticationException e) {
if (log.isDebugEnabled()) {
log.debug("Authentication request for " + credentials.getUsername() + " failed: " + e.toString(), e);
}
return false;
}
if (log.isDebugEnabled()) {
log.debug("Authentication request for " + credentials.getUsername() + " successful.");
}
return true;
}
/**
* Method to set the Acegi <code>AuthenticationManager</code> to delegate to.
*
* @param authenticationManager the Acegi AuthenticationManager that knows how to authenticate users.
*/
public void setAuthenticationManager(final AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
}
@@ -0,0 +1,53 @@
<?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.
*
* Demonstration of the applicationContext.xml that should be placed in
* CAS' WEB-INF directory. Note the CasPasswordHandler bean.
*
* $Id$
-->
<beans>
<!-- Data access object which stores authentication information -->
<bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
<property name="userMap">
<value>
marissa=koala,ROLES_IGNORED_BY_CAS
dianne=emu,ROLES_IGNORED_BY_CAS
scott=wombat,ROLES_IGNORED_BY_CAS
peter=opal,disabled,ROLES_IGNORED_BY_CAS
</value>
</property>
</bean>
<bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property>
</bean>
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref bean="daoAuthenticationProvider"/>
</list>
</property>
</bean>
<bean id="casPasswordHandler" class="org.acegisecurity.adapters.cas.CasPasswordHandler">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
</bean>
</beans>
@@ -0,0 +1,56 @@
<?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.
*
* Demonstration of the applicationContext.xml that should be copied into
* JA-SIG CAS's webapp/WEB-INF/deployerConfigContext.xml
* The example CAS AuthenticationHandler should be placed within CAS's
* AuthenticationManager's authenticationHandler list property.
*
* The Acegi-specific beans can just be placed in the context file.
*
* $Id$
-->
<beans>
<!-- Data access object which stores authentication information -->
<bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
<property name="userMap">
<value>
marissa=koala,ROLES_IGNORED_BY_CAS
dianne=emu,ROLES_IGNORED_BY_CAS
scott=wombat,ROLES_IGNORED_BY_CAS
peter=opal,disabled,ROLES_IGNORED_BY_CAS
</value>
</property>
</bean>
<bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property>
</bean>
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref bean="daoAuthenticationProvider"/>
</list>
</property>
</bean>
<bean id="casAuthenticationHandler" class="org.acegisecurity.adapters.cas3.CasAuthenticationHandler">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
</beans>
+11
View File
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="Acegi Security CAS Adapter">
<body>
<menu ref="parent"/>
<menu ref="reports"/>
</body>
</project>
@@ -0,0 +1,107 @@
/* 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.acegisecurity.adapters.cas;
import junit.framework.TestCase;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.mock.web.MockHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
/**
* Tests {@link CasPasswordHandlerProxy}.
*
* @author Ben Alex
* @version $Id$
*/
public class CasPasswordHandlerProxyTests extends TestCase {
//~ Constructors ===================================================================================================
public CasPasswordHandlerProxyTests() {
super();
}
public CasPasswordHandlerProxyTests(String arg0) {
super(arg0);
}
//~ Methods ========================================================================================================
public static void main(String[] args) {
junit.textui.TestRunner.run(CasPasswordHandlerProxyTests.class);
}
public final void setUp() throws Exception {
super.setUp();
}
public void testDetectsIfHttpServletRequestNotPassed() {
CasPasswordHandlerProxy proxy = new MockCasPasswordHandlerProxy(
"org/acegisecurity/adapters/cas/applicationContext-valid.xml");
try {
proxy.authenticate(null, "x", "y");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("Can only process HttpServletRequest", expected.getMessage());
}
}
public void testDetectsMissingDelegate() {
CasPasswordHandlerProxy proxy = new MockCasPasswordHandlerProxy(
"org/acegisecurity/adapters/cas/applicationContext-invalid.xml");
try {
proxy.authenticate(new MockHttpServletRequest(), "x", "y");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("Bean context must contain at least one bean of type CasPasswordHandler", expected.getMessage());
}
}
public void testNormalOperation() {
CasPasswordHandlerProxy proxy = new MockCasPasswordHandlerProxy(
"org/acegisecurity/adapters/cas/applicationContext-valid.xml");
assertTrue(proxy.authenticate(new MockHttpServletRequest(), "marissa", "koala"));
assertFalse(proxy.authenticate(new MockHttpServletRequest(), "marissa", "WRONG_PASSWORD"));
assertFalse(proxy.authenticate(new MockHttpServletRequest(), "INVALID_USER_NAME", "WRONG_PASSWORD"));
}
//~ Inner Classes ==================================================================================================
/**
* Mock object so that application context source can be specified.
*/
private class MockCasPasswordHandlerProxy extends CasPasswordHandlerProxy {
private ApplicationContext ctx;
public MockCasPasswordHandlerProxy(String appContextLocation) {
ctx = new ClassPathXmlApplicationContext(appContextLocation);
}
private MockCasPasswordHandlerProxy() {
super();
}
protected ApplicationContext getContext(HttpServletRequest httpRequest) {
return ctx;
}
}
}
@@ -0,0 +1,101 @@
/* 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.acegisecurity.adapters.cas;
import junit.framework.TestCase;
import org.acegisecurity.MockAuthenticationManager;
import org.springframework.mock.web.MockHttpServletRequest;
/**
* Tests {@link CasPasswordHandler}.
*
* @author Ben Alex
* @version $Id$
*/
public class CasPasswordHandlerTests extends TestCase {
//~ Constructors ===================================================================================================
public CasPasswordHandlerTests() {
super();
}
public CasPasswordHandlerTests(String arg0) {
super(arg0);
}
//~ Methods ========================================================================================================
public static void main(String[] args) {
junit.textui.TestRunner.run(CasPasswordHandlerTests.class);
}
public final void setUp() throws Exception {
super.setUp();
}
public void testDeniesAccessWhenAuthenticationManagerThrowsException()
throws Exception {
CasPasswordHandler handler = new CasPasswordHandler();
handler.setAuthenticationManager(new MockAuthenticationManager(false));
handler.afterPropertiesSet();
assertFalse(handler.authenticate(new MockHttpServletRequest(), "username", "password"));
}
public void testDetectsEmptyAuthenticationManager()
throws Exception {
CasPasswordHandler handler = new CasPasswordHandler();
try {
handler.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("An AuthenticationManager is required", expected.getMessage());
}
}
public void testGettersSetters() {
CasPasswordHandler handler = new CasPasswordHandler();
handler.setAuthenticationManager(new MockAuthenticationManager(false));
assertTrue(handler.getAuthenticationManager() != null);
}
public void testGracefullyHandlesEmptyUsernamesAndPassword()
throws Exception {
CasPasswordHandler handler = new CasPasswordHandler();
handler.setAuthenticationManager(new MockAuthenticationManager(true));
handler.afterPropertiesSet();
// If empty or null username we return false
assertFalse(handler.authenticate(new MockHttpServletRequest(), "", "password"));
assertFalse(handler.authenticate(new MockHttpServletRequest(), null, "password"));
// We authenticate with null passwords (they might not have one)
assertTrue(handler.authenticate(new MockHttpServletRequest(), "user", null));
assertTrue(handler.authenticate(new MockHttpServletRequest(), "user", ""));
}
public void testNormalOperation() throws Exception {
CasPasswordHandler handler = new CasPasswordHandler();
handler.setAuthenticationManager(new MockAuthenticationManager(true));
handler.afterPropertiesSet();
assertTrue(handler.authenticate(new MockHttpServletRequest(), "username", "password"));
}
}
@@ -0,0 +1,97 @@
/* 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.acegisecurity.adapters.cas3;
import org.acegisecurity.AuthenticationManager;
import org.jasig.cas.authentication.handler.AuthenticationException;
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
/**
* Tests {@link CasAuthenticationHandler}
*
* @author Scott Battaglia
* @version $Id$
*/
public class CasAuthenticationHandlerTests extends AbstractDependencyInjectionSpringContextTests {
//~ Instance fields ================================================================================================
private AuthenticationManager authenticationManager;
private CasAuthenticationHandler casAuthenticationHandler;
//~ Methods ========================================================================================================
protected String[] getConfigLocations() {
return new String[] {"/org/acegisecurity/adapters/cas/applicationContext-valid.xml"};
}
private UsernamePasswordCredentials getCredentialsFor(final String username, final String password) {
final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials();
credentials.setUsername(username);
credentials.setPassword(password);
return credentials;
}
protected void onSetUp() throws Exception {
this.casAuthenticationHandler = new CasAuthenticationHandler();
this.casAuthenticationHandler.setAuthenticationManager(authenticationManager);
this.casAuthenticationHandler.afterPropertiesSet();
}
public void setAuthenticationManager(final AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
public void testAfterPropertiesSet() throws Exception {
this.casAuthenticationHandler.setAuthenticationManager(null);
try {
this.casAuthenticationHandler.afterPropertiesSet();
fail("IllegalArgumenException expected when no AuthenticationManager is set.");
} catch (final IllegalArgumentException e) {
// this is okay
}
}
public void testGracefullyHandlesInvalidInput() {
try {
assertFalse(this.casAuthenticationHandler.authenticate(getCredentialsFor("", "")));
assertFalse(this.casAuthenticationHandler.authenticate(getCredentialsFor(null, null)));
} catch (final AuthenticationException e) {
fail("AuthenticationException not expected.");
}
}
public void testInvalidUsernamePasswordCombination() {
try {
assertFalse(this.casAuthenticationHandler.authenticate(getCredentialsFor("scott", "scott")));
} catch (final AuthenticationException e) {
fail("AuthenticationException not expected.");
}
}
public void testValidUsernamePasswordCombination() {
try {
assertTrue(this.casAuthenticationHandler.authenticate(getCredentialsFor("scott", "wombat")));
} catch (final AuthenticationException e) {
fail("AuthenticationException not expected.");
}
}
}
@@ -0,0 +1,47 @@
<?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>
<bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
<property name="userMap">
<value>
marissa=koala,ROLE_TELLER,ROLE_SUPERVISOR
dianne=emu,ROLE_TELLER
scott=wombat,ROLE_TELLER
peter=opal,disabled,ROLE_TELLER
</value>
</property>
</bean>
<bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property>
</bean>
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref bean="daoAuthenticationProvider"/>
</list>
</property>
</bean>
<!-- No CasPasswordHandler -->
</beans>
@@ -0,0 +1,49 @@
<?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>
<bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
<property name="userMap">
<value>
marissa=koala,ROLE_TELLER,ROLE_SUPERVISOR
dianne=emu,ROLE_TELLER
scott=wombat,ROLE_TELLER
peter=opal,disabled,ROLE_TELLER
</value>
</property>
</bean>
<bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property>
</bean>
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref bean="daoAuthenticationProvider"/>
</list>
</property>
</bean>
<bean id="casPasswordHandler" class="org.acegisecurity.adapters.cas.CasPasswordHandler">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
</bean>
</beans>
+5
View File
@@ -0,0 +1,5 @@
target
.settings
.classpath
.project
.wtpmodules
+17
View File
@@ -0,0 +1,17 @@
<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.acegisecurity</groupId>
<artifactId>acegi-security-adapters</artifactId>
<version>1.0.7</version>
</parent>
<artifactId>acegi-security-catalina</artifactId>
<name>Acegi Security System for Spring - Catalina adapter</name>
<dependencies>
<dependency>
<groupId>tomcat</groupId>
<artifactId>catalina</artifactId>
<version>4.1.9</version>
</dependency>
</dependencies>
</project>
@@ -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.acegisecurity.adapters.catalina;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.adapters.PrincipalAcegiUserToken;
import org.acegisecurity.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 Acegi Security System for Spring.<p>Returns a {@link
* PrincipalAcegiUserToken} to Catalina's authentication system, which is subsequently available via
* <code>HttpServletRequest.getUserPrincipal()</code>.</p>
*
* @author Ben Alex
* @version $Id$
*/
public class CatalinaAcegiUserRealm extends RealmBase {
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(CatalinaAcegiUserRealm.class);
//~ Instance fields ================================================================================================
private AuthenticationManager authenticationManager;
private Container container;
private String appContextLocation;
private String key;
protected final String name = "CatalinaSpringUserRealm / $Id$";
//~ 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 PrincipalAcegiUserToken(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 PrincipalAcegiUserToken)) {
logger.warn("Expected passed principal to be of type PrincipalAcegiUserToken but was "
+ principal.getClass().getName());
return false;
}
PrincipalAcegiUserToken test = (PrincipalAcegiUserToken) 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("CatalinaAcegiUserRealm 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);
}
}
@@ -0,0 +1,7 @@
<html>
<body>
Adapter to Catalina web container (Tomcat).
<p>
</body>
</html>
@@ -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.acegisecurity.userdetails.memory.InMemoryDaoImpl">
<property name="userMap">
<value>
marissa=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>
@@ -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.acegisecurity.userdetails.memory.InMemoryDaoImpl">
<property name="userMap">
<value>
marissa=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.acegisecurity.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.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref bean="daoAuthenticationProvider"/>
</list>
</property>
</bean>
</beans>
@@ -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.acegisecurity.adapters.catalina;
import junit.framework.TestCase;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.adapters.PrincipalAcegiUserToken;
import org.apache.catalina.LifecycleException;
import java.io.File;
import java.net.URL;
import java.security.Principal;
/**
* Tests {@link CatalinaAcegiUserRealm}.
*
* @author Ben Alex
* @version $Id$
*/
public class CatalinaAcegiUserRealmTests extends TestCase {
//~ Instance fields ================================================================================================
private final String ADAPTER_KEY = "my_key";
//~ Constructors ===================================================================================================
public CatalinaAcegiUserRealmTests() {
super();
}
public CatalinaAcegiUserRealmTests(String arg0) {
super(arg0);
}
//~ Methods ========================================================================================================
public static void main(String[] args) {
junit.textui.TestRunner.run(CatalinaAcegiUserRealmTests.class);
}
private CatalinaAcegiUserRealm makeAdapter(String fileName)
throws Exception {
CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
URL url = Thread.currentThread().getContextClassLoader().getResource("org/acegisecurity/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 {
CatalinaAcegiUserRealm adapter = makeAdapter("catalinaAdapterTest-invalid.xml");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
}
public void testAdapterAbortsIfNoAppContextSpecified()
throws Exception {
CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
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 {
CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
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 {
CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
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 {
CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
assertTrue(adapter.getName().lastIndexOf("CatalinaSpringUserRealm") != -1);
}
public void testAdapterStartsUpSuccess() throws Exception {
CatalinaAcegiUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
assertTrue(true);
}
public void testAuthenticateManyParamsReturnsNull() {
CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
assertEquals(null, adapter.authenticate(null, null, null, null, null, null, null, null));
}
public void testAuthenticateX509ReturnsNull() {
CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
assertEquals(null, adapter.authenticate(null));
}
public void testAuthenticationFailsForIncorrectPassword()
throws Exception {
CatalinaAcegiUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
assertEquals(null, adapter.authenticate("marissa", "kangaroo"));
}
public void testAuthenticationFailsForIncorrectUserName()
throws Exception {
CatalinaAcegiUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
assertEquals(null, adapter.authenticate("melissa", "koala"));
}
public void testAuthenticationUsingByteArrayForCredentials()
throws Exception {
CatalinaAcegiUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
byte[] credentials = {'k', 'o', 'a', 'l', 'a'};
Principal result = adapter.authenticate("marissa", credentials);
if (!(result instanceof PrincipalAcegiUserToken)) {
fail("Should have returned PrincipalAcegiUserToken");
}
PrincipalAcegiUserToken castResult = (PrincipalAcegiUserToken) result;
assertEquals("marissa", castResult.getPrincipal());
assertEquals("koala", castResult.getCredentials());
assertEquals("ROLE_TELLER", castResult.getAuthorities()[0].getAuthority());
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[1].getAuthority());
assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
}
public void testAuthenticationUsingStringForCredentials()
throws Exception {
CatalinaAcegiUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
Principal result = adapter.authenticate("marissa", "koala");
if (!(result instanceof PrincipalAcegiUserToken)) {
fail("Should have returned PrincipalAcegiUserToken");
}
PrincipalAcegiUserToken castResult = (PrincipalAcegiUserToken) result;
assertEquals("marissa", castResult.getPrincipal());
assertEquals("koala", castResult.getCredentials());
assertEquals("ROLE_TELLER", castResult.getAuthorities()[0].getAuthority());
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[1].getAuthority());
assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
}
public void testAuthenticationWithNullPasswordHandledGracefully()
throws Exception {
CatalinaAcegiUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
assertEquals(null, adapter.authenticate("marissa", (String) null));
}
public void testAuthenticationWithNullUserNameHandledGracefully()
throws Exception {
CatalinaAcegiUserRealm adapter = makeAdapter("catalinaAdapterTest-valid.xml");
assertEquals(null, adapter.authenticate(null, "koala"));
}
public void testGetPasswordReturnsNull() {
CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
assertEquals(null, adapter.getPassword(null));
}
public void testGetPrincipalReturnsNull() {
CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
assertEquals(null, adapter.getPrincipal(null));
}
public void testGetters() {
CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
adapter.setKey("KEY");
assertEquals("KEY", adapter.getKey());
adapter.setAppContextLocation("SOME_LOCATION");
assertEquals("SOME_LOCATION", adapter.getAppContextLocation());
}
public void testHasRoleWithANullPrincipalFails() {
CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
assertTrue(!adapter.hasRole(null, "ROLE_ONE"));
}
public void testHasRoleWithAPrincipalTheAdapterDidNotCreateFails() {
CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
assertTrue(!adapter.hasRole(new Principal() {
public String getName() {
return "MockPrincipal";
}
}, "ROLE_ONE"));
}
public void testHasRoleWithPrincipalAcegiUserToken() {
PrincipalAcegiUserToken token = new PrincipalAcegiUserToken("KEY", "Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO")},
null);
CatalinaAcegiUserRealm adapter = new CatalinaAcegiUserRealm();
assertTrue(adapter.hasRole(token, "ROLE_ONE"));
assertTrue(adapter.hasRole(token, "ROLE_TWO"));
assertTrue(!adapter.hasRole(token, "ROLE_WE_DO_NOT_HAVE"));
}
}
+5
View File
@@ -0,0 +1,5 @@
target
.settings
.classpath
.project
.wtpmodules
+23
View File
@@ -0,0 +1,23 @@
<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.acegisecurity</groupId>
<artifactId>acegi-security-adapters</artifactId>
<version>1.0.7</version>
</parent>
<artifactId>acegi-security-jboss</artifactId>
<name>Acegi Security System for Spring - 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>
<version>2.3</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
@@ -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.acegisecurity.adapters.jboss;
import org.acegisecurity.AccountExpiredException;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.CredentialsExpiredException;
import org.acegisecurity.adapters.PrincipalAcegiUserToken;
import org.acegisecurity.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 Acegi Security System for Spring.<p>Returns a {@link
* PrincipalAcegiUserToken} 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$
*/
public class JbossAcegiLoginModule 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 PrincipalAcegiUserToken(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,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.acegisecurity.adapters.jboss;
import org.acegisecurity.Authentication;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.context.HttpSessionContextIntegrationFilter;
import org.acegisecurity.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 {}
}
@@ -0,0 +1,7 @@
<html>
<body>
Adapter to JBoss.
<p>
</body>
</html>
@@ -0,0 +1,358 @@
/* 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.acegisecurity.adapters.jboss;
import junit.framework.TestCase;
import org.acegisecurity.adapters.PrincipalAcegiUserToken;
import org.jboss.security.SimplePrincipal;
import org.jboss.security.SimpleGroup;
import java.io.IOException;
import java.security.Principal;
import java.security.acl.Group;
import java.util.Properties;
import java.util.Enumeration;
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 JbossAcegiLoginModule}.
*
* @author Ben Alex
* @version $Id$
*/
public class JbossAcegiLoginModuleTests extends TestCase {
//~ Instance fields ================================================================================================
private final String ADAPTER_KEY = "my_key";
//~ Constructors ===================================================================================================
public JbossAcegiLoginModuleTests() {
super();
}
public JbossAcegiLoginModuleTests(String arg0) {
super(arg0);
}
//~ Methods ========================================================================================================
public static void main(String[] args) {
junit.textui.TestRunner.run(JbossAcegiLoginModuleTests.class);
}
public final void setUp() throws Exception {
super.setUp();
}
public void testAdapterAbortsIfAppContextDoesNotContainAnAuthenticationBean()
throws Exception {
JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
Properties props = new Properties();
props.put("key", ADAPTER_KEY);
props.put("appContextLocation", "org/acegisecurity/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 {
JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
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 {
JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
Properties props = new Properties();
props.put("appContextLocation", "org/acegisecurity/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/acegisecurity/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 {
JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
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 {
JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
Properties props = new Properties();
props.put("key", ADAPTER_KEY);
props.put("appContextLocation", "org/acegisecurity/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 {
JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
Properties props = new Properties();
props.put("key", ADAPTER_KEY);
props.put("appContextLocation", "org/acegisecurity/adapters/adaptertest-valid.xml");
adapter.initialize(null, null, null, props);
assertTrue(true);
}
public void testAuthenticationFailsForIncorrectPassword()
throws Exception {
JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
Properties props = new Properties();
props.put("key", ADAPTER_KEY);
props.put("appContextLocation", "org/acegisecurity/adapters/adaptertest-valid.xml");
Subject subject = new Subject();
CallbackHandler callback = new MockCallbackHandler("marissa", "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 {
JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
Properties props = new Properties();
props.put("key", ADAPTER_KEY);
props.put("appContextLocation", "org/acegisecurity/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 {
JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
Properties props = new Properties();
props.put("key", ADAPTER_KEY);
props.put("appContextLocation", "org/acegisecurity/adapters/adaptertest-valid.xml");
Subject subject = new Subject();
CallbackHandler callback = new MockCallbackHandler("marissa", "koala");
adapter.initialize(subject, callback, null, props);
assertTrue(adapter.login());
Principal result = adapter.getIdentity();
if (!(result instanceof PrincipalAcegiUserToken)) {
fail("Should have returned PrincipalAcegiUserToken");
}
PrincipalAcegiUserToken castResult = (PrincipalAcegiUserToken) result;
assertEquals("marissa", castResult.getPrincipal());
assertEquals("koala", castResult.getCredentials());
assertEquals("ROLE_TELLER", castResult.getAuthorities()[0].getAuthority());
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[1].getAuthority());
assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
}
public void testAuthenticationWithNullPasswordHandledGracefully()
throws Exception {
JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
Properties props = new Properties();
props.put("key", ADAPTER_KEY);
props.put("appContextLocation", "org/acegisecurity/adapters/adaptertest-valid.xml");
Subject subject = new Subject();
CallbackHandler callback = new MockCallbackHandler("marissa", 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 {
JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
Properties props = new Properties();
props.put("key", ADAPTER_KEY);
props.put("appContextLocation", "org/acegisecurity/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 {
JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
Properties props = new Properties();
props.put("key", ADAPTER_KEY);
props.put("appContextLocation", "org/acegisecurity/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 {
JbossAcegiLoginModule adapter = new JbossAcegiLoginModule();
Properties props = new Properties();
props.put("key", ADAPTER_KEY);
props.put("appContextLocation", "org/acegisecurity/adapters/adaptertest-valid.xml");
Subject subject = new Subject();
CallbackHandler callback = new MockCallbackHandler("marissa", "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]);
}
}
}
}
}
@@ -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.acegisecurity.adapters.jboss;
import junit.framework.TestCase;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.adapters.PrincipalAcegiUserToken;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.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$
*/
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 {
PrincipalAcegiUserToken principal = new PrincipalAcegiUserToken("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 {}
}
}
@@ -0,0 +1,171 @@
/* 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.acegisecurity.adapters.jboss;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NameParser;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
/**
* Mocks a <code>javax.naming.Context</code> and returns an <code>Object</code> when queried for address
* <code>java:comp/env/security/subject</code>.
*
* @author Ben Alex
* @version $Id$
*/
public class MockInitialContext implements Context {
//~ Instance fields ================================================================================================
private Object object;
//~ Constructors ===================================================================================================
public MockInitialContext(Object object) {
this.object = object;
}
private MockInitialContext() {
super();
}
//~ Methods ========================================================================================================
public Object addToEnvironment(String propName, Object propVal)
throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public void bind(String name, Object obj) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public void bind(Name name, Object obj) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public void close() throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public String composeName(String name, String prefix)
throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public Name composeName(Name name, Name prefix) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public Context createSubcontext(String name) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public Context createSubcontext(Name name) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public void destroySubcontext(String name) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public void destroySubcontext(Name name) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public Hashtable getEnvironment() throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public String getNameInNamespace() throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public NameParser getNameParser(String name) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public NameParser getNameParser(Name name) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public NamingEnumeration list(String name) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public NamingEnumeration list(Name name) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public NamingEnumeration listBindings(String name)
throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public NamingEnumeration listBindings(Name name) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public Object lookup(String name) throws NamingException {
return this.object;
}
public Object lookup(Name name) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public Object lookupLink(String name) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public Object lookupLink(Name name) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public void rebind(String name, Object obj) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public void rebind(Name name, Object obj) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public Object removeFromEnvironment(String propName)
throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public void rename(String oldName, String newName)
throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public void rename(Name oldName, Name newName) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public void unbind(String name) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
public void unbind(Name name) throws NamingException {
throw new UnsupportedOperationException("mock method not implemented");
}
}
@@ -0,0 +1,49 @@
/* 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.acegisecurity.adapters.jboss;
import javax.naming.Context;
import javax.naming.NamingException;
/**
* Provides mock of <code>JbossIntegrationFilter</code>, using a lookup <code>Context</code> provided in the
* constructor.
*
* @author Ben Alex
* @version $Id$
*/
public class MockJbossIntegrationFilter extends JbossIntegrationFilter {
//~ Instance fields ================================================================================================
private Context context;
//~ Constructors ===================================================================================================
public MockJbossIntegrationFilter(Context context) {
this.context = context;
}
private MockJbossIntegrationFilter() {
super();
}
//~ Methods ========================================================================================================
protected Context getLookupContext() throws NamingException {
return this.context;
}
}
+5
View File
@@ -0,0 +1,5 @@
target
.settings
.classpath
.project
.wtpmodules
+17
View File
@@ -0,0 +1,17 @@
<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.acegisecurity</groupId>
<artifactId>acegi-security-adapters</artifactId>
<version>1.0.7</version>
</parent>
<artifactId>acegi-security-jetty</artifactId>
<name>Acegi Security System for Spring - Jetty adapter</name>
<dependencies>
<dependency>
<groupId>jetty</groupId>
<artifactId>org.mortbay.jetty</artifactId>
<version>4.2.22</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,161 @@
/* 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.acegisecurity.adapters.jetty;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mortbay.http.HttpRequest;
import org.mortbay.http.UserPrincipal;
import org.mortbay.http.UserRealm;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Map;
/**
* Adapter to enable Jetty to authenticate via the Acegi Security System for Spring.<p>Returns a {@link
* JettyAcegiUserToken} to Jetty's authentication system, which is subsequently available via
* <code>HttpServletRequest.getUserPrincipal()</code>.</p>
*
* @author Ben Alex
* @version $Id$
*/
public final class JettyAcegiUserRealm implements UserRealm {
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(JettyAcegiUserRealm.class);
//~ Instance fields ================================================================================================
private AuthenticationManager authenticationManager;
private String key;
private String realm;
//~ Constructors ===================================================================================================
/**
* Construct a <code>SpringUserRealm</code>.
*
* @param realm the name of the authentication realm (within Jetty)
* @param providerKey a password to sign all authentication objects
* @param appContextLocation the classpath location of the bean context XML
* file
*
* @throws IllegalArgumentException DOCUMENT ME!
*/
public JettyAcegiUserRealm(String realm, String providerKey, String appContextLocation) {
this.realm = realm;
this.key = providerKey;
if ((realm == null) || "".equals(realm)) {
throw new IllegalArgumentException("realm must be specified");
}
if ((key == null) || "".equals(key)) {
throw new IllegalArgumentException("key must be specified");
}
if ((appContextLocation == null) || "".equals(appContextLocation)) {
throw new IllegalArgumentException("appContextLocation must be specified");
}
if (Thread.currentThread().getContextClassLoader().getResource(appContextLocation) == null) {
throw new IllegalArgumentException("Cannot locate " + appContextLocation);
}
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(appContextLocation);
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);
}
protected JettyAcegiUserRealm() {
throw new IllegalArgumentException("Cannot use default constructor");
}
//~ Methods ========================================================================================================
public UserPrincipal authenticate(String username, Object password, HttpRequest httpRequest) {
if (username == null) {
return null;
}
if (password == null) {
password = "";
}
Authentication request = new UsernamePasswordAuthenticationToken(username.toString(), password.toString());
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 JettyAcegiUserToken(this.key, response.getPrincipal().toString(),
response.getCredentials().toString(), response.getAuthorities());
}
public void disassociate(UserPrincipal userPrincipal) {
// No action required
}
public AuthenticationManager getAuthenticationManager() {
return authenticationManager;
}
/**
* Accesses the realm name.
*
* @return the name of the realm as defined when <code>SpringUserRealm</code> was created
*/
public String getName() {
return this.realm;
}
public void logout(UserPrincipal arg0) {
// Not supported
}
public UserPrincipal popRole(UserPrincipal userPrincipal) {
// Not supported
return userPrincipal;
}
public UserPrincipal pushRole(UserPrincipal userPrincipal, String role) {
// Not supported
return userPrincipal;
}
}
@@ -0,0 +1,63 @@
/* 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.acegisecurity.adapters.jetty;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.adapters.AbstractAdapterAuthenticationToken;
import org.mortbay.http.UserPrincipal;
/**
* A Jetty compatible {@link org.acegisecurity.Authentication} object.
*
* @author Ben Alex
* @version $Id$
*/
public class JettyAcegiUserToken extends AbstractAdapterAuthenticationToken implements UserPrincipal {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private String password;
private String username;
//~ Constructors ===================================================================================================
public JettyAcegiUserToken(String key, String username, String password, GrantedAuthority[] authorities) {
super(key, authorities);
this.username = username;
this.password = password;
}
protected JettyAcegiUserToken() {
throw new IllegalArgumentException("Cannot use default constructor");
}
//~ Methods ========================================================================================================
public Object getCredentials() {
return this.password;
}
public String getName() {
return this.username;
}
public Object getPrincipal() {
return this.username;
}
}
@@ -0,0 +1,7 @@
<html>
<body>
Adapter to Jetty web container.
<p>
</body>
</html>
@@ -0,0 +1,237 @@
/* 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.acegisecurity.adapters.jetty;
import junit.framework.TestCase;
import org.mortbay.http.UserPrincipal;
/**
* Tests {@link JettyAcegiUserRealm}.
*
* @author Ben Alex
* @version $Id$
*/
public class JettyAcegiUserRealmTests extends TestCase {
//~ Instance fields ================================================================================================
private final String ADAPTER_KEY = "my_key";
private final String REALM_NAME = "Acegi Powered Realm";
//~ Constructors ===================================================================================================
public JettyAcegiUserRealmTests() {
super();
}
public JettyAcegiUserRealmTests(String arg0) {
super(arg0);
}
//~ Methods ========================================================================================================
public static void main(String[] args) {
junit.textui.TestRunner.run(JettyAcegiUserRealmTests.class);
}
private JettyAcegiUserRealm makeAdapter(String fileName)
throws Exception {
String useFile = "org/acegisecurity/adapters/" + fileName;
return new JettyAcegiUserRealm(REALM_NAME, ADAPTER_KEY, useFile);
}
public final void setUp() throws Exception {
super.setUp();
}
public void testAdapterAbortsIfAppContextDoesNotContainAnAuthenticationBean()
throws Exception {
try {
JettyAcegiUserRealm adapter = makeAdapter("adaptertest-invalid.xml");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("Bean context must contain at least one bean of type AuthenticationManager",
expected.getMessage());
}
}
public void testAdapterAbortsIfNoAppContextSpecified()
throws Exception {
try {
new JettyAcegiUserRealm(REALM_NAME, ADAPTER_KEY, null);
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("appContextLocation must be specified", expected.getMessage());
}
try {
new JettyAcegiUserRealm(REALM_NAME, ADAPTER_KEY, "");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("appContextLocation must be specified", expected.getMessage());
}
}
public void testAdapterAbortsIfNoKeySpecified() throws Exception {
try {
new JettyAcegiUserRealm(REALM_NAME, null, "SOME_PATH");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("key must be specified", expected.getMessage());
}
try {
new JettyAcegiUserRealm(REALM_NAME, "", "SOME_PATH");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("key must be specified", expected.getMessage());
}
}
public void testAdapterAbortsIfNoRealmNameSpecified()
throws Exception {
try {
new JettyAcegiUserRealm(null, ADAPTER_KEY, "SOME_PATH");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("realm must be specified", expected.getMessage());
}
try {
new JettyAcegiUserRealm(null, ADAPTER_KEY, "SOME_PATH");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("realm must be specified", expected.getMessage());
}
}
public void testAdapterAbortsWithIncorrectApplicationContextLocation()
throws Exception {
try {
new JettyAcegiUserRealm(REALM_NAME, ADAPTER_KEY, "SOME_INVALID_LOCATION");
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(expected.getMessage().startsWith("Cannot locate"));
}
}
public void testAdapterIdentifiesTheRealmItManages()
throws Exception {
JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
assertEquals(REALM_NAME, adapter.getName());
}
public void testAdapterStartsUpSuccess() throws Exception {
JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
assertTrue(true);
}
public void testAuthenticationFailsForIncorrectPassword()
throws Exception {
JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
assertEquals(null, adapter.authenticate("marissa", "kangaroo", null));
}
public void testAuthenticationFailsForIncorrectUserName()
throws Exception {
JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
assertEquals(null, adapter.authenticate("melissa", "koala", null));
}
public void testAuthenticationSuccess() throws Exception {
JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
UserPrincipal result = adapter.authenticate("marissa", "koala", null);
if (!(result instanceof JettyAcegiUserToken)) {
fail("Should have returned JettyAcegiUserToken");
}
JettyAcegiUserToken castResult = (JettyAcegiUserToken) result;
assertEquals("marissa", castResult.getPrincipal());
assertEquals("koala", castResult.getCredentials());
assertEquals("ROLE_TELLER", castResult.getAuthorities()[0].getAuthority());
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[1].getAuthority());
assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
}
public void testAuthenticationWithNullPasswordHandledGracefully()
throws Exception {
JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
assertEquals(null, adapter.authenticate("marissa", null, null));
}
public void testAuthenticationWithNullUserNameHandledGracefully()
throws Exception {
JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
assertEquals(null, adapter.authenticate(null, "koala", null));
}
public void testDisassociateImplemented() throws Exception {
JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
adapter.disassociate(new MockUserPrincipal());
assertTrue(true);
}
public void testGetAuthenticationManager() throws Exception {
JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
assertTrue(adapter.getAuthenticationManager() != null);
}
public void testLogoutImplemented() throws Exception {
JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
adapter.logout(new MockUserPrincipal());
assertTrue(true);
}
public void testNoArgsConstructor() {
try {
new JettyAcegiUserRealm();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
}
public void testPopRoleImplemented() throws Exception {
JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
MockUserPrincipal user = new MockUserPrincipal();
assertEquals(user, adapter.popRole(user));
}
public void testPushRoleImplemented() throws Exception {
JettyAcegiUserRealm adapter = makeAdapter("adaptertest-valid.xml");
MockUserPrincipal user = new MockUserPrincipal();
assertEquals(user, adapter.pushRole(user, "SOME_ROLE"));
}
//~ Inner Classes ==================================================================================================
private class MockUserPrincipal implements UserPrincipal {
public String getName() {
throw new UnsupportedOperationException("mock method not implemented");
}
public boolean isAuthenticated() {
throw new UnsupportedOperationException("mock method not implemented");
}
public boolean isUserInRole(String arg0) {
throw new UnsupportedOperationException("mock method not implemented");
}
}
}
@@ -0,0 +1,68 @@
/* 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.acegisecurity.adapters.jetty;
import junit.framework.TestCase;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
/**
* Tests {@link JettyAcegiUserToken}.
*
* @author Ben Alex
* @version $Id$
*/
public class JettyAcegiUserTokenTests extends TestCase {
//~ Constructors ===================================================================================================
public JettyAcegiUserTokenTests() {
super();
}
public JettyAcegiUserTokenTests(String arg0) {
super(arg0);
}
//~ Methods ========================================================================================================
public static void main(String[] args) {
junit.textui.TestRunner.run(JettyAcegiUserTokenTests.class);
}
public final void setUp() throws Exception {
super.setUp();
}
public void testGetters() throws Exception {
JettyAcegiUserToken token = new JettyAcegiUserToken("my_password", "Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO")});
assertEquals("Test", token.getPrincipal());
assertEquals("Password", token.getCredentials());
assertEquals("my_password".hashCode(), token.getKeyHash());
assertEquals("Test", token.getName());
}
public void testNoArgsConstructor() {
try {
new JettyAcegiUserToken();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
}
}
+30
View File
@@ -0,0 +1,30 @@
<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.acegisecurity</groupId>
<artifactId>acegi-security-parent</artifactId>
<version>1.0.7</version>
</parent>
<artifactId>acegi-security-adapters</artifactId>
<name>Acegi Security System for Spring - Adapters</name>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-mock</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<modules>
<module>cas</module>
<module>catalina</module>
<module>jboss</module>
<module>jetty</module>
<module>resin</module>
</modules>
</project>
+5
View File
@@ -0,0 +1,5 @@
target
.settings
.classpath
.project
.wtpmodules
+23
View File
@@ -0,0 +1,23 @@
<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.acegisecurity</groupId>
<artifactId>acegi-security-adapters</artifactId>
<version>1.0.7</version>
</parent>
<artifactId>acegi-security-resin</artifactId>
<name>Acegi Security System for Spring - Resin adapter</name>
<dependencies>
<dependency>
<groupId>com.caucho</groupId>
<artifactId>resin</artifactId>
<version>3.0.9</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.3</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,152 @@
/* 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.acegisecurity.adapters.resin;
import com.caucho.http.security.AbstractAuthenticator;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.adapters.PrincipalAcegiUserToken;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.security.Principal;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Adapter to enable Resin to authenticate via the Acegi Security System for Spring.<p>Returns a {@link
* PrincipalAcegiUserToken} to Resin's authentication system, which is subsequently available via
* <code>HttpServletRequest.getUserPrincipal()</code>.</p>
*
* @author Ben Alex
* @version $Id$
*/
public class ResinAcegiAuthenticator extends AbstractAuthenticator {
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(ResinAcegiAuthenticator.class);
//~ Instance fields ================================================================================================
private AuthenticationManager authenticationManager;
private String appContextLocation;
private String key;
//~ Methods ========================================================================================================
public String getAppContextLocation() {
return appContextLocation;
}
public String getKey() {
return key;
}
public void init() throws ServletException {
super.init();
if ((appContextLocation == null) || "".equals(appContextLocation)) {
throw new ServletException("appContextLocation must be defined");
}
if ((key == null) || "".equals(key)) {
throw new ServletException("key must be defined");
}
if (Thread.currentThread().getContextClassLoader().getResource(appContextLocation) == null) {
throw new ServletException("Cannot locate " + appContextLocation);
}
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(appContextLocation);
Map beans = ctx.getBeansOfType(AuthenticationManager.class, true, true);
if (beans.size() == 0) {
throw new ServletException("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("ResinAcegiAuthenticator Started");
}
public boolean isUserInRole(HttpServletRequest request, HttpServletResponse response, ServletContext application,
Principal principal, String role) {
if (!(principal instanceof PrincipalAcegiUserToken)) {
if (logger.isWarnEnabled()) {
logger.warn("Expected passed principal to be of type PrincipalAcegiUserToken");
}
return false;
}
PrincipalAcegiUserToken test = (PrincipalAcegiUserToken) principal;
return test.isUserInRole(role);
}
protected Principal loginImpl(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 PrincipalAcegiUserToken(this.key, response.getPrincipal().toString(),
response.getCredentials().toString(), response.getAuthorities(), response.getPrincipal());
}
protected Principal loginImpl(HttpServletRequest request, HttpServletResponse response, ServletContext application,
String userName, String password) throws ServletException {
return loginImpl(userName, password);
}
public void setAppContextLocation(String appContextLocation) {
this.appContextLocation = appContextLocation;
}
public void setKey(String key) {
this.key = key;
}
}
@@ -0,0 +1,7 @@
<html>
<body>
Adapter to Resin web container.
<p>
</body>
</html>
@@ -0,0 +1,261 @@
/* 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.acegisecurity.adapters.resin;
import junit.framework.TestCase;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.adapters.PrincipalAcegiUserToken;
import java.security.Principal;
import javax.servlet.ServletException;
/**
* Tests {@link ResinAcegiAuthenticator}.
*
* @author Ben Alex
* @version $Id$
*/
public class ResinAcegiAuthenticatorTests extends TestCase {
//~ Instance fields ================================================================================================
private final String ADAPTER_KEY = "my_key";
//~ Constructors ===================================================================================================
public ResinAcegiAuthenticatorTests() {
super();
}
public ResinAcegiAuthenticatorTests(String arg0) {
super(arg0);
}
//~ Methods ========================================================================================================
public static void main(String[] args) {
junit.textui.TestRunner.run(ResinAcegiAuthenticatorTests.class);
}
public final void setUp() throws Exception {
super.setUp();
}
public void testAdapterAbortsIfAppContextDoesNotContainAnAuthenticationBean()
throws Exception {
ResinAcegiAuthenticator adapter = new ResinAcegiAuthenticator();
adapter.setAppContextLocation("org/acegisecurity/adapters/adaptertest-invalid.xml");
adapter.setKey(ADAPTER_KEY);
try {
adapter.init();
fail("Should have thrown ServletException");
} catch (ServletException expected) {
assertEquals("Bean context must contain at least one bean of type AuthenticationManager",
expected.getMessage());
}
}
public void testAdapterAbortsIfNoAppContextSpecified()
throws Exception {
ResinAcegiAuthenticator adapter = new ResinAcegiAuthenticator();
adapter.setKey(ADAPTER_KEY);
try {
adapter.init();
fail("Should have thrown ServletException");
} catch (ServletException expected) {
assertEquals("appContextLocation must be defined", expected.getMessage());
}
adapter.setAppContextLocation("");
try {
adapter.init();
fail("Should have thrown ServletException");
} catch (ServletException expected) {
assertEquals("appContextLocation must be defined", expected.getMessage());
}
}
public void testAdapterAbortsIfNoKeySpecified() throws Exception {
ResinAcegiAuthenticator adapter = new ResinAcegiAuthenticator();
adapter.setAppContextLocation("org/acegisecurity/adapters/adaptertest-valid.xml");
try {
adapter.init();
fail("Should have thrown ServletException");
} catch (ServletException expected) {
assertEquals("key must be defined", expected.getMessage());
}
adapter.setKey("");
try {
adapter.init();
fail("Should have thrown ServletException");
} catch (ServletException expected) {
assertEquals("key must be defined", expected.getMessage());
}
}
public void testAdapterAbortsWithIncorrectApplicationContextLocation()
throws Exception {
ResinAcegiAuthenticator adapter = new ResinAcegiAuthenticator();
adapter.setAppContextLocation("FILE_DOES_NOT_EXIST");
adapter.setKey(ADAPTER_KEY);
try {
adapter.init();
fail("Should have thrown ServletException");
} catch (ServletException expected) {
assertTrue(expected.getMessage().startsWith("Cannot locate"));
}
}
public void testAdapterStartsUpSuccess() throws Exception {
ResinAcegiAuthenticator adapter = new ResinAcegiAuthenticator();
adapter.setAppContextLocation("org/acegisecurity/adapters/adaptertest-valid.xml");
adapter.setKey(ADAPTER_KEY);
adapter.init();
assertTrue(true);
}
public void testAuthenticationFailsForIncorrectPassword()
throws Exception {
ResinAcegiAuthenticator adapter = new ResinAcegiAuthenticator();
adapter.setAppContextLocation("org/acegisecurity/adapters/adaptertest-valid.xml");
adapter.setKey(ADAPTER_KEY);
adapter.init();
assertEquals(null, adapter.loginImpl("marissa", "kangaroo"));
}
public void testAuthenticationFailsForIncorrectUserName()
throws Exception {
ResinAcegiAuthenticator adapter = new ResinAcegiAuthenticator();
adapter.setAppContextLocation("org/acegisecurity/adapters/adaptertest-valid.xml");
adapter.setKey(ADAPTER_KEY);
adapter.init();
assertEquals(null, adapter.loginImpl("melissa", "koala"));
}
public void testAuthenticationSuccess() throws Exception {
ResinAcegiAuthenticator adapter = new ResinAcegiAuthenticator();
adapter.setAppContextLocation("org/acegisecurity/adapters/adaptertest-valid.xml");
adapter.setKey(ADAPTER_KEY);
adapter.init();
Principal result = adapter.loginImpl("marissa", "koala");
if (!(result instanceof PrincipalAcegiUserToken)) {
fail("Should have returned PrincipalAcegiUserToken");
}
PrincipalAcegiUserToken castResult = (PrincipalAcegiUserToken) result;
assertEquals("marissa", castResult.getPrincipal());
assertEquals("koala", castResult.getCredentials());
assertEquals("ROLE_TELLER", castResult.getAuthorities()[0].getAuthority());
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[1].getAuthority());
assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
}
public void testAuthenticationSuccessUsingAlternateMethod()
throws Exception {
ResinAcegiAuthenticator adapter = new ResinAcegiAuthenticator();
adapter.setAppContextLocation("org/acegisecurity/adapters/adaptertest-valid.xml");
adapter.setKey(ADAPTER_KEY);
adapter.init();
Principal result = adapter.loginImpl(null, null, null, "marissa", "koala");
if (!(result instanceof PrincipalAcegiUserToken)) {
fail("Should have returned PrincipalAcegiUserToken");
}
PrincipalAcegiUserToken castResult = (PrincipalAcegiUserToken) result;
assertEquals("marissa", castResult.getPrincipal());
assertEquals("koala", castResult.getCredentials());
assertEquals("ROLE_TELLER", castResult.getAuthorities()[0].getAuthority());
assertEquals("ROLE_SUPERVISOR", castResult.getAuthorities()[1].getAuthority());
assertEquals(ADAPTER_KEY.hashCode(), castResult.getKeyHash());
}
public void testAuthenticationWithNullPasswordHandledGracefully()
throws Exception {
ResinAcegiAuthenticator adapter = new ResinAcegiAuthenticator();
adapter.setAppContextLocation("org/acegisecurity/adapters/adaptertest-valid.xml");
adapter.setKey(ADAPTER_KEY);
adapter.init();
assertEquals(null, adapter.loginImpl("marissa", null));
}
public void testAuthenticationWithNullUserNameHandledGracefully()
throws Exception {
ResinAcegiAuthenticator adapter = new ResinAcegiAuthenticator();
adapter.setAppContextLocation("org/acegisecurity/adapters/adaptertest-valid.xml");
adapter.setKey(ADAPTER_KEY);
adapter.init();
assertEquals(null, adapter.loginImpl(null, "koala"));
}
public void testGetters() throws Exception {
ResinAcegiAuthenticator adapter = new ResinAcegiAuthenticator();
adapter.setAppContextLocation("org/acegisecurity/adapters/adaptertest-valid.xml");
adapter.setKey(ADAPTER_KEY);
assertEquals(ADAPTER_KEY, adapter.getKey());
assertEquals("org/acegisecurity/adapters/adaptertest-valid.xml", adapter.getAppContextLocation());
}
public void testHasRoleWithANullPrincipalFails() throws Exception {
ResinAcegiAuthenticator adapter = new ResinAcegiAuthenticator();
adapter.setAppContextLocation("org/acegisecurity/adapters/adaptertest-valid.xml");
adapter.setKey(ADAPTER_KEY);
adapter.init();
assertTrue(!adapter.isUserInRole(null, null, null, null, "ROLE_ONE"));
}
public void testHasRoleWithAPrincipalTheAdapterDidNotCreateFails()
throws Exception {
ResinAcegiAuthenticator adapter = new ResinAcegiAuthenticator();
adapter.setAppContextLocation("org/acegisecurity/adapters/adaptertest-valid.xml");
adapter.setKey(ADAPTER_KEY);
adapter.init();
assertTrue(!adapter.isUserInRole(null, null, null,
new Principal() {
public String getName() {
return "MockPrincipal";
}
}, "ROLE_ONE"));
}
public void testHasRoleWithPrincipalAcegiUserToken()
throws Exception {
PrincipalAcegiUserToken token = new PrincipalAcegiUserToken("KEY", "Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO")},
null);
ResinAcegiAuthenticator adapter = new ResinAcegiAuthenticator();
adapter.setAppContextLocation("org/acegisecurity/adapters/adaptertest-valid.xml");
adapter.setKey(ADAPTER_KEY);
adapter.init();
assertTrue(adapter.isUserInRole(null, null, null, token, "ROLE_ONE"));
assertTrue(adapter.isUserInRole(null, null, null, token, "ROLE_ONE"));
assertTrue(!adapter.isUserInRole(null, null, null, token, "ROLE_WE_DO_NOT_HAVE"));
}
}
-6
View File
@@ -1,6 +0,0 @@
dependencies {
compile project(':spring-security-core'),
"org.springframework:spring-beans:$springVersion",
"org.springframework:spring-context:$springVersion"
}
-61
View File
@@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<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-parent</artifactId>
<version>3.0.3.RELEASE</version>
</parent>
<packaging>jar</packaging>
<artifactId>spring-security-aspects</artifactId>
<name>Spring Security - Aspects</name>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.0.3.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.2</version>
<dependencies>
<!--
NB: You must use Maven 2.0.9 or above or these
are ignored (see MNG-2972)
-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.6.8</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -1,76 +0,0 @@
package org.springframework.security.access.intercept.aspectj.aspect;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.*;
import org.springframework.security.access.intercept.aspectj.AspectJCallback;
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
/**
* Concrete AspectJ aspect using Spring Security @Secured annotation
* for JDK 1.5+.
*
* <p>
* When using this aspect, you <i>must</i> annotate the implementation class
* (and/or methods within that class), <i>not</i> the interface (if any) that
* the class implements. AspectJ follows Java's rule that annotations on
* interfaces are <i>not</i> inherited. This will vary from Spring AOP.
*
* @author Mike Wiesner
* @author Luke Taylor
* @since 3.1
*/
public aspect AnnotationSecurityAspect implements InitializingBean {
/**
* Matches the execution of any public method in a type with the Secured
* annotation, or any subtype of a type with the Secured annotation.
*/
private pointcut executionOfAnyPublicMethodInAtSecuredType() :
execution(public * ((@Secured *)+).*(..)) && @this(Secured);
/**
* Matches the execution of any method with the Secured annotation.
*/
private pointcut executionOfSecuredMethod() :
execution(* *(..)) && @annotation(Secured);
/**
* Matches the execution of any method with Pre/Post annotations.
*/
private pointcut executionOfPrePostAnnotatedMethod() :
execution(* *(..)) && (@annotation(PreAuthorize) || @annotation(PreFilter)
|| @annotation(PostAuthorize) || @annotation(PostFilter));
private pointcut securedMethodExecution() :
executionOfAnyPublicMethodInAtSecuredType() ||
executionOfSecuredMethod() ||
executionOfPrePostAnnotatedMethod();
private AspectJMethodSecurityInterceptor securityInterceptor;
Object around(): securedMethodExecution() {
if (this.securityInterceptor == null) {
return proceed();
}
AspectJCallback callback = new AspectJCallback() {
public Object proceedWithObject() {
return proceed();
}
};
return this.securityInterceptor.invoke(thisJoinPoint, callback);
}
public void setSecurityInterceptor(AspectJMethodSecurityInterceptor securityInterceptor) {
this.securityInterceptor = securityInterceptor;
}
public void afterPropertiesSet() throws Exception {
if (this.securityInterceptor == null) {
throw new IllegalArgumentException("securityInterceptor required");
}
}
}
@@ -1,18 +0,0 @@
<?xml version="1.0"?>
<!--
AspectJ load-time weaving config file to install common Spring
aspects.
-->
<aspectj>
<!--
<weaver options="-showWeaveInfo"/>
-->
<aspects>
<aspect
name="org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect" />
</aspects>
</aspectj>
@@ -1,110 +0,0 @@
package org.springframework.security.access.intercept.aspectj.aspect;
import java.util.Arrays;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.ExpressionBasedAnnotationAttributeFactory;
import org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice;
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
import org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
/**
*
* @author Luke Taylor
* @since 3.0.3
*/
public class AnnotationSecurityAspectTests {
private @Mock AccessDecisionManager adm;
private @Mock AuthenticationManager authman;
private TestingAuthenticationToken anne = new TestingAuthenticationToken("anne", "", "ROLE_A");
// private TestingAuthenticationToken bob = new TestingAuthenticationToken("bob", "", "ROLE_B");
private AspectJMethodSecurityInterceptor interceptor;
private SecuredImpl secured = new SecuredImpl();
private PrePostSecured prePostSecured = new PrePostSecured();
@Before
public final void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
interceptor = new AspectJMethodSecurityInterceptor();
interceptor.setAccessDecisionManager(adm);
interceptor.setAuthenticationManager(authman);
interceptor.setSecurityMetadataSource(new SecuredAnnotationSecurityMetadataSource());
AnnotationSecurityAspect secAspect = AnnotationSecurityAspect.aspectOf();
secAspect.setSecurityInterceptor(interceptor);
}
@After
public void clearContext() {
SecurityContextHolder.clearContext();
}
@Test
public void securedInterfaceMethodAllowsAllAccess() throws Exception {
secured.securedMethod();
}
@Test(expected=AuthenticationCredentialsNotFoundException.class)
public void securedClassMethodDeniesUnauthenticatedAccess() throws Exception {
secured.securedClassMethod();
}
@Test
public void securedClassMethodAllowsAccessToRoleA() throws Exception {
SecurityContextHolder.getContext().setAuthentication(anne);
secured.securedClassMethod();
}
// SEC-1262
@Test(expected=AccessDeniedException.class)
public void denyAllPreAuthorizeDeniesAccess() throws Exception {
SecurityContextHolder.getContext().setAuthentication(anne);
interceptor.setSecurityMetadataSource(new PrePostAnnotationSecurityMetadataSource(
new ExpressionBasedAnnotationAttributeFactory(new DefaultMethodSecurityExpressionHandler())));
AffirmativeBased adm = new AffirmativeBased();
AccessDecisionVoter[] voters = new AccessDecisionVoter[]
{new PreInvocationAuthorizationAdviceVoter(new ExpressionBasedPreInvocationAdvice())};
adm.setDecisionVoters(Arrays.asList(voters));
interceptor.setAccessDecisionManager(adm);
prePostSecured.denyAllMethod();
}
}
interface SecuredInterface {
@Secured("ROLE_X")
void securedMethod();
}
class SecuredImpl implements SecuredInterface {
// Not really secured because AspectJ doesn't inherit annotations from interfaces
public void securedMethod() {
}
@Secured("ROLE_A")
public void securedClassMethod() {
}
}
class PrePostSecured {
@PreAuthorize("denyAll")
public void denyAllMethod() {
}
}
-206
View File
@@ -1,206 +0,0 @@
apply plugin: 'base'
allprojects {
version = '3.0.3.RELEASE'
releaseBuild = version.endsWith('RELEASE')
snapshotBuild = version.endsWith('SNAPSHOT')
group = 'org.springframework.security'
repositories {
mavenRepo name:'Local', urls: "file://" + System.properties['user.home'] + "/.m2/repository"
mavenCentral()
mavenRepo name: 'SpringSource Milestone Repo', urls: 'http://repository.springsource.com/maven/bundles/milestone'
mavenRepo name: 'SpringSource Maven Snapshot Repo', urls: 'http://maven.springframework.org/snapshot/'
mavenRepo name: 'SpringSource Enterprise Release', urls: 'http://repository.springsource.com/maven/bundles/release'
mavenRepo name: 'SpringSource Enterprise External', urls: 'http://repository.springsource.com/maven/bundles/external'
}
}
configure(javaProjects) {
apply from: "$rootDir/gradle/javaprojects.gradle"
apply from: "$rootDir/gradle/maven.gradle"
}
configure(coreModuleProjects) {
apply from: "$rootDir/gradle/bundlor.gradle"
// Gives better names in structure101 jar diagram
sourceSets.main.classesDir = new File(buildDir, "classes/" + project.name.substring("spring-security".length() + 1))
}
configure (aspectjProjects) {
apply from: "$rootDir/gradle/aspectj.gradle"
}
configurations {
antlibs
}
dependencies {
antlibs "org.springframework.build:org.springframework.build.aws.ant:3.0.3.RELEASE",
"net.java.dev.jets3t:jets3t:0.6.1"
}
task apidocs(type: Javadoc) {
destinationDir = new File(buildDir, 'apidocs')
title = "Spring Security $version API"
optionsFile = file("$buildDir/tmp/javadoc.options")
source coreModuleProjects.collect {project ->
project.sourceSets.main.allJava
}
classpath = files(coreModuleProjects.collect {project ->
project.sourceSets.main.compileClasspath
})
}
task docSiteLogin(type: Login) {
if (project.hasProperty('sshHost')) {
host = project.property('sshHost')
}
}
// Define remoteSiteDir and sshHost in gradle.properties
def remoteDocsDir = null
if (hasProperty('remoteSiteDir')) {
remoteDocsDir="$remoteSiteDir/docs/3.0.x"
}
task uploadApidocs(type: TarUpload) {
dependsOn apidocs
classifier = 'apidocs'
remoteDir = remoteDocsDir
login = docSiteLogin
into('apidocs') {
from apidocs.destinationDir
}
}
def docsDir = new File(project(':manual').buildDir, 'docs')
task uploadDoc(type: TarUpload) {
dependsOn ':manual:doc'
classifier = 'doc'
remoteDir = remoteDocsDir
login = docSiteLogin
into('reference') {
from docsDir
}
}
task uploadFaq(type: TarUpload) {
dependsOn ':faq:docbookHtmlSingle'
classifier = 'faq'
if (project.hasProperty('remoteSiteDir')) {
remoteDir = project.property('remoteSiteDir')
}
login = docSiteLogin
def faqDir = new File(project(':faq').buildDir, 'docs')
into('faq') {
from faqDir
}
}
task dist(type: Zip) {
def zipRootDir = "${project.name}-$version"
into(zipRootDir) {
into('docs/apidocs') {
from apidocs.destinationDir
}
into('docs/reference') {
from docsDir
}
into('dist') {
from coreModuleProjects.collect {project -> project.libsDir }
from project(':spring-security-samples-tutorial').libsDir
from project(':spring-security-samples-contacts').libsDir
}
}
}
dist {
dependsOn apidocs, ':manual:doc', subprojects.collect { "$it.path:assemble" }
doLast {
ant.checksum(file: archivePath, algorithm: 'SHA1', fileext: '.sha1')
}
}
task uploadDist(type: UploadDist) {
archiveFile = dist.archivePath
shaFile = "${dist.archivePath}.sha1" as File
archiveName = dist.archiveName
classpath = configurations.antlibs
}
def getJavaProjects() {
subprojects.findAll {project -> project.name != 'faq' && project.name != 'manual' }
}
def getSampleProjects() {
subprojects.findAll {project -> project.name.startsWith('spring-security-samples') }
}
def getItestProjects() {
subprojects.findAll {project -> project.name.startsWith('itest') }
}
def getCoreModuleProjects() {
javaProjects - sampleProjects - itestProjects - aspectjProjects
}
def getAspectjProjects() {
subprojects.findAll {project -> project.name == 'spring-security-aspects' || project.name == 'spring-security-samples-aspectj'}
}
class UploadDist extends DefaultTask {
@InputFile
File shaFile
@InputFile
File archiveFile
@Input
String archiveName
@InputFiles
def classpath
@TaskAction
def upload() {
def accessKey = project.s3AccessKey
def secretKey = project.s3SecretAccessKey
def version = project.version
project.ant {
taskdef(resource: 'org/springframework/build/aws/ant/antlib.xml', classpath: classpath.asPath)
s3(accessKey: accessKey, secretKey: secretKey) {
upload(bucketName: 'dist.springframework.org', file: archiveFile,
toFile: releaseType() + "/SEC/${archiveName}", publicRead: 'true') {
metadata(name: 'project.name', value: 'Spring Security')
metadata(name: 'release.type', value: releaseType())
metadata(name: 'bundle.version', value: version)
metadata(name: 'package.file.name', value: archiveName)
}
upload(bucketName: 'dist.springframework.org', file: shaFile,
toFile: releaseType() + "/SEC/${archiveName}.sha1", publicRead: 'true')
}
}
}
def releaseType() {
if (project.releaseBuild) {
'release'
} else if (project.snapshotBuild) {
'snapshot'
} else {
'milestone'
}
}
}
-32
View File
@@ -1,32 +0,0 @@
apply plugin: 'groovy'
repositories {
mavenRepo name:'localRepo', urls: "file://" + System.properties['user.home'] + "/.m2/repository"
mavenCentral()
mavenRepo name:'Shibboleth Repo', urls:'http://shibboleth.internet2.edu/downloads/maven2'
}
dependencies {
def fopDeps = [ 'org.apache.xmlgraphics:fop:0.95-1@jar',
'org.apache.xmlgraphics:xmlgraphics-commons:1.3',
'org.apache.xmlgraphics:batik-bridge:1.7@jar',
'org.apache.xmlgraphics:batik-util:1.7@jar',
'org.apache.xmlgraphics:batik-css:1.7@jar',
'org.apache.xmlgraphics:batik-dom:1.7',
'org.apache.xmlgraphics:batik-svg-dom:1.7@jar',
'org.apache.avalon.framework:avalon-framework-api:4.3.1']
groovy localGroovy()
compile gradleApi(),
'org.apache.xerces:resolver:2.9.1',
'saxon:saxon:6.5.3',
'org.apache.xerces:xercesImpl:2.9.1',
fopDeps
runtime 'net.sf.xslthl:xslthl:2.0.1',
'net.sf.docbook:docbook-xsl:1.75.2:resources@zip'
}
task ide(type: Copy) {
from configurations.runtime
into 'ide'
}

Some files were not shown because too many files have changed in this diff Show More