1
0
mirror of synced 2026-07-12 22:30:33 +00:00

Compare commits

..

83 Commits

Author SHA1 Message Date
Luke Taylor 82d140ffb1 Version 3.0.4.RELEASE 2010-10-26 15:32:22 +01:00
Luke Taylor 1563491322 SEC-1600: Added Implementation-Version and Implementation-Title to manifest templates and checking of version numbers in namespace config module and core. Config checks the version of core it is running against and core checks the Spring version, reporting any mismatches or situations where the app is running with less than the recommended Spring version. 2010-10-26 15:32:21 +01:00
Luke Taylor b688bb69ee SEC-1543: Change IpAddressMatcher to return false when comparing an Inet6Address with an Inet4Address rather than raising an exception. 2010-10-26 15:32:21 +01:00
Luke Taylor 36f008643d SEC-1598: Removed invalid properties from SessionFixationProtectionStrategy bean declaration in Session Management chapter docbook. 2010-10-26 15:32:21 +01:00
Luke Taylor cbdf77e991 SEC-1597: Corrected bean class name for RememberMeAuthenticationProvider in docbook source. 2010-10-26 15:32:21 +01:00
Luke Taylor 399e921d14 SEC-1599: Corrected docbook source. 2010-10-26 15:32:21 +01:00
Luke Taylor c458311d2d SEC-1548: Added extra logging to Dao-authentication classes to clarify reasons for authentication failure (missing user vs wrong password etc.). 2010-10-26 15:32:21 +01:00
Luke Taylor d6f408e8bf SEC-1583: Added hasAuthority and hasAnyAuthority imlementations to SecurityExpressionRoot. 2010-10-26 15:32:21 +01:00
Luke Taylor 1739628e6a SEC-1589: Add support for property placeholder in intercept-methods access attribute. 2010-10-26 15:32:21 +01:00
Luke Taylor 8e68fa1334 SEC-1584: Added namespace support for injecting custom HttpFirewall instance into FilterChainProxy. 2010-10-26 15:32:21 +01:00
Luke Taylor 82cd72768d doc updates to be merged with orgininal sec-1584 doc changes 2010-10-26 15:32:20 +01:00
Luke Taylor 161710cc87 SEC-1584: Doc updates to explain request matching process. 2010-10-26 15:32:20 +01:00
Luke Taylor dc1b652512 SEC-1584: Additional integration tests. 2010-10-26 15:32:20 +01:00
Luke Taylor ed9411c660 SEC-1584: Addition of HttpFirewall strategy to FilterChainProxy to reject un-normalized requests and wrap the incoming request object before processing by the security filter chain to provide a more consistent representation of paths than is guaranteed by the servlet spec. The wrapper strips path parameters from pathInfo and servletPath to provide consistency of URL matching across servlet containers and protect against bypassing security constraints by the malicious addition of such parameters to the URL. The paths are canonicalized further by replacing of multiple sequences of "/" characters with a single "/". 2010-10-26 15:31:33 +01:00
Luke Taylor e58f982351 Updating gitignore and removing unnecessary casts from FilterChainProxyConfigTests. 2010-10-05 13:31:49 +01:00
Luke Taylor 072b73354f Update namespace handler message to account for later schema versions being used by mistake. 2010-10-05 13:31:49 +01:00
Rob Winch 443231d1e8 SEC-1578: Use ThreadLocal.remove() instead of ThreadLocal.set(null) 2010-10-04 21:10:21 -05:00
Luke Taylor 45674a16ea SEC-1540: Apply patch to support HTTP method matching for requires-channel namespace attribute. 2010-08-18 13:17:21 +01:00
Luke Taylor a1b124def5 SEC-1532: Add cache of previously matched beans to ProtectPointcutPostProcessor to ensure that it doesn't perform pointcut matching every time a new prototype bean is created. 2010-08-11 18:29:21 +01:00
Luke Taylor f6abc24ed6 SEC-1529: More user-friendly expression @PreAuthorize expression in EL chapter. 2010-08-05 18:17:25 +01:00
Luke Taylor 1a9b7e1b6f SEC-1520: Close NamingEnumeration in LDAP compare implementation. 2010-07-21 16:55:09 +01:00
Luke Taylor 8b5c70951d SEC-1518: Fix element ordering in security.tld 2010-07-21 16:16:46 +01:00
Luke Taylor c891ab45ec Remove optional qualifier from apacheds dependencies in LDAP sample. 2010-07-13 02:08:44 +01:00
Luke Taylor 657a69b906 Minor doc/javadoc updates to clarify use of UserDetailsContextapper. 2010-07-04 15:10:08 +01:00
Luke Taylor 3b8fbe8bee Minor doc updates. 2010-07-03 19:43:01 +01:00
Luke Taylor 4ad85cdfdf SEC-1508: Update docbook processing to use Docbook 5 namespaces. 2010-07-03 13:12:08 +01:00
Luke Taylor 845c50a1c3 SEC-1507: Applied patch to return empty authority list rather than null from RoleHierarchyImpl. 2010-07-02 19:51:36 +01:00
Luke Taylor 25d222208d Switch version to 3.0.4-CI-SNAPSHOT. 2010-07-01 00:37:55 +01:00
Luke Taylor 9b0c21dfef 3.0.3 release. Update version in build files. 2010-07-01 00:37:29 +01:00
Luke Taylor 8301bd6276 Added that config jar is required to use the namespace. 2010-06-30 20:47:35 +01:00
Luke Taylor 1872d94aa1 Porting gradle changes from master 2010-06-30 20:45:03 +01:00
Luke Taylor 46611872db Updated version in manual for 3.0.3 release 2010-06-30 15:59:34 +01:00
Luke Taylor b6cbdde0cb Minor doc xref link corrections. 2010-06-26 13:14:15 +01:00
Luke Taylor 71e1702224 SEC-1493: Documentation of support for erasing credentials. 2010-06-26 12:34:20 +01:00
Luke Taylor 80ccd2b285 SEC-1501: Fix bean classname in Javadoc for SwitchUserFilter. 2010-06-25 13:36:52 +01:00
Luke Taylor 02c1f02f2a SEC-1493: Fix broken tests in 3.0.x branch 2010-06-25 13:36:08 +01:00
Luke Taylor 21a664b2eb Deprecation warning suppression for UserMap. 2010-06-25 12:50:58 +01:00
Luke Taylor 9a2d0c2cb5 SEC-1493: Added namespace support. 2010-06-20 21:11:49 +01:00
Luke Taylor 73b62497a3 SEC-1493: Added CredentialsContainer interface and implemented it in User, AbstractAuthenticationToken and UsernamePasswordAuthenticationToken. ProviderManager makes use of this to erase the credentials of the returned Authentication object (and its contents) if configured to do so by setting the 'eraseCredentialsAfterAuthentication' property. 2010-06-20 21:11:40 +01:00
Luke Taylor 09aba3906c SEC-1496: Added support for use of any non-standard URL schemes in DefaultRedirectStrategy. 2010-06-18 03:34:13 +01:00
Luke Taylor 57cfff6f5c SEC-1500: Convert AbstractRetryEntryPoint to use requestURI to correctly encode URLs. 2010-06-18 01:33:38 +01:00
Luke Taylor b7b6b2bac7 Update to Spring 3.0.3.RELEASE 2010-06-18 01:27:32 +01:00
Luke Taylor 8602ae3863 Upgrade maven build to Spring 3.0.3.BUILD-SNAPSHOT 2010-06-15 00:16:41 +01:00
Luke Taylor 8737fe3acb SEC-1495: Convert User class equals and hashcode methods to only use the "username" property.
This prevents situations where other data may have changed when a User object is reloaded (during a subsequent authentication attempt, in which case and Set.contains()/Map.containsKey() will return false even though the collection in question contains a principal representing the same user.
2010-06-10 22:28:12 +01:00
Luke Taylor 27faad3402 SEC-1488: Remove commons-logging dependencies from maven poms and use slf4j in all samples. 2010-05-28 13:10:08 +01:00
Luke Taylor aaa7bd90b2 SEC-1481: Updated constructors of Authentication types to use a generic wildcard for authorities collection. 2010-05-21 16:02:25 +01:00
Luke Taylor 295e0ded18 SEC-1483: Change User constructor to use a generic wildcard for authorities collection. 2010-05-21 16:02:07 +01:00
Luke Taylor 304f12fb63 SEC-1455: Load namespace parsers when required, rather than on init() call, to avoid classloaded issue with dmServer failing to resolve web classes when the namespace handler is first used. 2010-05-21 15:42:11 +01:00
Luke Taylor 8cbe232fbf SEC-1480: Add simple equals and hashcode methods based on DN value to LdapUserDetailsImpl to allow its use as a map key (in SessionRegistry, for example). 2010-05-15 02:29:56 +01:00
Luke Taylor 5ac106808e Remove outdated scm information from pom.xml. 2010-04-28 20:16:40 +01:00
Luke Taylor 8c605516b3 SEC-1463: Change namespace user-service parser to store username in lower-case when building map for in-memory UserDetailsService. Lookups are supposed to be case-insensitive with this class. 2010-04-24 16:42:00 +01:00
Luke Taylor e6e168f127 SEC-1456: Set rtexprvalue=true for "url" attribute in access tag to allow dynamic values (such as URL of current page). 2010-04-21 17:29:27 +01:00
Luke Taylor 6d6c2d31ef SEC-1462: Only apply session fixation protection strategy if request.isRequestedSessionIdValid() returns true. We don't need to create a new session if the current one already has a different Id from the client. 2010-04-20 18:04:56 +01:00
Luke Taylor 8f6aecac9b Clarify that multiple authentication-provider elements can be used in combination. 2010-04-17 15:25:37 +01:00
Luke Taylor 0760bb947b SEC-1458: Remove logger field in HttpSessionEventPublisher in favour of direct lookup. Prevents early initialization of logging system when listener is initialized. 2010-04-16 16:13:41 +01:00
Luke Taylor 9d2e2ca11d SEC-1232: Add config dependency to maven build for aspectj sample. 2010-03-31 19:59:19 +01:00
Luke Taylor 6354c7e052 SEC-1232: GlobalMethodSecurityBeanDefinitionParser support for mode='aspectj'
AspectJ sample application context also updated to use this syntax.
2010-03-31 17:41:23 +01:00
Luke Taylor 42cdaa0ce2 Latest gradle syntax updates. 2010-03-31 17:12:00 +01:00
Luke Taylor eda60b72b1 SEC-1448: Fixed failure to resolve generic method argument names in MethodSecurityEvaluationContext.
Changed to use AopUtils.getMostSpecificMethod() when obtaining the method on which the parameter resolution should be performed. Also added better error handling and log warning when parameter names cannot be resolved. The exception will then be a SpEL one, rather than a NPE.
2010-03-27 17:22:38 +00:00
Luke Taylor 0d198d42ae SEC-1444: Fix JNDI escaping problems in LDAP authentication.
CompositeName adds quotes to names which contain a forward slash ("/") character. These are automatically removed by Spring LDAP's DistinguishedName, but only if they are at the ends of the String. Since we were preprending the base to the (quoted) DN, resulting in something like ["cn=joe/b",ou=people], this was causing problems with the DN value returned from the search. Additionally, the bind succeeds when a DN is used with a slash, but the subsequent call to getAttributes() fails. This call now passes in a DistinguishedName for the user DN instance instead of a String.
2010-03-27 15:30:45 +00:00
Luke Taylor f000aaa7e8 SEC-1440: Implement support for separate entry-point-ref on htt-basic namespace element. Changes ported from master branch. 2010-03-26 14:06:12 +00:00
Luke Taylor 634e340d80 Update schema version to 3.0.3 2010-03-26 13:53:56 +00:00
Luke Taylor 4c8e9e2d7e SEC-1450: Replace use of ClassUtils.getMostSpecificMethod() in AbstractFallbackMethodDefinitionSource with AopUtils.getMostSpecificMethod() equivalent.
Ensures protect-pointcut expressions match methods with generic parameters.
2010-03-24 21:03:45 +00:00
Luke Taylor e518adbef1 SEC-1443: Modify Jsr250Voter to handle multiple "RolesAllowed" roles.
It now votes to abstain if there are no Jsr250 attributes present. If any are found, it will either deny or grant access. For multiple "RoleAllowed" attributes, access will be granted if any user authority matches or denied if no match is found.
2010-03-22 16:26:49 +00:00
Luke Taylor 59b69f6f48 SEC-1434: Remove use of BeanDefinition of type java.lang.String which causes problems in Google App Engine.
This results in the method BeanUtils.findEditorByConvention attempting to get hold of the system classloader which isn't allowed by the security manager in GAE.
2010-03-16 02:22:36 +00:00
Luke Taylor b8e50c0933 SEC-1439: Make getters and setters public on HttpRequestResponseHolder.
Necessary to allow use of custom SecurityContextRepository.(cherry picked from commit d5df53f1db)
2010-03-12 15:54:12 +00:00
Luke Taylor 677576ea8b SEC-1429: Fix test. Wasn't setting allowSessionCreation=false on failure handler. 2010-03-11 02:30:37 +00:00
Luke Taylor 91153df78d SEC-1262: Added new (replacement) AspectJ interceptor which wraps the JoinPoint in a MethodInvocation adapter to provide compatibility with classes which only support MethodInvocation instances.
Also deprecated the existing AspectJ interceptors. This will also allow future simplification of the AbstractMethodSecurityMetadataSource, as it no longer needs to support JoinPoints.
2010-03-11 02:15:35 +00:00
Luke Taylor 1b0ac9c785 Porting of gradle changes from master. 2010-03-11 02:15:02 +00:00
Luke Taylor 8c9159f273 Added repo for aws-maen 3.0.0 dep 2010-03-06 01:41:38 +00:00
Luke Taylor 4c8b0faa88 Upgrade aws-maven to 3.0.0.RELEASE (mvn 2.2.x compatible) 2010-03-05 18:03:59 +00:00
Luke Taylor 5a5b62e2cb SEC-1429: Removed cached authentication from session after successful authentication.(cherry picked from commit 43f0e11106) 2010-03-05 00:11:08 +00:00
Luke Taylor 6ac8588144 Fix to Javadoc for AbstractAuthenticationProcessingFilter.(cherry picked from commit a3263753d9) 2010-03-04 22:07:30 +00:00
Luke Taylor 5690f1c581 SEC-1428: Check if response has been committed before redirecting to target URL in AbstractAuthenticationTargetUrlRequestHandler. 2010-03-04 22:00:37 +00:00
Luke Taylor 87cf27ab7c SEC-1429: Move logic for saving of AuthenticationException into the SimpleUrlAuthenticationFailurehandler from AbstractAuthenticationProcessingFilter. It will also now use request scope if configured to do a forward instead of a redirect. 2010-03-04 21:49:38 +00:00
Luke Taylor 41e06152b3 SEC-1420: JSP for itest of authentication tags with and without escaping. 2010-03-04 01:44:54 +00:00
Luke Taylor a7e21318bf SEC-1425: Replace use of Java 1.6 String.isEmpty(). 2010-03-04 00:52:54 +00:00
Luke Taylor bc6aae132b SEC-1420: Add htmlEscape attribute to authentication JSP tag.
This allows HTML escaping to be disabled if required.
2010-03-04 00:47:59 +00:00
Luke Taylor b46ae6ac62 SEC-1425: Add check for empty cookie in AbstractRememberMeServices.
Prevents ArrayOutOfBoundsException later when processing the tokeniszed cookie.
2010-02-28 14:00:43 +00:00
Luke Taylor 317da55cd0 SEC-1423: Cache PointcutExpression instances in ProtectPointcutPostProcessor for more efficient startup. 2010-02-26 17:50:45 +00:00
Luke Taylor 9e751e22c8 Refactoring to remove remaining circular dependencies indicated by structure101. 2010-02-26 17:50:14 +00:00
Luke Taylor 4d65b35827 Minor gradle 0.9 syntax change. 2010-02-26 17:49:32 +00:00
Luke Taylor 9831980bc2 Update versions to 3.0.3.CI-SNAPSHOT. 2010-02-26 15:04:43 +00:00
1022 changed files with 22753 additions and 35071 deletions
+6 -10
View File
@@ -1,20 +1,16 @@
target/
*/src/META-INF/
.classpath
.springBeans
.project
.DS_Store
.settings/
.idea/
out/
bin/
intellij/
build/
*.log
*.log.*
*.iml
out/
intellij/
*.ipr
*.iws
*.log
*.log.1
.DS_Store
*.iml
.gradle/
gradle.properties
atlassian-ide-plugin.xml
-3
View File
@@ -2,7 +2,6 @@
dependencies {
compile project(':spring-security-core'),
'aopalliance:aopalliance:1.0',
"net.sf.ehcache:ehcache:$ehcacheVersion",
"org.springframework:spring-aop:$springVersion",
"org.springframework:spring-context:$springVersion",
@@ -12,6 +11,4 @@ dependencies {
testCompile "org.springframework:spring-beans:$springVersion",
"org.springframework:spring-context-support:$springVersion",
"org.springframework:spring-test:$springVersion"
testRuntime "hsqldb:hsqldb:$hsqlVersion"
}
+68
View File
@@ -0,0 +1,68 @@
<?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.4.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>
@@ -20,7 +20,6 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.AuthorizationServiceException;
@@ -146,10 +145,14 @@ public class AclEntryVoter extends AbstractAclVoter {
}
public boolean supports(ConfigAttribute attribute) {
return (attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute());
if ((attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute())) {
return true;
} else {
return false;
}
}
public int vote(Authentication authentication, MethodInvocation object, Collection<ConfigAttribute> attributes) {
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
for(ConfigAttribute attr : attributes) {
@@ -174,7 +177,7 @@ public class AclEntryVoter extends AbstractAclVoter {
try {
Class<?> clazz = domainObject.getClass();
Method method = clazz.getMethod(internalMethod, new Class[0]);
domainObject = method.invoke(domainObject);
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);
@@ -1,66 +0,0 @@
package org.springframework.security.acls;
import java.util.ArrayList;
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.PermissionCacheOptimizer;
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
import org.springframework.security.acls.domain.SidRetrievalStrategyImpl;
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.Sid;
import org.springframework.security.acls.model.SidRetrievalStrategy;
import org.springframework.security.core.Authentication;
/**
* Batch loads ACLs for collections of objects to allow optimised filtering.
*
* @author Luke Taylor
* @since 3.1
*/
public class AclPermissionCacheOptimizer implements PermissionCacheOptimizer {
private final Log logger = LogFactory.getLog(getClass());
private final AclService aclService;
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
private ObjectIdentityRetrievalStrategy oidRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
public AclPermissionCacheOptimizer(AclService aclService) {
this.aclService = aclService;
}
public void cachePermissionsFor(Authentication authentication, Collection<?> objects) {
if (objects.isEmpty()) {
return;
}
List<ObjectIdentity> oidsToCache = new ArrayList<ObjectIdentity>(objects.size());
for (Object domainObject : objects) {
if (domainObject == null) {
continue;
}
ObjectIdentity oid = oidRetrievalStrategy.getObjectIdentity(domainObject);
oidsToCache.add(oid);
}
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
if (logger.isDebugEnabled()) {
logger.debug("Eagerly loading Acls for " + oidsToCache.size() + " objects");
}
aclService.readAclsById(oidsToCache, sids);
}
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
this.oidRetrievalStrategy = objectIdentityRetrievalStrategy;
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
}
@@ -34,7 +34,7 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
private final Log logger = LogFactory.getLog(getClass());
private final AclService aclService;
private AclService aclService;
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
private ObjectIdentityGenerator objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
@@ -70,30 +70,24 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
List<Permission> requiredPermission = resolvePermission(permission);
final boolean debug = logger.isDebugEnabled();
if (debug) {
logger.debug("Checking permission '" + permission + "' for object '" + oid + "'");
}
try {
// Lookup only ACLs for SIDs we're interested in
Acl acl = aclService.readAclById(oid, sids);
if (acl.isGranted(requiredPermission, sids, false)) {
if (debug) {
if (logger.isDebugEnabled()) {
logger.debug("Access is granted");
}
return true;
}
if (debug) {
if (logger.isDebugEnabled()) {
logger.debug("Returning false - ACLs returned, but insufficient permissions for this principal");
}
} catch (NotFoundException nfe) {
if (debug) {
if (logger.isDebugEnabled()) {
logger.debug("Returning false - no ACLs apply for this principal");
}
}
@@ -117,7 +111,7 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
if (permission instanceof String) {
String permString = (String)permission;
Permission p;
Permission p = null;
try {
p = permissionFactory.buildFromName(permString);
@@ -43,12 +43,12 @@ import org.springframework.util.Assert;
public abstract class AbstractAclProvider implements AfterInvocationProvider {
//~ Instance fields ================================================================================================
protected final AclService aclService;
protected AclService aclService;
protected Class<?> processDomainObjectClass = Object.class;
protected ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
protected SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
protected String processConfigAttribute;
protected final List<Permission> requirePermission;
protected List<Permission> requirePermission = Arrays.asList(BasePermission.READ);
//~ Constructors ===================================================================================================
@@ -78,9 +78,11 @@ public abstract class AbstractAclProvider implements AfterInvocationProvider {
// Obtain the SIDs applicable to the principal
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
Acl acl = null;
try {
// Lookup only ACLs for SIDs we're interested in
Acl acl = aclService.readAclById(objectIdentity, sids);
acl = aclService.readAclById(objectIdentity, sids);
return acl.isGranted(requirePermission, sids, false);
} catch (NotFoundException ignore) {
@@ -75,7 +75,9 @@ public class AclEntryAfterInvocationCollectionFilteringProvider extends Abstract
Object returnedObject) throws AccessDeniedException {
if (returnedObject == null) {
logger.debug("Return object is null, skipping");
if (logger.isDebugEnabled()) {
logger.debug("Return object is null, skipping");
}
return null;
}
@@ -65,7 +65,7 @@ public class AclEntryAfterInvocationProvider extends AbstractAclProvider impleme
//~ Constructors ===================================================================================================
public AclEntryAfterInvocationProvider(AclService aclService, List<Permission> requirePermission) {
this(aclService, "AFTER_ACL_READ", requirePermission);
super(aclService, "AFTER_ACL_READ", requirePermission);
}
public AclEntryAfterInvocationProvider(AclService aclService, String processConfigAttribute,
@@ -81,13 +81,17 @@ public class AclEntryAfterInvocationProvider extends AbstractAclProvider impleme
if (returnedObject == null) {
// AclManager interface contract prohibits nulls
// As they have permission to null/nothing, grant access
logger.debug("Return object is null, skipping");
if (logger.isDebugEnabled()) {
logger.debug("Return object is null, skipping");
}
return null;
}
if (!getProcessDomainObjectClass().isAssignableFrom(returnedObject.getClass())) {
logger.debug("Return object is not applicable for this provider, skipping");
if (logger.isDebugEnabled()) {
logger.debug("Return object is not applicable for this provider, skipping");
}
return returnedObject;
}
@@ -104,7 +108,7 @@ public class AclEntryAfterInvocationProvider extends AbstractAclProvider impleme
logger.debug("Denying access");
throw new AccessDeniedException(messages.getMessage("AclEntryAfterInvocationProvider.noPermission",
throw new AccessDeniedException(messages.getMessage("BasicAclEntryAfterInvocationProvider.noPermission",
new Object[] {authentication.getName(), returnedObject},
"Authentication {0} has NO permissions to the domain object {1}"));
}
@@ -95,7 +95,7 @@ class ArrayFilterer<T> implements Filterer<T> {
}
public T next() {
if (!hasNext()) {
if (hasNext() == false) {
throw new NoSuchElementException();
}
return list[index++];
@@ -37,9 +37,12 @@ class CollectionFilterer<T> implements Filterer<T> {
//~ Instance fields ================================================================================================
private final Collection<T> collection;
private Collection<T> collection;
private final Set<T> removeList;
// collectionIter offers significant performance optimisations (as
// per security-developer mailing list conversation 19/5/05)
private Iterator<T> collectionIter;
private Set<T> removeList;
//~ Constructors ===================================================================================================
@@ -85,7 +88,9 @@ class CollectionFilterer<T> implements Filterer<T> {
* @see org.springframework.security.acls.afterinvocation.Filterer#iterator()
*/
public Iterator<T> iterator() {
return collection.iterator();
collectionIter = collection.iterator();
return collectionIter;
}
/**
@@ -12,7 +12,7 @@ public abstract class AbstractPermission implements Permission {
//~ Instance fields ================================================================================================
protected final char code;
protected char code;
protected int mask;
//~ Constructors ===================================================================================================
@@ -33,13 +33,13 @@ import java.io.Serializable;
public class AccessControlEntryImpl implements AccessControlEntry, AuditableAccessControlEntry {
//~ Instance fields ================================================================================================
private final Acl acl;
private Acl acl;
private Permission permission;
private final Serializable id;
private final Sid sid;
private Serializable id;
private Sid sid;
private boolean auditFailure = false;
private boolean auditSuccess = false;
private final boolean granting;
private boolean granting;
//~ Constructors ===================================================================================================
@@ -41,9 +41,9 @@ import org.springframework.util.Assert;
public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
//~ Instance fields ================================================================================================
private final GrantedAuthority gaGeneralChanges;
private final GrantedAuthority gaModifyAuditing;
private final GrantedAuthority gaTakeOwnership;
private GrantedAuthority gaGeneralChanges;
private GrantedAuthority gaModifyAuditing;
private GrantedAuthority gaTakeOwnership;
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
//~ Constructors ===================================================================================================
@@ -52,23 +52,16 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
* Constructor. The only mandatory parameter relates to the system-wide {@link GrantedAuthority} instances that
* can be held to always permit ACL changes.
*
* @param auths the <code>GrantedAuthority</code>s that have
* @param auths an array of <code>GrantedAuthority</code>s that have
* special permissions (index 0 is the authority needed to change
* ownership, index 1 is the authority needed to modify auditing details,
* index 2 is the authority needed to change other ACL and ACE details) (required)
* <p>
* Alternatively, a single value can be supplied for all three permissions.
*/
public AclAuthorizationStrategyImpl(GrantedAuthority... auths) {
Assert.isTrue(auths != null && (auths.length == 3 || auths.length == 1),
"One or three GrantedAuthority instances required");
if (auths.length == 3) {
gaTakeOwnership = auths[0];
gaModifyAuditing = auths[1];
gaGeneralChanges = auths[2];
} else {
gaTakeOwnership = gaModifyAuditing = gaGeneralChanges = auths[0];
}
public AclAuthorizationStrategyImpl(GrantedAuthority[] auths) {
Assert.isTrue(auths != null && auths.length == 3, "GrantedAuthority[] with three elements required");
this.gaTakeOwnership = auths[0];
this.gaModifyAuditing = auths[1];
this.gaGeneralChanges = auths[2];
}
//~ Methods ========================================================================================================
@@ -91,7 +84,7 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
}
// Not authorized by ACL ownership; try via adminstrative permissions
GrantedAuthority requiredAuthority;
GrantedAuthority requiredAuthority = null;
if (changeType == CHANGE_AUDITING) {
requiredAuthority = this.gaModifyAuditing;
@@ -26,7 +26,6 @@ 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.PermissionGrantingStrategy;
import org.springframework.security.acls.model.Sid;
import org.springframework.security.acls.model.UnloadedSidException;
import org.springframework.util.Assert;
@@ -42,8 +41,8 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
private Acl parentAcl;
private transient AclAuthorizationStrategy aclAuthorizationStrategy;
private transient PermissionGrantingStrategy permissionGrantingStrategy;
private final List<AccessControlEntry> aces = new ArrayList<AccessControlEntry>();
private transient AuditLogger auditLogger;
private List<AccessControlEntry> aces = new ArrayList<AccessControlEntry>();
private ObjectIdentity objectIdentity;
private Serializable id;
private Sid owner; // OwnershipAcl
@@ -70,48 +69,39 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
this.objectIdentity = objectIdentity;
this.id = id;
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
this.permissionGrantingStrategy = new DefaultPermissionGrantingStrategy(auditLogger);
}
/**
* @deprecated Use the version which takes a {@code PermissionGrantingStrategy} argument instead.
*/
@Deprecated
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
AuditLogger auditLogger, Acl parentAcl, List<Sid> loadedSids, boolean entriesInheriting, Sid owner) {
this(objectIdentity, id, aclAuthorizationStrategy, new DefaultPermissionGrantingStrategy(auditLogger),
parentAcl, loadedSids, entriesInheriting, owner);
this.auditLogger = auditLogger;
}
/**
* Full constructor, which should be used by persistence tools that do not
* provide field-level access features.
*
* @param objectIdentity the object identity this ACL relates to
* @param id the primary key assigned to this ACL
* @param aclAuthorizationStrategy authorization strategy
* @param grantingStrategy the {@code PermissionGrantingStrategy} which will be used by the {@code isGranted()} method
* @param parentAcl the parent (may be may be {@code null})
* @param loadedSids the loaded SIDs if only a subset were loaded (may be {@code null})
* @param objectIdentity the object identity this ACL relates to (required)
* @param id the primary key assigned to this ACL (required)
* @param aclAuthorizationStrategy authorization strategy (required)
* @param auditLogger audit logger (required)
* @param parentAcl the parent (may be <code>null</code>)
* @param loadedSids the loaded SIDs if only a subset were loaded (may be
* <code>null</code>)
* @param entriesInheriting if ACEs from the parent should inherit into
* this ACL
* @param owner the owner (required)
*/
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
PermissionGrantingStrategy grantingStrategy, Acl parentAcl, List<Sid> loadedSids, boolean entriesInheriting, Sid owner) {
AuditLogger auditLogger, Acl parentAcl, List<Sid> loadedSids, boolean entriesInheriting, Sid owner) {
Assert.notNull(objectIdentity, "Object Identity required");
Assert.notNull(id, "Id required");
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
Assert.notNull(owner, "Owner required");
Assert.notNull(auditLogger, "AuditLogger required");
this.objectIdentity = objectIdentity;
this.id = id;
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
this.auditLogger = auditLogger;
this.parentAcl = parentAcl; // may be null
this.loadedSids = loadedSids; // may be null
this.entriesInheriting = entriesInheriting;
this.owner = owner;
this.permissionGrantingStrategy = grantingStrategy;
}
/**
@@ -178,11 +168,35 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
}
/**
* Delegates to the {@link PermissionGrantingStrategy}.
* Determines authorization. The order of the <code>permission</code> and <code>sid</code> arguments is
* <em>extremely important</em>! The method will iterate through each of the <code>permission</code>s in the order
* specified. For each iteration, all of the <code>sid</code>s will be considered, again in the order they are
* presented. A search will then be performed for the first {@link AccessControlEntry} object that directly
* matches that <code>permission:sid</code> combination. When the <em>first full match</em> is found (ie an ACE
* that has the SID currently being searched for and the exact permission bit mask being search for), the grant or
* deny flag for that ACE will prevail. If the ACE specifies to grant access, the method will return
* <code>true</code>. If the ACE specifies to deny access, the loop will stop and the next <code>permission</code>
* iteration will be performed. If each permission indicates to deny access, the first deny ACE found will be
* considered the reason for the failure (as it was the first match found, and is therefore the one most logically
* requiring changes - although not always). If absolutely no matching ACE was found at all for any permission,
* the parent ACL will be tried (provided that there is a parent and {@link #isEntriesInheriting()} is
* <code>true</code>. The parent ACL will also scan its parent and so on. If ultimately no matching ACE is found,
* a <code>NotFoundException</code> will be thrown and the caller will need to decide how to handle the permission
* check. Similarly, if any of the SID arguments presented to the method were not loaded by the ACL,
* <code>UnloadedSidException</code> will be thrown.
*
* @param permission the exact permissions to scan for (order is important)
* @param sids the exact SIDs to scan for (order is important)
* @param administrativeMode if <code>true</code> denotes the query is for administrative purposes and no auditing
* will be undertaken
*
* @return <code>true</code> if one of the permissions has been granted, <code>false</code> if one of the
* permissions has been specifically revoked
*
* @throws NotFoundException if an exact ACE for one of the permission bit masks and SID combination could not be
* found
* @throws UnloadedSidException if the passed SIDs are unknown to this ACL because the ACL was only loaded for a
* subset of SIDs
* @see DefaultPermissionGrantingStrategy
*/
public boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
throws NotFoundException, UnloadedSidException {
@@ -193,7 +207,64 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
throw new UnloadedSidException("ACL was not loaded for one or more SID");
}
return permissionGrantingStrategy.isGranted(this, permission, sids, administrativeMode);
AccessControlEntry firstRejection = null;
for (Permission p : permission) {
for (Sid sid: sids) {
// Attempt to find exact match for this permission mask and SID
boolean scanNextSid = true;
for (AccessControlEntry ace : aces ) {
if ((ace.getPermission().getMask() == p.getMask()) && ace.getSid().equals(sid)) {
// Found a matching ACE, so its authorization decision will prevail
if (ace.isGranting()) {
// Success
if (!administrativeMode) {
auditLogger.logIfNeeded(true, ace);
}
return true;
}
// Failure for this permission, so stop search
// We will see if they have a different permission
// (this permission is 100% rejected for this SID)
if (firstRejection == null) {
// Store first rejection for auditing reasons
firstRejection = ace;
}
scanNextSid = false; // helps break the loop
break; // exit aces loop
}
}
if (!scanNextSid) {
break; // exit SID for loop (now try next permission)
}
}
}
if (firstRejection != null) {
// We found an ACE to reject the request at this point, as no
// other ACEs were found that granted a different permission
if (!administrativeMode) {
auditLogger.logIfNeeded(false, firstRejection);
}
return false;
}
// No matches have been found so far
if (isEntriesInheriting() && (parentAcl != null)) {
// We have a parent, so let them try to find a matching ACE
return parentAcl.isGranted(permission, sids, false);
} else {
// We either have no parent, or we're the uppermost parent
throw new NotFoundException("Unable to locate a matching ACE for passed permissions and SIDs");
}
}
public boolean isSidLoaded(List<Sid> sids) {
@@ -249,6 +320,39 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
return parentAcl;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("AclImpl[");
sb.append("id: ").append(this.id).append("; ");
sb.append("objectIdentity: ").append(this.objectIdentity).append("; ");
sb.append("owner: ").append(this.owner).append("; ");
int count = 0;
for (AccessControlEntry ace : aces) {
count++;
if (count == 1) {
sb.append("\r\n");
}
sb.append(ace).append("\r\n");
}
if (count == 0) {
sb.append("no ACEs; ");
}
sb.append("inheriting: ").append(this.entriesInheriting).append("; ");
sb.append("parent: ").append((this.parentAcl == null) ? "Null" : this.parentAcl.getObjectIdentity().toString());
sb.append("; ");
sb.append("aclAuthorizationStrategy: ").append(this.aclAuthorizationStrategy).append("; ");
sb.append("auditLogger: ").append(this.auditLogger);
sb.append("]");
return sb.toString();
}
public void updateAce(int aceIndex, Permission permission)
throws NotFoundException {
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
@@ -275,15 +379,15 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
if (obj instanceof AclImpl) {
AclImpl rhs = (AclImpl) obj;
if (this.aces.equals(rhs.aces)) {
if ((this.parentAcl == null && rhs.parentAcl == null) || (this.parentAcl !=null && this.parentAcl.equals(rhs.parentAcl))) {
if ((this.objectIdentity == null && rhs.objectIdentity == null) || (this.objectIdentity != null && this.objectIdentity.equals(rhs.objectIdentity))) {
if ((this.id == null && rhs.id == null) || (this.id != null && this.id.equals(rhs.id))) {
if ((this.owner == null && rhs.owner == null) || (this.owner != null && this.owner.equals(rhs.owner))) {
if ((this.parentAcl == null && rhs.parentAcl == null) || (this.parentAcl.equals(rhs.parentAcl))) {
if ((this.objectIdentity == null && rhs.objectIdentity == null) || (this.objectIdentity.equals(rhs.objectIdentity))) {
if ((this.id == null && rhs.id == null) || (this.id.equals(rhs.id))) {
if ((this.owner == null && rhs.owner == null) || this.owner.equals(rhs.owner)) {
if (this.entriesInheriting == rhs.entriesInheriting) {
if ((this.loadedSids == null && rhs.loadedSids == null)) {
return true;
}
if (this.loadedSids != null && (this.loadedSids.size() == rhs.loadedSids.size())) {
if (this.loadedSids.size() == rhs.loadedSids.size()) {
for (int i = 0; i < this.loadedSids.size(); i++) {
if (!this.loadedSids.get(i).equals(rhs.loadedSids.get(i))) {
return false;
@@ -301,37 +405,4 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
return false;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("AclImpl[");
sb.append("id: ").append(this.id).append("; ");
sb.append("objectIdentity: ").append(this.objectIdentity).append("; ");
sb.append("owner: ").append(this.owner).append("; ");
int count = 0;
for (AccessControlEntry ace : aces) {
count++;
if (count == 1) {
sb.append("\n");
}
sb.append(ace).append("\n");
}
if (count == 0) {
sb.append("no ACEs; ");
}
sb.append("inheriting: ").append(this.entriesInheriting).append("; ");
sb.append("parent: ").append((this.parentAcl == null) ? "Null" : this.parentAcl.getObjectIdentity().toString());
sb.append("; ");
sb.append("aclAuthorizationStrategy: ").append(this.aclAuthorizationStrategy).append("; ");
sb.append("permissionGrantingStrategy: ").append(this.permissionGrantingStrategy);
sb.append("]");
return sb.toString();
}
}
@@ -64,19 +64,18 @@ public class DefaultPermissionFactory implements PermissionFactory {
Field[] fields = clazz.getFields();
for (Field field : fields) {
for (int i = 0; i < fields.length; i++) {
try {
Object fieldValue = field.get(null);
Object fieldValue = fields[i].get(null);
if (Permission.class.isAssignableFrom(fieldValue.getClass())) {
// Found a Permission static field
Permission perm = (Permission) fieldValue;
String permissionName = field.getName();
String permissionName = fields[i].getName();
registerPermission(perm, permissionName);
}
} catch (Exception ignore) {
}
} catch (Exception ignore) {}
}
}
@@ -84,7 +83,7 @@ public class DefaultPermissionFactory implements PermissionFactory {
Assert.notNull(perm, "Permission required");
Assert.hasText(permissionName, "Permission name required");
Integer mask = Integer.valueOf(perm.getMask());
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);
@@ -98,7 +97,7 @@ public class DefaultPermissionFactory implements PermissionFactory {
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(Integer.valueOf(mask));
return registeredPermissionsByInteger.get(new Integer(mask));
}
// To get this far, we have to use a CumulativePermission
@@ -1,119 +0,0 @@
package org.springframework.security.acls.domain;
import java.util.List;
import org.springframework.security.acls.model.AccessControlEntry;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.PermissionGrantingStrategy;
import org.springframework.security.acls.model.Sid;
import org.springframework.util.Assert;
public class DefaultPermissionGrantingStrategy implements PermissionGrantingStrategy {
private final transient AuditLogger auditLogger;
/**
* Creates an instance with the logger which will be used to record granting and denial of requested permissions.
*/
public DefaultPermissionGrantingStrategy(AuditLogger auditLogger) {
Assert.notNull(auditLogger, "auditLogger cannot be null");
this.auditLogger = auditLogger;
}
/**
* Determines authorization. The order of the <code>permission</code> and <code>sid</code> arguments is
* <em>extremely important</em>! The method will iterate through each of the <code>permission</code>s in the order
* specified. For each iteration, all of the <code>sid</code>s will be considered, again in the order they are
* presented. A search will then be performed for the first {@link AccessControlEntry} object that directly
* matches that <code>permission:sid</code> combination. When the <em>first full match</em> is found (ie an ACE
* that has the SID currently being searched for and the exact permission bit mask being search for), the grant or
* deny flag for that ACE will prevail. If the ACE specifies to grant access, the method will return
* <code>true</code>. If the ACE specifies to deny access, the loop will stop and the next <code>permission</code>
* iteration will be performed. If each permission indicates to deny access, the first deny ACE found will be
* considered the reason for the failure (as it was the first match found, and is therefore the one most logically
* requiring changes - although not always). If absolutely no matching ACE was found at all for any permission,
* the parent ACL will be tried (provided that there is a parent and {@link Acl#isEntriesInheriting()} is
* <code>true</code>. The parent ACL will also scan its parent and so on. If ultimately no matching ACE is found,
* a <code>NotFoundException</code> will be thrown and the caller will need to decide how to handle the permission
* check. Similarly, if any of the SID arguments presented to the method were not loaded by the ACL,
* <code>UnloadedSidException</code> will be thrown.
*
* @param permission the exact permissions to scan for (order is important)
* @param sids the exact SIDs to scan for (order is important)
* @param administrativeMode if <code>true</code> denotes the query is for administrative purposes and no auditing
* will be undertaken
*
* @return <code>true</code> if one of the permissions has been granted, <code>false</code> if one of the
* permissions has been specifically revoked
*
* @throws NotFoundException if an exact ACE for one of the permission bit masks and SID combination could not be
* found
*/
public boolean isGranted(Acl acl, List<Permission> permission, List<Sid> sids, boolean administrativeMode)
throws NotFoundException {
final List<AccessControlEntry> aces = acl.getEntries();
AccessControlEntry firstRejection = null;
for (Permission p : permission) {
for (Sid sid: sids) {
// Attempt to find exact match for this permission mask and SID
boolean scanNextSid = true;
for (AccessControlEntry ace : aces ) {
if ((ace.getPermission().getMask() == p.getMask()) && ace.getSid().equals(sid)) {
// Found a matching ACE, so its authorization decision will prevail
if (ace.isGranting()) {
// Success
if (!administrativeMode) {
auditLogger.logIfNeeded(true, ace);
}
return true;
}
// Failure for this permission, so stop search
// We will see if they have a different permission
// (this permission is 100% rejected for this SID)
if (firstRejection == null) {
// Store first rejection for auditing reasons
firstRejection = ace;
}
scanNextSid = false; // helps break the loop
break; // exit aces loop
}
}
if (!scanNextSid) {
break; // exit SID for loop (now try next permission)
}
}
}
if (firstRejection != null) {
// We found an ACE to reject the request at this point, as no
// other ACEs were found that granted a different permission
if (!administrativeMode) {
auditLogger.logIfNeeded(false, firstRejection);
}
return false;
}
// No matches have been found so far
if (acl.isEntriesInheriting() && (acl.getParentAcl() != null)) {
// We have a parent, so let them try to find a matching ACE
return acl.getParentAcl().isGranted(permission, sids, false);
} else {
// We either have no parent, or we're the uppermost parent
throw new NotFoundException("Unable to locate a matching ACE for passed permissions and SIDs");
}
}
}
@@ -23,48 +23,34 @@ import net.sf.ehcache.Element;
import org.springframework.security.acls.model.AclCache;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.PermissionGrantingStrategy;
import org.springframework.security.util.FieldUtils;
import org.springframework.util.Assert;
/**
* Simple implementation of {@link AclCache} that delegates to EH-CACHE.
*
* <p>
* Designed to handle the transient fields in {@link AclImpl}. Note that this implementation assumes all
* {@link AclImpl} instances share the same {@link PermissionGrantingStrategy} and {@link AclAuthorizationStrategy}
* instances.
* {@link AclImpl} instances share the same {@link AuditLogger} and {@link AclAuthorizationStrategy} instance.
* </p>
*
* @author Ben Alex
*/
public class EhCacheBasedAclCache implements AclCache {
//~ Instance fields ================================================================================================
private final Ehcache cache;
private PermissionGrantingStrategy permissionGrantingStrategy;
private Ehcache cache;
private AuditLogger auditLogger;
private AclAuthorizationStrategy aclAuthorizationStrategy;
//~ Constructors ===================================================================================================
/**
* @deprecated use the second constructor which injects the strategy objects. See SEC-1498.
*/
@Deprecated
public EhCacheBasedAclCache(Ehcache cache) {
Assert.notNull(cache, "Cache required");
this.cache = cache;
}
public EhCacheBasedAclCache(Ehcache cache, PermissionGrantingStrategy permissionGrantingStrategy,
AclAuthorizationStrategy aclAuthorizationStrategy) {
Assert.notNull(cache, "Cache required");
Assert.notNull(permissionGrantingStrategy, "PermissionGrantingStrategy required");
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
this.cache = cache;
this.permissionGrantingStrategy = permissionGrantingStrategy;
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
}
//~ Methods ========================================================================================================
public void evictFromCache(Serializable pk) {
@@ -129,7 +115,7 @@ public class EhCacheBasedAclCache implements AclCache {
if (this.aclAuthorizationStrategy == null) {
if (acl instanceof AclImpl) {
this.aclAuthorizationStrategy = (AclAuthorizationStrategy) FieldUtils.getProtectedFieldValue("aclAuthorizationStrategy", acl);
this.permissionGrantingStrategy = (PermissionGrantingStrategy) FieldUtils.getProtectedFieldValue("permissionGrantingStrategy", acl);
this.auditLogger = (AuditLogger) FieldUtils.getProtectedFieldValue("auditLogger", acl);
}
}
@@ -144,7 +130,7 @@ public class EhCacheBasedAclCache implements AclCache {
private MutableAcl initializeTransientFields(MutableAcl value) {
if (value instanceof AclImpl) {
FieldUtils.setProtectedFieldValue("aclAuthorizationStrategy", value, this.aclAuthorizationStrategy);
FieldUtils.setProtectedFieldValue("permissionGrantingStrategy", value, this.permissionGrantingStrategy);
FieldUtils.setProtectedFieldValue("auditLogger", value, this.auditLogger);
}
if (value.getParentAcl() != null) {
@@ -30,7 +30,7 @@ import org.springframework.util.Assert;
public class GrantedAuthoritySid implements Sid {
//~ Instance fields ================================================================================================
private final String grantedAuthority;
private String grantedAuthority;
//~ Constructors ===================================================================================================
@@ -78,7 +78,7 @@ public class ObjectIdentityImpl implements ObjectIdentity {
try {
Method method = typeClass.getMethod("getId", new Class[] {});
result = method.invoke(object);
result = method.invoke(object, new Object[] {});
} catch (Exception e) {
throw new IdentityUnavailableException("Could not extract identity from object " + object, e);
}
@@ -32,7 +32,7 @@ import org.springframework.util.Assert;
public class PrincipalSid implements Sid {
//~ Instance fields ================================================================================================
private final String principal;
private String principal;
//~ Constructors ===================================================================================================
@@ -51,7 +51,7 @@ public class SidRetrievalStrategyImpl implements SidRetrievalStrategy {
//~ Methods ========================================================================================================
public List<Sid> getSids(Authentication authentication) {
Collection<? extends GrantedAuthority> authorities = roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
Collection<GrantedAuthority> authorities = roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
List<Sid> sids = new ArrayList<Sid>(authorities.size() + 1);
sids.add(new PrincipalSid(authentication));
@@ -29,6 +29,7 @@ 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;
@@ -37,7 +38,6 @@ 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.DefaultPermissionGrantingStrategy;
import org.springframework.security.acls.domain.GrantedAuthoritySid;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PermissionFactory;
@@ -49,7 +49,6 @@ 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.PermissionGrantingStrategy;
import org.springframework.security.acls.model.Sid;
import org.springframework.security.acls.model.UnloadedSidException;
import org.springframework.security.util.FieldUtils;
@@ -107,11 +106,11 @@ public final class BasicLookupStrategy implements LookupStrategy {
//~ Instance fields ================================================================================================
private final AclAuthorizationStrategy aclAuthorizationStrategy;
private AclAuthorizationStrategy aclAuthorizationStrategy;
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
private final AclCache aclCache;
private final PermissionGrantingStrategy grantingStrategy;
private final JdbcTemplate jdbcTemplate;
private AclCache aclCache;
private AuditLogger auditLogger;
private JdbcTemplate jdbcTemplate;
private int batchSize = 50;
private final Field fieldAces = FieldUtils.getField(AclImpl.class, "aces");
@@ -131,28 +130,19 @@ public final class BasicLookupStrategy implements LookupStrategy {
* @param dataSource to access the database
* @param aclCache the cache where fully-loaded elements can be stored
* @param aclAuthorizationStrategy authorization strategy (required)
*
* @deprecated Use the version which takes a {@code PermissionGrantingStrategy} argument instead.
*/
@Deprecated
public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
AclAuthorizationStrategy aclAuthorizationStrategy, AuditLogger auditLogger) {
this(dataSource, aclCache, aclAuthorizationStrategy, new DefaultPermissionGrantingStrategy(auditLogger));
}
public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
AclAuthorizationStrategy aclAuthorizationStrategy, PermissionGrantingStrategy grantingStrategy) {
AclAuthorizationStrategy aclAuthorizationStrategy, AuditLogger auditLogger) {
Assert.notNull(dataSource, "DataSource required");
Assert.notNull(aclCache, "AclCache required");
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
Assert.notNull(grantingStrategy, "grantingStrategy required");
Assert.notNull(auditLogger, "AuditLogger required");
jdbcTemplate = new JdbcTemplate(dataSource);
this.aclCache = aclCache;
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
this.grantingStrategy = grantingStrategy;
this.auditLogger = auditLogger;
fieldAces.setAccessible(true);
fieldAcl.setAccessible(true);
}
//~ Methods ========================================================================================================
@@ -405,7 +395,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
// Now we have the parent (if there is one), create the true AclImpl
AclImpl result = new AclImpl(inputAcl.getObjectIdentity(), (Long) inputAcl.getId(), aclAuthorizationStrategy,
grantingStrategy, parent, null, inputAcl.isEntriesInheriting(), inputAcl.getOwner());
auditLogger, parent, null, inputAcl.isEntriesInheriting(), inputAcl.getOwner());
// Copy the "aces" from the input to the destination
@@ -476,8 +466,8 @@ public final class BasicLookupStrategy implements LookupStrategy {
//~ Inner Classes ==================================================================================================
private class ProcessResultSet implements ResultSetExtractor<Set<Long>> {
private final Map<Serializable, Acl> acls;
private final List<Sid> sids;
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");
@@ -494,8 +484,9 @@ public final class BasicLookupStrategy implements LookupStrategy {
* @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 {
public Set<Long> extractData(ResultSet rs) throws SQLException, DataAccessException {
Set<Long> parentIdsToLookup = new HashSet<Long>(); // Set of parent_id Longs
while (rs.next()) {
@@ -564,7 +555,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
owner = new GrantedAuthoritySid(rs.getString("acl_sid"));
}
acl = new AclImpl(objectIdentity, id, aclAuthorizationStrategy, grantingStrategy, parentAcl, null,
acl = new AclImpl(objectIdentity, id, aclAuthorizationStrategy, auditLogger, parentAcl, null,
entriesInheriting, owner);
acls.put(id, acl);
@@ -603,7 +594,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
}
private class StubAclParent implements Acl {
private final Long id;
private Long id;
public StubAclParent(Long id) {
this.id = id;
@@ -56,8 +56,8 @@ public class JdbcAclService implements AclService {
//~ Instance fields ================================================================================================
protected final JdbcTemplate jdbcTemplate;
private final LookupStrategy lookupStrategy;
protected JdbcTemplate jdbcTemplate;
private LookupStrategy lookupStrategy;
private String findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL;
//~ Constructors ===================================================================================================
@@ -109,9 +109,10 @@ public class JdbcAclService implements AclService {
Map<ObjectIdentity, Acl> result = lookupStrategy.readAclsById(objects, sids);
// Check every requested object identity was found (throw NotFoundException if needed)
for (ObjectIdentity oid : objects) {
if (!result.containsKey(oid)) {
throw new NotFoundException("Unable to find ACL information for object identity '" + oid + "'");
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) + "'");
}
}
@@ -61,7 +61,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
//~ Instance fields ================================================================================================
private boolean foreignKeysInDatabase = true;
private final AclCache aclCache;
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()";
@@ -194,7 +194,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
Assert.notNull(sid, "Sid required");
String sidName;
String sidName = null;
boolean sidIsPrincipal = true;
if (sid instanceof PrincipalSid) {
@@ -214,7 +214,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
}
if (allowCreate) {
jdbcTemplate.update(insertSid, Boolean.valueOf(sidIsPrincipal), sidName);
jdbcTemplate.update(insertSid, new Object[] {Boolean.valueOf(sidIsPrincipal), sidName});
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
return new Long(jdbcTemplate.queryForLong(sidIdentityQuery));
}
@@ -229,8 +229,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
if (deleteChildren) {
List<ObjectIdentity> children = findChildren(objectIdentity);
if (children != null) {
for (ObjectIdentity child : children) {
deleteAcl(child, true);
for (int i = 0; i < children.size(); i++) {
deleteAcl(children.get(i), true);
}
}
} else {
@@ -263,7 +263,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
* @param oidPrimaryKey the rows in acl_entry to delete
*/
protected void deleteEntries(Long oidPrimaryKey) {
jdbcTemplate.update(deleteEntryByObjectIdentityForeignKey, oidPrimaryKey);
jdbcTemplate.update(deleteEntryByObjectIdentityForeignKey,
new Object[] {oidPrimaryKey});
}
/**
@@ -276,7 +277,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
*/
protected void deleteObjectIdentity(Long oidPrimaryKey) {
// Delete the acl_object_identity row
jdbcTemplate.update(deleteObjectIdentityByPrimaryKey, oidPrimaryKey);
jdbcTemplate.update(deleteObjectIdentityByPrimaryKey, new Object[] {oidPrimaryKey});
}
/**
@@ -290,7 +291,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
*/
protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
try {
return new Long(jdbcTemplate.queryForLong(selectObjectIdentityPrimaryKey, oid.getType(), oid.getIdentifier()));
return new Long(jdbcTemplate.queryForLong(selectObjectIdentityPrimaryKey,
new Object[] {oid.getType(), oid.getIdentifier()}));
} catch (DataAccessException notFound) {
return null;
}
@@ -324,8 +326,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
Assert.notNull(objectIdentity, "ObjectIdentity required");
List<ObjectIdentity> children = findChildren(objectIdentity);
if (children != null) {
for (ObjectIdentity child : children) {
clearCacheIncludingChildren(child);
for (int i = 0; i < children.size(); i++) {
clearCacheIncludingChildren(children.get(i));
}
}
aclCache.evictFromCache(objectIdentity);
@@ -354,7 +356,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
Long ownerSid = createOrRetrieveSidPrimaryKey(acl.getOwner(), true);
int count = jdbcTemplate.update(updateObjectIdentity,
parentId, ownerSid, Boolean.valueOf(acl.isEntriesInheriting()), acl.getId());
new Object[] {parentId, ownerSid, new Boolean(acl.isEntriesInheriting()), acl.getId()});
if (count != 1) {
throw new NotFoundException("Unable to locate ACL to update");
@@ -1,20 +0,0 @@
package org.springframework.security.acls.model;
import java.util.List;
/**
* Allow customization of the logic for determining whether a permission or permissions are granted to a particular
* sid or sids by an {@link Acl}.
*
* @author Luke Taylor
* @since 3.0.2
*/
public interface PermissionGrantingStrategy {
/**
* Returns true if the the supplied strategy decides that the supplied {@code Acl} grants access
* based on the supplied list of permissions and sids.
*/
boolean isGranted(Acl acl, List<Permission> permission, List<Sid> sids, boolean administrativeMode);
}
@@ -1,56 +0,0 @@
package org.springframework.security.acls;
import static org.mockito.Mockito.*;
import org.junit.Test;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
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;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* @author Luke Taylor
*/
@SuppressWarnings({"unchecked"})
public class AclPermissionCacheOptimizerTests {
@Test
public void eagerlyLoadsRequiredAcls() throws Exception {
AclService service = mock(AclService.class);
AclPermissionCacheOptimizer pco = new AclPermissionCacheOptimizer(service);
ObjectIdentityRetrievalStrategy oidStrat = mock(ObjectIdentityRetrievalStrategy.class);
SidRetrievalStrategy sidStrat = mock(SidRetrievalStrategy.class);
pco.setObjectIdentityRetrievalStrategy(oidStrat);
pco.setSidRetrievalStrategy(sidStrat);
Object[] dos = {new Object(), null, new Object()};
ObjectIdentity[] oids = {new ObjectIdentityImpl("A", "1"), new ObjectIdentityImpl("A", "2")};
when(oidStrat.getObjectIdentity(dos[0])).thenReturn(oids[0]);
when(oidStrat.getObjectIdentity(dos[2])).thenReturn(oids[1]);
pco.cachePermissionsFor(mock(Authentication.class), Arrays.asList(dos));
// AclService should be invoked with the list of required Oids
verify(service).readAclsById(eq(Arrays.asList(oids)), any(List.class));
}
@Test
public void ignoresEmptyCollection() {
AclService service = mock(AclService.class);
AclPermissionCacheOptimizer pco = new AclPermissionCacheOptimizer(service);
ObjectIdentityRetrievalStrategy oids = mock(ObjectIdentityRetrievalStrategy.class);
SidRetrievalStrategy sids = mock(SidRetrievalStrategy.class);
pco.setObjectIdentityRetrievalStrategy(oids);
pco.setSidRetrievalStrategy(sids);
pco.cachePermissionsFor(mock(Authentication.class), Collections.emptyList());
verifyZeroInteractions(service, sids, oids);
}
}
@@ -1,64 +0,0 @@
package org.springframework.security.acls.afterinvocation;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.when;
import org.junit.Test;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.acls.model.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.SpringSecurityMessageSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* @author Luke Taylor
*/
@SuppressWarnings({"unchecked"})
public class AclEntryAfterInvocationCollectionFilteringProviderTests {
@Test
public void objectsAreRemovedIfPermissionDenied() throws Exception {
AclService service = mock(AclService.class);
Acl acl = mock(Acl.class);
when(acl.isGranted(any(List.class), any(List.class), anyBoolean())).thenReturn(false);
when(service.readAclById(any(ObjectIdentity.class), any(List.class))).thenReturn(acl);
AclEntryAfterInvocationCollectionFilteringProvider provider = new AclEntryAfterInvocationCollectionFilteringProvider(service, Arrays.asList(mock(Permission.class)));
provider.setObjectIdentityRetrievalStrategy(mock(ObjectIdentityRetrievalStrategy.class));
provider.setProcessDomainObjectClass(Object.class);
provider.setSidRetrievalStrategy(mock(SidRetrievalStrategy.class));
Object returned = provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("AFTER_ACL_COLLECTION_READ"), new ArrayList(Arrays.asList(new Object(), new Object())));
assertTrue(returned instanceof List);
assertTrue(((List)returned).isEmpty());
returned = provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("UNSUPPORTED", "AFTER_ACL_COLLECTION_READ"), new Object[] {new Object(), new Object()});
assertTrue(returned instanceof Object[]);
assertTrue(((Object[])returned).length == 0);
}
@Test
public void accessIsGrantedIfNoAttributesDefined() throws Exception {
AclEntryAfterInvocationCollectionFilteringProvider provider = new AclEntryAfterInvocationCollectionFilteringProvider(mock(AclService.class), Arrays.asList(mock(Permission.class)));
Object returned = new Object();
assertSame(returned, provider.decide(mock(Authentication.class), new Object(), Collections.<ConfigAttribute>emptyList(), returned));
}
@Test
public void nullReturnObjectIsIgnored() throws Exception {
AclService service = mock(AclService.class);
AclEntryAfterInvocationCollectionFilteringProvider provider = new AclEntryAfterInvocationCollectionFilteringProvider(service, Arrays.asList(mock(Permission.class)));
assertNull(provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("AFTER_ACL_COLLECTION_READ"), null));
verify(service, never()).readAclById(any(ObjectIdentity.class), any(List.class));
}
}
@@ -1,101 +0,0 @@
package org.springframework.security.acls.afterinvocation;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
import org.junit.Test;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.acls.model.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.SpringSecurityMessageSource;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* @author Luke Taylor
*/
@SuppressWarnings({"unchecked"})
public class AclEntryAfterInvocationProviderTests {
@Test(expected=IllegalArgumentException.class)
public void rejectsMissingPermissions() throws Exception {
try {
new AclEntryAfterInvocationProvider(mock(AclService.class), null);
fail("Exception expected");
} catch (IllegalArgumentException expected) {
}
new AclEntryAfterInvocationProvider(mock(AclService.class), Collections.<Permission>emptyList());
}
@Test
public void accessIsAllowedIfPermissionIsGranted() {
AclService service = mock(AclService.class);
Acl acl = mock(Acl.class);
when(acl.isGranted(any(List.class), any(List.class), anyBoolean())).thenReturn(true);
when(service.readAclById(any(ObjectIdentity.class), any(List.class))).thenReturn(acl);
AclEntryAfterInvocationProvider provider = new AclEntryAfterInvocationProvider(service, Arrays.asList(mock(Permission.class)));
provider.setMessageSource(new SpringSecurityMessageSource());
provider.setObjectIdentityRetrievalStrategy(mock(ObjectIdentityRetrievalStrategy.class));
provider.setProcessDomainObjectClass(Object.class);
provider.setSidRetrievalStrategy(mock(SidRetrievalStrategy.class));
Object returned = new Object();
assertSame(returned, provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("AFTER_ACL_READ"), returned));
}
@Test
public void accessIsGrantedIfNoAttributesDefined() throws Exception {
AclEntryAfterInvocationProvider provider = new AclEntryAfterInvocationProvider(mock(AclService.class), Arrays.asList(mock(Permission.class)));
Object returned = new Object();
assertSame(returned, provider.decide(mock(Authentication.class), new Object(), Collections.<ConfigAttribute>emptyList(), returned));
}
@Test
public void accessIsGrantedIfObjectTypeNotSupported() throws Exception {
AclEntryAfterInvocationProvider provider = new AclEntryAfterInvocationProvider(mock(AclService.class), Arrays.asList(mock(Permission.class)));
provider.setProcessDomainObjectClass(String.class);
// Not a String
Object returned = new Object();
assertSame(returned, provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("AFTER_ACL_READ"), returned));
}
@Test(expected= AccessDeniedException.class)
public void accessIsDeniedIfPermissionIsNotGranted() {
AclService service = mock(AclService.class);
Acl acl = mock(Acl.class);
when(acl.isGranted(any(List.class), any(List.class), anyBoolean())).thenReturn(false);
// Try a second time with no permissions found
when(acl.isGranted(any(List.class), any(List.class), anyBoolean())).thenThrow(new NotFoundException(""));
when(service.readAclById(any(ObjectIdentity.class), any(List.class))).thenReturn(acl);
AclEntryAfterInvocationProvider provider = new AclEntryAfterInvocationProvider(service, Arrays.asList(mock(Permission.class)));
provider.setProcessConfigAttribute("MY_ATTRIBUTE");
provider.setMessageSource(new SpringSecurityMessageSource());
provider.setObjectIdentityRetrievalStrategy(mock(ObjectIdentityRetrievalStrategy.class));
provider.setProcessDomainObjectClass(Object.class);
provider.setSidRetrievalStrategy(mock(SidRetrievalStrategy.class));
try {
provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("UNSUPPORTED", "MY_ATTRIBUTE"), new Object());
fail();
} catch (AccessDeniedException expected) {
}
// Second scenario with no acls found
provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("UNSUPPORTED", "MY_ATTRIBUTE"), new Object());
}
@Test
public void nullReturnObjectIsIgnored() throws Exception {
AclService service = mock(AclService.class);
AclEntryAfterInvocationProvider provider = new AclEntryAfterInvocationProvider(service, Arrays.asList(mock(Permission.class)));
assertNull(provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("AFTER_ACL_COLLECTION_READ"), null));
verify(service, never()).readAclById(any(ObjectIdentity.class), any(List.class));
}
}
@@ -1,8 +1,10 @@
package org.springframework.security.acls.domain;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
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;
@@ -16,6 +18,7 @@ import org.springframework.security.acls.model.Sid;
* @author Andrei Stefan
*/
public class AccessControlImplEntryTests {
Mockery jmock = new JUnit4Mockery();
//~ Methods ========================================================================================================
@@ -32,7 +35,7 @@ public class AccessControlImplEntryTests {
// Check Sid field is present
try {
new AccessControlEntryImpl(null, mock(Acl.class), null,
new AccessControlEntryImpl(null, jmock.mock(Acl.class), null,
BasePermission.ADMINISTRATION, true, true, true);
fail("It should have thrown IllegalArgumentException");
}
@@ -41,7 +44,7 @@ public class AccessControlImplEntryTests {
// Check Permission field is present
try {
new AccessControlEntryImpl(null, mock(Acl.class), new PrincipalSid("johndoe"), null,
new AccessControlEntryImpl(null, jmock.mock(Acl.class), new PrincipalSid("johndoe"), null,
true, true, true);
fail("It should have thrown IllegalArgumentException");
}
@@ -51,11 +54,11 @@ public class AccessControlImplEntryTests {
@Test
public void testAccessControlEntryImplGetters() {
Acl mockAcl = mock(Acl.class);
Acl mockAcl = jmock.mock(Acl.class);
Sid sid = new PrincipalSid("johndoe");
// Create a sample entry
AccessControlEntry ace = new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid, BasePermission.ADMINISTRATION,
AccessControlEntry ace = new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.ADMINISTRATION,
true, true, true);
// and check every get() method
@@ -70,31 +73,32 @@ public class AccessControlImplEntryTests {
@Test
public void testEquals() {
final Acl mockAcl = mock(Acl.class);
final ObjectIdentity oid = mock(ObjectIdentity.class);
when(mockAcl.getObjectIdentity()).thenReturn(oid);
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(Long.valueOf(1), mockAcl, sid, BasePermission.ADMINISTRATION,
AccessControlEntry ace = new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.ADMINISTRATION,
true, true, true);
assertFalse(ace.equals(null));
assertFalse(ace.equals(Long.valueOf(100)));
assertFalse(ace.equals(new Long(100)));
assertTrue(ace.equals(ace));
assertTrue(ace.equals(new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid,
assertTrue(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
BasePermission.ADMINISTRATION, true, true, true)));
assertFalse(ace.equals(new AccessControlEntryImpl(Long.valueOf(2), mockAcl, sid,
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(2), mockAcl, sid,
BasePermission.ADMINISTRATION, true, true, true)));
assertFalse(ace.equals(new AccessControlEntryImpl(Long.valueOf(1), mockAcl, new PrincipalSid("scott"),
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, new PrincipalSid("scott"),
BasePermission.ADMINISTRATION, true, true, true)));
assertFalse(ace.equals(new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid, BasePermission.WRITE, true,
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.WRITE, true,
true, true)));
assertFalse(ace.equals(new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid,
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
BasePermission.ADMINISTRATION, false, true, true)));
assertFalse(ace.equals(new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid,
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
BasePermission.ADMINISTRATION, true, false, true)));
assertFalse(ace.equals(new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid,
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
BasePermission.ADMINISTRATION, true, true, false)));
}
}
@@ -1,18 +1,37 @@
package org.springframework.security.acls.domain;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.junit.*;
import org.springframework.security.acls.model.*;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.util.FieldUtils;
import static org.mockito.Mockito.mock;
import java.lang.reflect.Field;
import java.util.*;
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;
/**
@@ -30,8 +49,8 @@ public class AclImplTests {
private static final List<Sid> BEN = Arrays.asList((Sid)new PrincipalSid("ben"));
Authentication auth = new TestingAuthenticationToken("joe", "ignored", "ROLE_ADMINISTRATOR");
AclAuthorizationStrategy authzStrategy;
PermissionGrantingStrategy pgs;
Mockery jmockCtx = new Mockery();
AclAuthorizationStrategy mockAuthzStrategy;
AuditLogger mockAuditLogger;
ObjectIdentity objectIdentity = new ObjectIdentityImpl(TARGET_CLASS, 100);
@@ -40,9 +59,8 @@ public class AclImplTests {
@Before
public void setUp() throws Exception {
SecurityContextHolder.getContext().setAuthentication(auth);
authzStrategy = mock(AclAuthorizationStrategy.class);
mockAuditLogger = mock(AuditLogger.class);
pgs = new DefaultPermissionGrantingStrategy(mockAuditLogger);
mockAuthzStrategy = mock(AclAuthorizationStrategy.class);
mockAuditLogger = mock(AuditLogger.class);;
auth.setAuthenticated(true);
}
@@ -54,26 +72,25 @@ public class AclImplTests {
@Test(expected=IllegalArgumentException.class)
public void constructorsRejectNullObjectIdentity() throws Exception {
try {
new AclImpl(null, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
new AclImpl(null, 1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid("joe"));
fail("Should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
}
new AclImpl(null, 1, authzStrategy, mockAuditLogger);
new AclImpl(null, 1, mockAuthzStrategy, mockAuditLogger);
}
@Test(expected=IllegalArgumentException.class)
public void constructorsRejectNullId() throws Exception {
try {
new AclImpl(objectIdentity, null, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
new AclImpl(objectIdentity, null, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid("joe"));
fail("Should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
}
new AclImpl(objectIdentity, null, authzStrategy, mockAuditLogger);
new AclImpl(objectIdentity, null, mockAuthzStrategy, mockAuditLogger);
}
@SuppressWarnings("deprecation")
@Test(expected=IllegalArgumentException.class)
public void constructorsRejectNullAclAuthzStrategy() throws Exception {
try {
@@ -85,9 +102,20 @@ public class AclImplTests {
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, authzStrategy, pgs, null, null, true, new PrincipalSid(
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid(
"joe"));
try {
acl.insertAce(0, null, new GrantedAuthoritySid("ROLE_IGNORED"), true);
@@ -105,7 +133,7 @@ public class AclImplTests {
@Test
public void insertAceAddsElementAtCorrectIndex() throws Exception {
MutableAcl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid("joe"));
MockAclService service = new MockAclService();
// Insert one permission
@@ -141,7 +169,7 @@ public class AclImplTests {
@Test(expected=NotFoundException.class)
public void insertAceFailsForNonExistentElement() throws Exception {
MutableAcl acl = new AclImpl(objectIdentity,1, authzStrategy, pgs, null, null, true, new PrincipalSid(
MutableAcl acl = new AclImpl(objectIdentity,1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid(
"joe"));
MockAclService service = new MockAclService();
@@ -154,7 +182,8 @@ public class AclImplTests {
@Test
public void deleteAceKeepsInitialOrdering() throws Exception {
MutableAcl acl = new AclImpl(objectIdentity,1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
MutableAcl acl = new AclImpl(objectIdentity,1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid(
"joe"));
MockAclService service = new MockAclService();
// Add several permissions
@@ -185,10 +214,11 @@ public class AclImplTests {
@Test
public void deleteAceFailsForNonExistentElement() throws Exception {
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
MutableAcl acl = new AclImpl(objectIdentity, (1), strategy, pgs, null, null, true, new PrincipalSid(
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);
@@ -200,7 +230,8 @@ public class AclImplTests {
@Test
public void isGrantingRejectsEmptyParameters() throws Exception {
MutableAcl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
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);
@@ -224,7 +255,8 @@ public class AclImplTests {
ObjectIdentity rootOid = new ObjectIdentityImpl(TARGET_CLASS, 100);
// Create an ACL which owner is not the authenticated principal
MutableAcl rootAcl = new AclImpl(rootOid, 1, authzStrategy, pgs, null, null, false, new PrincipalSid("joe"));
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);
@@ -267,12 +299,16 @@ public class AclImplTests {
ObjectIdentity childOid2 = new ObjectIdentityImpl(TARGET_CLASS, 104);
// Create ACLs
PrincipalSid joe = new PrincipalSid("joe");
MutableAcl grandParentAcl = new AclImpl(grandParentOid, 1, authzStrategy, pgs, null, null, false, joe);
MutableAcl parentAcl1 = new AclImpl(parentOid1, 2, authzStrategy, pgs, null, null, true, joe);
MutableAcl parentAcl2 = new AclImpl(parentOid2, 3, authzStrategy, pgs, null, null, true, joe);
MutableAcl childAcl1 = new AclImpl(childOid1, 4, authzStrategy, pgs, null, null, true, joe);
MutableAcl childAcl2 = new AclImpl(childOid2, 4, authzStrategy, pgs, null, null, false, joe);
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);
@@ -330,7 +366,8 @@ public class AclImplTests {
Authentication auth = new TestingAuthenticationToken("ben", "ignored","ROLE_GENERAL");
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
MutableAcl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, false, new PrincipalSid("joe"));
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);
@@ -347,7 +384,7 @@ public class AclImplTests {
acl.updateAce(1, BasePermission.DELETE);
acl.updateAce(2, BasePermission.READ);
// Check the change was successfully made
// 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);
@@ -358,7 +395,8 @@ public class AclImplTests {
Authentication auth = new TestingAuthenticationToken("ben", "ignored", "ROLE_AUDITING", "ROLE_GENERAL");
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
MutableAcl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, false, new PrincipalSid("joe"));
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);
@@ -383,13 +421,16 @@ public class AclImplTests {
@Test
public void gettersAndSettersAreConsistent() throws Exception {
Authentication auth = new TestingAuthenticationToken("ben", "ignored", "ROLE_GENERAL");
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, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
MutableAcl parentAcl = new AclImpl(identity2, 2, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
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);
@@ -408,14 +449,14 @@ public class AclImplTests {
acl.setEntriesInheriting(false);
assertFalse(acl.isEntriesInheriting());
acl.setOwner(new PrincipalSid("ben"));
((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, authzStrategy, pgs, null, loadedSids, true,
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, loadedSids, true,
new PrincipalSid("joe"));
assertTrue(acl.isSidLoaded(loadedSids));
@@ -431,19 +472,22 @@ public class AclImplTests {
@Test(expected=NotFoundException.class)
public void insertAceRaisesNotFoundExceptionForIndexLessThanZero() throws Exception {
AclImpl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
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, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
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, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
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
@@ -453,22 +497,13 @@ public class AclImplTests {
// SEC-1151
@Test(expected=NotFoundException.class)
public void deleteAceRaisesNotFoundExceptionForIndexEqualToSize() throws Exception {
AclImpl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
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);
}
// SEC-1795
@Test
public void changingParentIsSuccessful() throws Exception {
AclImpl parentAcl = new AclImpl(objectIdentity, 1L, authzStrategy, mockAuditLogger);
AclImpl childAcl = new AclImpl(objectIdentity, 2L, authzStrategy, mockAuditLogger);
AclImpl changeParentAcl = new AclImpl(objectIdentity, 3L, authzStrategy, mockAuditLogger);
childAcl.setParent(parentAcl);
childAcl.setParent(changeParentAcl);
}
//~ Inner Classes ==================================================================================================
@@ -1,8 +1,8 @@
package org.springframework.security.acls.domain;
import static org.junit.Assert.*;
import junit.framework.Assert;
import junit.framework.TestCase;
import org.junit.*;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.MutableAcl;
@@ -10,7 +10,8 @@ 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.authority.SimpleGrantedAuthority;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.context.SecurityContextHolder;
/**
@@ -19,31 +20,28 @@ import org.springframework.security.core.context.SecurityContextHolder;
*
* @author Andrei Stefan
*/
public class AclImplementationSecurityCheckTests {
public class AclImplementationSecurityCheckTests extends TestCase {
private static final String TARGET_CLASS = "org.springframework.security.acls.TargetObject";
//~ Methods ========================================================================================================
@Before
public void setUp() throws Exception {
protected void setUp() throws Exception {
SecurityContextHolder.clearContext();
}
@After
public void tearDown() throws Exception {
protected void tearDown() throws Exception {
SecurityContextHolder.clearContext();
}
@Test
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 SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
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());
@@ -52,43 +50,43 @@ public class AclImplementationSecurityCheckTests {
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
// Create another authorization strategy
AclAuthorizationStrategy aclAuthorizationStrategy2 = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_ONE"), new SimpleGrantedAuthority("ROLE_TWO"),
new SimpleGrantedAuthority("ROLE_THREE"));
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);
fail("It should have thrown NotFoundException");
Assert.fail("It should have thrown NotFoundException");
}
catch (NotFoundException expected) {
}
try {
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_AUDITING);
fail("It should have thrown NotFoundException");
Assert.fail("It should have thrown NotFoundException");
}
catch (NotFoundException expected) {
}
try {
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
fail("It should have thrown NotFoundException");
Assert.fail("It should have thrown NotFoundException");
}
catch (NotFoundException expected) {
}
}
@Test
public void testSecurityCheckWithMultipleACEs() throws Exception {
// Create a simple authentication with ROLE_GENERAL
Authentication auth = new TestingAuthenticationToken("user", "password", "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 SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
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
@@ -103,13 +101,13 @@ public class AclImplementationSecurityCheckTests {
// nor granting access
try {
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_AUDITING);
fail("It should have thrown AccessDeniedException");
Assert.fail("It should have thrown AccessDeniedException");
}
catch (AccessDeniedException expected) {
}
try {
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
fail("It should have thrown AccessDeniedException");
Assert.fail("It should have thrown AccessDeniedException");
}
catch (AccessDeniedException expected) {
}
@@ -120,7 +118,7 @@ public class AclImplementationSecurityCheckTests {
// (false) will deny this access
try {
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_AUDITING);
fail("It should have thrown AccessDeniedException");
Assert.fail("It should have thrown AccessDeniedException");
}
catch (AccessDeniedException expected) {
}
@@ -140,58 +138,58 @@ public class AclImplementationSecurityCheckTests {
aclFirstAllow.insertAce(1, BasePermission.ADMINISTRATION, new PrincipalSid(auth), false);
try {
aclAuthorizationStrategy.securityCheck(aclFirstAllow, AclAuthorizationStrategy.CHANGE_AUDITING);
assertTrue(true);
Assert.assertTrue(true);
}
catch (AccessDeniedException notExpected) {
fail("It shouldn't have thrown AccessDeniedException");
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);
fail("It should have thrown NotFoundException");
Assert.fail("It should have thrown NotFoundException");
}
catch (NotFoundException expected) {
assertTrue(true);
Assert.assertTrue(true);
}
// and still grant access for CHANGE_GENERAL
try {
aclAuthorizationStrategy.securityCheck(aclNoACE, AclAuthorizationStrategy.CHANGE_GENERAL);
assertTrue(true);
Assert.assertTrue(true);
}
catch (NotFoundException expected) {
fail("It shouldn't have thrown NotFoundException");
Assert.fail("It shouldn't have thrown NotFoundException");
}
}
@Test
public void testSecurityCheckWithInheritableACEs() throws Exception {
// Create a simple authentication with ROLE_GENERAL
Authentication auth = new TestingAuthenticationToken("user", "password", "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, 100);
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
// Authorization strategy will require a different role for each access
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_ONE"), new SimpleGrantedAuthority("ROLE_TWO"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
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, 1, aclAuthorizationStrategy, new ConsoleAuditLogger());
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, 2, aclAuthorizationStrategy, new ConsoleAuditLogger());
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);
fail("It should have thrown NotFoundException");
Assert.fail("It should have thrown NotFoundException");
}
catch (NotFoundException expected) {
assertTrue(true);
Assert.assertTrue(true);
}
// Link the child with its parent and test again against the
@@ -200,60 +198,63 @@ public class AclImplementationSecurityCheckTests {
childAcl.setEntriesInheriting(true);
try {
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
assertTrue(true);
Assert.assertTrue(true);
}
catch (NotFoundException expected) {
fail("It shouldn't have thrown NotFoundException");
Assert.fail("It shouldn't have thrown NotFoundException");
}
// Create a root parent and link it to the middle parent
MutableAcl rootParentAcl = new AclImpl(identity, 1, aclAuthorizationStrategy,
MutableAcl rootParentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy,
new ConsoleAuditLogger());
parentAcl = new AclImpl(identity, 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);
assertTrue(true);
Assert.assertTrue(true);
}
catch (NotFoundException expected) {
fail("It shouldn't have thrown NotFoundException");
Assert.fail("It shouldn't have thrown NotFoundException");
}
}
@SuppressWarnings("deprecation")
@Test
public void testSecurityCheckPrincipalOwner() throws Exception {
Authentication auth = new TestingAuthenticationToken("user", "password", "ROLE_ONE");
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, 100);
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
new GrantedAuthorityImpl("ROLE_GENERAL") });
Acl acl = new AclImpl(identity, 1, aclAuthorizationStrategy, new ConsoleAuditLogger(), null, null,
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) {
fail("It shouldn't have thrown AccessDeniedException");
Assert.fail("It shouldn't have thrown AccessDeniedException");
}
try {
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_AUDITING);
fail("It shouldn't have thrown AccessDeniedException");
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) {
fail("It shouldn't have thrown AccessDeniedException");
Assert.fail("It shouldn't have thrown AccessDeniedException");
}
}
}
@@ -1,11 +1,13 @@
package org.springframework.security.acls.domain;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
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;
@@ -19,17 +21,29 @@ import org.springframework.security.acls.model.AuditableAccessControlEntry;
*/
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 = mock(AuditableAccessControlEntry.class);
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));
}
@@ -42,36 +56,35 @@ public class AuditLoggerTests {
@Test
public void nonAuditableAceIsIgnored() {
AccessControlEntry ace = mock(AccessControlEntry.class);
AccessControlEntry ace = jmock.mock(AccessControlEntry.class);
logger.logIfNeeded(true, ace);
assertEquals(0, bytes.size());
}
@Test
public void successIsNotLoggedIfAceDoesntRequireSuccessAudit() throws Exception {
when(ace.isAuditSuccess()).thenReturn(false);
jmock.checking(aceDoesntRequireAudit);
logger.logIfNeeded(true, ace);
assertEquals(0, bytes.size());
}
@Test
public void successIsLoggedIfAceRequiresSuccessAudit() throws Exception {
when(ace.isAuditSuccess()).thenReturn(true);
jmock.checking(aceRequiresAudit);
logger.logIfNeeded(true, ace);
assertTrue(bytes.toString().startsWith("GRANTED due to ACE"));
}
@Test
public void failureIsntLoggedIfAceDoesntRequireFailureAudit() throws Exception {
when(ace.isAuditFailure()).thenReturn(false);
jmock.checking(aceDoesntRequireAudit);
logger.logIfNeeded(false, ace);
assertEquals(0, bytes.size());
}
@Test
public void failureIsLoggedIfAceRequiresFailureAudit() throws Exception {
when(ace.isAuditFailure()).thenReturn(true);
jmock.checking(aceRequiresAudit);
logger.logIfNeeded(false, ace);
assertTrue(bytes.toString().startsWith("DENIED due to ACE"));
}
@@ -140,7 +140,7 @@ public class ObjectIdentityImplTests {
@Test
public void longAndIntegerIdsWithSameValueAreEqualAndHaveSameHashcode() {
ObjectIdentity obj = new ObjectIdentityImpl(Object.class, new Long(5));
ObjectIdentity obj2 = new ObjectIdentityImpl(Object.class, Integer.valueOf(5));
ObjectIdentity obj2 = new ObjectIdentityImpl(Object.class, new Integer(5));
assertEquals(obj, obj2);
assertEquals(obj.hashCode(), obj2.hashCode());
@@ -17,7 +17,7 @@ public class ObjectIdentityRetrievalStrategyImplTests extends TestCase {
public void testObjectIdentityCreation() throws Exception {
MockIdDomainObject domain = new MockIdDomainObject();
domain.setId(Integer.valueOf(1));
domain.setId(new Integer(1));
ObjectIdentityRetrievalStrategy retStrategy = new ObjectIdentityRetrievalStrategyImpl();
ObjectIdentity identity = retStrategy.getObjectIdentity(domain);
@@ -1,10 +1,19 @@
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.*;
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;
@@ -14,7 +23,6 @@ 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.DefaultPermissionGrantingStrategy;
import org.springframework.security.acls.domain.EhCacheBasedAclCache;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PrincipalSid;
@@ -25,11 +33,10 @@ 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.authority.SimpleGrantedAuthority;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.util.FileCopyUtils;
import java.util.*;
/**
* Tests {@link BasicLookupStrategy}
*
@@ -93,9 +100,10 @@ public class BasicLookupStrategyTests {
@Before
public void initializeBeans() {
EhCacheBasedAclCache cache = new EhCacheBasedAclCache(getCache());
AclAuthorizationStrategy authorizationStrategy = new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_ADMINISTRATOR"));
strategy = new BasicLookupStrategy(dataSource, cache, authorizationStrategy,
new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()));
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());
}
@@ -120,7 +128,7 @@ public class BasicLookupStrategyTests {
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, Integer.valueOf(102));
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);
@@ -128,7 +136,7 @@ public class BasicLookupStrategyTests {
@Test
public void testAclsRetrievalFromCacheOnly() throws Exception {
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(100));
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));
@@ -145,11 +153,11 @@ public class BasicLookupStrategyTests {
@Test
public void testAclsRetrievalWithCustomBatchSize() throws Exception {
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(101));
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
this.strategy.setBatchSize(1);
((BasicLookupStrategy) this.strategy).setBatchSize(1);
Map<ObjectIdentity, Acl> map = this.strategy.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
checkEntries(topParentOid, middleParentOid, childOid, map);
}
@@ -184,36 +192,36 @@ public class BasicLookupStrategyTests {
// Check each entry
Assert.assertTrue(topParent.isEntriesInheriting());
Assert.assertEquals(topParent.getId(), Long.valueOf(1));
Assert.assertEquals(topParent.getId(), new Long(1));
Assert.assertEquals(topParent.getOwner(), new PrincipalSid("ben"));
Assert.assertEquals(topParent.getEntries().get(0).getId(), Long.valueOf(1));
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((topParent.getEntries().get(0)).isGranting());
Assert.assertTrue(((AuditableAccessControlEntry) topParent.getEntries().get(0)).isGranting());
Assert.assertEquals(topParent.getEntries().get(1).getId(), Long.valueOf(2));
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(topParent.getEntries().get(1).isGranting());
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries().get(1)).isGranting());
Assert.assertTrue(middleParent.isEntriesInheriting());
Assert.assertEquals(middleParent.getId(), Long.valueOf(2));
Assert.assertEquals(middleParent.getId(), new Long(2));
Assert.assertEquals(middleParent.getOwner(), new PrincipalSid("ben"));
Assert.assertEquals(middleParent.getEntries().get(0).getId(), Long.valueOf(3));
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(middleParent.getEntries().get(0).isGranting());
Assert.assertTrue(((AuditableAccessControlEntry) middleParent.getEntries().get(0)).isGranting());
Assert.assertTrue(child.isEntriesInheriting());
Assert.assertEquals(child.getId(), Long.valueOf(3));
Assert.assertEquals(child.getId(), new Long(3));
Assert.assertEquals(child.getOwner(), new PrincipalSid("ben"));
Assert.assertEquals(child.getEntries().get(0).getId(), Long.valueOf(4));
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());
@@ -226,21 +234,21 @@ public class BasicLookupStrategyTests {
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, Long.valueOf(100));
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(101));
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(102));
ObjectIdentity middleParent2Oid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(103));
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, map.get(childOid).getObjectIdentity());
Assert.assertEquals(childOid, ((Acl) map.get(childOid)).getObjectIdentity());
Assert.assertNotNull(map.get(middleParentOid));
Assert.assertEquals(middleParentOid, map.get(middleParentOid).getObjectIdentity());
Assert.assertEquals(middleParentOid, ((Acl) map.get(middleParentOid)).getObjectIdentity());
Assert.assertNotNull(map.get(topParentOid));
Assert.assertEquals(topParentOid, map.get(topParentOid).getObjectIdentity());
Assert.assertEquals(topParentOid, ((Acl) map.get(topParentOid)).getObjectIdentity());
// The second parent shouldn't have been retrieved
Assert.assertNull(map.get(middleParent2Oid));
@@ -260,8 +268,8 @@ public class BasicLookupStrategyTests {
ObjectIdentity grandParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(104));
ObjectIdentity parent1Oid = new ObjectIdentityImpl(TARGET_CLASS, new Long(105));
ObjectIdentity parent2Oid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(106));
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(107));
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);
@@ -271,7 +279,7 @@ public class BasicLookupStrategyTests {
strategy.setBatchSize(6);
Map<ObjectIdentity, Acl> foundAcls = strategy.readAclsById(childOids, sids);
Acl foundChildAcl = foundAcls.get(childOid);
Acl foundChildAcl = (Acl) foundAcls.get(childOid);
Assert.assertNotNull(foundChildAcl);
Assert.assertTrue(foundChildAcl.isGranted(checkPermission, sids, false));
@@ -285,7 +293,7 @@ public class BasicLookupStrategyTests {
Assert.fail("It shouldn't have thrown NotFoundException");
}
Acl foundParent2Acl = foundAcls.get(parent2Oid);
Acl foundParent2Acl = (Acl) foundAcls.get(parent2Oid);
Assert.assertNotNull(foundParent2Acl);
Assert.assertTrue(foundParent2Acl.isGranted(checkPermission, sids, false));
}
@@ -2,10 +2,22 @@ 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.*;
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;
@@ -16,18 +28,11 @@ 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.authority.SimpleGrantedAuthority;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.util.FieldUtils;
import 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.*;
/**
* Tests {@link EhCacheBasedAclCache}
*
@@ -122,11 +127,11 @@ public class EhCacheBasedAclCacheTests {
// SEC-527
@Test
public void testDiskSerializationOfMutableAclObjectInstance() throws Exception {
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(100));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
MutableAcl acl = new AclImpl(identity, Long.valueOf(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
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");
@@ -145,7 +150,7 @@ public class EhCacheBasedAclCacheTests {
Object retrieved1 = FieldUtils.getProtectedFieldValue("aclAuthorizationStrategy", retrieved);
assertEquals(null, retrieved1);
Object retrieved2 = FieldUtils.getProtectedFieldValue("permissionGrantingStrategy", retrieved);
Object retrieved2 = FieldUtils.getProtectedFieldValue("auditLogger", retrieved);
assertEquals(null, retrieved2);
}
@@ -154,11 +159,11 @@ public class EhCacheBasedAclCacheTests {
Ehcache cache = getCache();
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(100));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
MutableAcl acl = new AclImpl(identity, Long.valueOf(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
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);
@@ -168,29 +173,29 @@ public class EhCacheBasedAclCacheTests {
assertFalse(cache.isElementInMemory(acl.getObjectIdentity()));
// Check we can get from cache the same objects we put in
assertEquals(myCache.getFromCache(Long.valueOf(1)), acl);
assertEquals(myCache.getFromCache(new Long(1)), acl);
assertEquals(myCache.getFromCache(identity), acl);
// Put another object in cache
ObjectIdentity identity2 = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(101));
MutableAcl acl2 = new AclImpl(identity2, Long.valueOf(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
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(Long.valueOf(3));
myCache.evictFromCache(new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(102)));
myCache.evictFromCache(new Long(3));
myCache.evictFromCache(new ObjectIdentityImpl(TARGET_CLASS, new Long(102)));
assertEquals(cache.getSize(), 4);
assertEquals(4, cache.getDiskStoreSize());
myCache.evictFromCache(Long.valueOf(1));
myCache.evictFromCache(new Long(1));
assertEquals(cache.getSize(), 2);
assertEquals(2, cache.getDiskStoreSize());
// Check the second object inserted
assertEquals(myCache.getFromCache(Long.valueOf(2)), acl2);
assertEquals(myCache.getFromCache(new Long(2)), acl2);
assertEquals(myCache.getFromCache(identity2), acl2);
myCache.evictFromCache(identity2);
@@ -203,17 +208,18 @@ public class EhCacheBasedAclCacheTests {
Ehcache cache = getCache();
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
Authentication auth = new TestingAuthenticationToken("user", "password", "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, Long.valueOf(1));
ObjectIdentity identityParent = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(2));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
MutableAcl acl = new AclImpl(identity, Long.valueOf(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
MutableAcl parentAcl = new AclImpl(identityParent, Long.valueOf(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
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);
@@ -234,17 +240,17 @@ public class EhCacheBasedAclCacheTests {
}
// Check we can get from cache the same objects we put in
AclImpl aclFromCache = (AclImpl) myCache.getFromCache(Long.valueOf(1));
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(), "permissionGrantingStrategy"));
assertNotNull(FieldUtils.getFieldValue(aclFromCache.getParentAcl(), "auditLogger"));
assertEquals(acl, myCache.getFromCache(identity));
assertNotNull(FieldUtils.getFieldValue(aclFromCache, "aclAuthorizationStrategy"));
AclImpl parentAclFromCache = (AclImpl) myCache.getFromCache(Long.valueOf(2));
AclImpl parentAclFromCache = (AclImpl) myCache.getFromCache(new Long(2));
assertEquals(parentAcl, parentAclFromCache);
assertNotNull(FieldUtils.getFieldValue(parentAclFromCache, "aclAuthorizationStrategy"));
assertEquals(parentAcl, myCache.getFromCache(identityParent));
@@ -4,7 +4,6 @@ import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import java.util.Collection;
import java.util.List;
import org.junit.Test;
@@ -54,8 +53,8 @@ public class SidRetrievalStrategyTests {
@Test
public void roleHierarchyIsUsedWhenSet() throws Exception {
RoleHierarchy rh = mock(RoleHierarchy.class);
List rhAuthorities = AuthorityUtils.createAuthorityList("D");
when(rh.getReachableGrantedAuthorities(anyCollection())).thenReturn(rhAuthorities);
List<GrantedAuthority> rhAuthorities = AuthorityUtils.createAuthorityList("D");
when(rh.getReachableGrantedAuthorities(anyList())).thenReturn(rhAuthorities);
SidRetrievalStrategy strat = new SidRetrievalStrategyImpl(rh);
List<Sid> sids = strat.getSids(authentication);
@@ -2,13 +2,14 @@ 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.SimpleGrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
public class SidTests extends TestCase {
@@ -108,7 +109,7 @@ public class SidTests extends TestCase {
}
try {
GrantedAuthority ga = new SimpleGrantedAuthority(null);
GrantedAuthority ga = new GrantedAuthorityImpl(null);
new GrantedAuthoritySid(ga);
Assert.fail("It should have thrown IllegalArgumentException");
}
@@ -117,7 +118,7 @@ public class SidTests extends TestCase {
}
try {
GrantedAuthority ga = new SimpleGrantedAuthority("ROLE_TEST");
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
new GrantedAuthoritySid(ga);
Assert.assertTrue(true);
}
@@ -141,15 +142,15 @@ public class SidTests extends TestCase {
}
public void testGrantedAuthoritySidEquals() throws Exception {
GrantedAuthority ga = new SimpleGrantedAuthority("ROLE_TEST");
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 SimpleGrantedAuthority("ROLE_TEST"))));
Assert.assertFalse(gaSid.equals(new GrantedAuthoritySid(new SimpleGrantedAuthority("ROLE_NOT_EQUAL"))));
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")));
}
@@ -158,26 +159,26 @@ public class SidTests extends TestCase {
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
Sid principalSid = new PrincipalSid(authentication);
Assert.assertTrue(principalSid.hashCode() == "johndoe".hashCode());
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 SimpleGrantedAuthority("ROLE_TEST");
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
Sid gaSid = new GrantedAuthoritySid(ga);
Assert.assertTrue(gaSid.hashCode() == "ROLE_TEST".hashCode());
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 SimpleGrantedAuthority("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 SimpleGrantedAuthority("ROLE_TEST");
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
GrantedAuthoritySid gaSid = new GrantedAuthoritySid(ga);
Assert.assertTrue("johndoe".equals(principalSid.getPrincipal()));
@@ -36,13 +36,13 @@
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
<constructor-arg value="ROLE_ADMINISTRATOR"/>
</bean>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
<constructor-arg value="ROLE_ADMINISTRATOR"/>
</bean>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
<constructor-arg value="ROLE_ADMINISTRATOR"/>
</bean>
</list>
-14
View File
@@ -1,14 +0,0 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.springframework.security" level="${sec.log.level}:-WARN"/>
<root level="${root.level}:-WARN">
<appender-ref ref="STDOUT" />
</root>
</configuration>
+12 -13
View File
@@ -5,19 +5,18 @@ Bundle-Name: Spring Security Acls
Bundle-Vendor: SpringSource
Bundle-Version: ${version}
Bundle-ManifestVersion: 2
Ignored-Existing-Headers:
Ignored-Existing-Headers:
Import-Package,
Export-Package
Import-Template:
org.aopalliance.*;version="${aopAllianceRange}",
org.apache.commons.logging.*;version="${cloggingRange}",
org.springframework.security.core.*;version="${secRange}",
org.springframework.security.access.*;version="${secRange}",
org.springframework.security.util.*;version="${secRange}",
org.springframework.context.*;version="${secRange}";resolution:=optional,
org.springframework.dao.*;version="${springRange}";resolution:=optional,
org.springframework.jdbc.core.*;version="${springRange}";resolution:=optional,
org.springframework.transaction.support.*;version="${springRange}";resolution:=optional,
org.springframework.util.*;version="${springRange}";resolution:=optional,
net.sf.ehcache.*;version="${ehcacheRange}";resolution:=optional,
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
-2
View File
@@ -3,6 +3,4 @@ dependencies {
compile project(':spring-security-core'),
"org.springframework:spring-beans:$springVersion",
"org.springframework:spring-context:$springVersion"
testCompile 'aopalliance:aopalliance:1.0'
}
+61
View File
@@ -0,0 +1,61 @@
<?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.4.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.4.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,10 +1,6 @@
package org.springframework.security.access.intercept.aspectj.aspect;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.Before;
@@ -18,17 +14,12 @@ 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.ExpressionBasedPostInvocationAdvice;
import org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice;
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
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.access.vote.RoleVoter;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.TestingAuthenticationToken;
@@ -40,23 +31,18 @@ import org.springframework.security.core.context.SecurityContextHolder;
* @since 3.0.3
*/
public class AnnotationSecurityAspectTests {
private AffirmativeBased adm;
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 SecuredImplSubclass securedSub = new SecuredImplSubclass();
private PrePostSecured prePostSecured = new PrePostSecured();
@Before
public final void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
interceptor = new AspectJMethodSecurityInterceptor();
adm = new AffirmativeBased();
AccessDecisionVoter[] voters = new AccessDecisionVoter[]
{new RoleVoter(), new PreInvocationAuthorizationAdviceVoter(new ExpressionBasedPreInvocationAdvice())};
adm.setDecisionVoters(Arrays.asList(voters));
interceptor.setAccessDecisionManager(adm);
interceptor.setAuthenticationManager(authman);
interceptor.setSecurityMetadataSource(new SecuredAnnotationSecurityMetadataSource());
@@ -85,57 +71,18 @@ public class AnnotationSecurityAspectTests {
secured.securedClassMethod();
}
@Test(expected=AccessDeniedException.class)
public void internalPrivateCallIsIntercepted() {
SecurityContextHolder.getContext().setAuthentication(anne);
try {
secured.publicCallsPrivate();
fail("Expected AccessDeniedException");
} catch (AccessDeniedException expected) {
}
securedSub.publicCallsPrivate();
}
@Test(expected=AccessDeniedException.class)
public void protectedMethodIsIntercepted() throws Exception {
SecurityContextHolder.getContext().setAuthentication(anne);
secured.protectedMethod();
}
@Test
public void overriddenProtectedMethodIsNotIntercepted() throws Exception {
// AspectJ doesn't inherit annotations
securedSub.protectedMethod();
}
// SEC-1262
@Test(expected=AccessDeniedException.class)
public void denyAllPreAuthorizeDeniesAccess() throws Exception {
configureForElAnnotations();
SecurityContextHolder.getContext().setAuthentication(anne);
prePostSecured.denyAllMethod();
}
@Test
public void postFilterIsApplied() throws Exception {
configureForElAnnotations();
SecurityContextHolder.getContext().setAuthentication(anne);
List<String> objects = prePostSecured.postFilterMethod();
assertEquals(2, objects.size());
assertTrue(objects.contains("apple"));
assertTrue(objects.contains("aubergine"));
}
private void configureForElAnnotations() {
DefaultMethodSecurityExpressionHandler eh = new DefaultMethodSecurityExpressionHandler();
interceptor.setSecurityMetadataSource(new PrePostAnnotationSecurityMetadataSource(
new ExpressionBasedAnnotationAttributeFactory(eh)));
new ExpressionBasedAnnotationAttributeFactory(new DefaultMethodSecurityExpressionHandler())));
AffirmativeBased adm = new AffirmativeBased();
AccessDecisionVoter[] voters = new AccessDecisionVoter[]
{new PreInvocationAuthorizationAdviceVoter(new ExpressionBasedPreInvocationAdvice())};
adm.setDecisionVoters(Arrays.asList(voters));
interceptor.setAccessDecisionManager(adm);
AfterInvocationProviderManager aim = new AfterInvocationProviderManager();
aim.setProviders(Arrays.asList(new PostInvocationAdviceProvider(new ExpressionBasedPostInvocationAdvice(eh))));
interceptor.setAfterInvocationManager(aim);
prePostSecured.denyAllMethod();
}
}
@@ -145,6 +92,7 @@ interface SecuredInterface {
}
class SecuredImpl implements SecuredInterface {
// Not really secured because AspectJ doesn't inherit annotations from interfaces
public void securedMethod() {
}
@@ -152,39 +100,11 @@ class SecuredImpl implements SecuredInterface {
@Secured("ROLE_A")
public void securedClassMethod() {
}
@Secured("ROLE_X")
private void privateMethod() {
}
@Secured("ROLE_X")
protected void protectedMethod() {
}
@Secured("ROLE_X")
public void publicCallsPrivate() {
privateMethod();
}
}
class SecuredImplSubclass extends SecuredImpl {
protected void protectedMethod() {
}
public void publicCallsPrivate() {
super.publicCallsPrivate();
}
}
class PrePostSecured {
@PreAuthorize("denyAll")
public void denyAllMethod() {
}
@PostFilter("filterObject.startsWith('a')")
public List<String> postFilterMethod() {
ArrayList<String> objects = new ArrayList<String>();
objects.addAll(Arrays.asList(new String[] {"apple", "banana", "aubergine", "orange"}));
return objects;
}
}
-16
View File
@@ -1,16 +0,0 @@
Implementation-Title: org.springframework.security.aspects
Implementation-Version: ${version}
Bundle-SymbolicName: org.springframework.security.aspects
Bundle-Name: Spring Security Aspects
Bundle-Vendor: SpringSource
Bundle-ManifestVersion: 2
Bundle-Version: ${version}
Ignored-Existing-Headers:
Import-Package,
Export-Package
Import-Template:
org.aspectj.*;version="${aspectjRange}";resolution:=optional,
org.apache.commons.logging.*;version="${cloggingRange}",
org.springframework.security.core.*;version="${secRange}",
org.springframework.security.access.intercept.aspectj;version="${secRange}",
org.springframework.beans.factory;version="${springRange}"
+163 -36
View File
@@ -1,63 +1,120 @@
apply plugin: 'base'
description = 'Spring Security'
allprojects {
version = '3.1.0.RELEASE'
version = '3.0.4.CI-SNAPSHOT'
releaseBuild = version.endsWith('RELEASE')
snapshotBuild = version.endsWith('SNAPSHOT')
group = 'org.springframework.security'
repositories {
mavenLocal()
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'
}
}
// Set up different subproject lists for individual configuration
javaProjects = subprojects.findAll { project -> project.name != 'docs' && project.name != 'faq' && project.name != 'manual' }
sampleProjects = subprojects.findAll { project -> project.name.startsWith('spring-security-samples') }
itestProjects = subprojects.findAll { project -> project.name.startsWith('itest') }
coreModuleProjects = javaProjects - sampleProjects - itestProjects
aspectjProjects = [project(':spring-security-aspects'), project(':spring-security-samples-aspectj')]
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))
apply plugin: 'bundlor'
bundlor.expansions = bundlorProperties
apply from: "$rootDir/gradle/maven-deployment.gradle"
apply plugin: 'emma'
}
task coreBuild {
dependsOn coreModuleProjects*.tasks*.matching { task -> task.name == 'build' }
}
configure (aspectjProjects) {
apply plugin: 'aspectj'
apply from: "$rootDir/gradle/aspectj.gradle"
}
// Task for creating the distro zip
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) {
dependsOn subprojects*.tasks*.matching { task -> task.name == 'assemble' }
evaluationDependsOn(':docs')
def zipRootDir = "${project.name}-$version"
into(zipRootDir) {
from(rootDir) {
include '*.txt'
into('docs/apidocs') {
from apidocs.destinationDir
}
into('docs') {
with(project(':docs').apiSpec)
with(project(':docs:manual').spec)
into('docs/reference') {
from docsDir
}
into('dist') {
from coreModuleProjects.collect {project -> project.libsDir }
@@ -67,13 +124,83 @@ task dist(type: Zip) {
}
}
task uploadDist(type: S3DistroUpload) {
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
projectKey = 'SEC'
shaFile = "${dist.archivePath}.sha1" as File
archiveName = dist.archiveName
classpath = configurations.antlibs
}
apply from: "$rootDir/gradle/ide-integration.gradle"
task wrapper(type: Wrapper) {
gradleVersion = '1.0-milestone-3'
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'
}
}
}
+4 -28
View File
@@ -1,13 +1,11 @@
apply plugin: 'groovy'
repositories {
mavenLocal()
mavenRepo name:'localRepo', urls: "file://" + System.properties['user.home'] + "/.m2/repository"
mavenCentral()
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'
mavenRepo name:'Shibboleth Repo', urls:'http://shibboleth.internet2.edu/downloads/maven2'
}
// Docbook Plugin
dependencies {
def fopDeps = [ 'org.apache.xmlgraphics:fop:0.95-1@jar',
'org.apache.xmlgraphics:xmlgraphics-commons:1.3',
@@ -19,38 +17,16 @@ dependencies {
'org.apache.avalon.framework:avalon-framework-api:4.3.1']
groovy localGroovy()
compile gradleApi(),
'xml-resolver:xml-resolver:1.2',
'xerces:xercesImpl:2.9.1',
'org.apache.xerces:resolver:2.9.1',
'saxon:saxon:6.5.3',
'net.java.dev.jets3t:jets3t:0.6.1',
'org.apache.xerces:xercesImpl:2.9.1',
fopDeps
runtime 'net.sf.xslthl:xslthl:2.0.1',
'net.sf.docbook:docbook-xsl:1.75.2:ns-resources@zip'
}
// GAE
dependencies {
compile 'com.google.appengine:appengine-tools-sdk:1.4.2'
}
dependencies{
compile "emma:emma:2.0.5312"
}
// Bundlor
dependencies {
compile 'com.springsource.bundlor:com.springsource.bundlor:1.0.0.RELEASE',
'com.springsource.bundlor:com.springsource.bundlor.blint:1.0.0.RELEASE'
}
task ide(type: Copy) {
from configurations.runtime
into 'ide'
}
apply plugin: 'idea'
ideaModule {
excludeDirs += file('.gradle')
}
@@ -1,92 +0,0 @@
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.TaskAction
import org.jets3t.service.security.AWSCredentials
import org.jets3t.service.impl.rest.httpclient.RestS3Service
import org.jets3t.service.S3Service
import org.jets3t.service.model.S3Bucket
import org.jets3t.service.model.S3Object
import org.jets3t.service.acl.AccessControlList
/**
* @author Luke Taylor
*/
class S3DistroUpload extends DefaultTask {
@InputFile
File archiveFile
@Input
String bucketName = 'dist.springframework.org'
// 'Spring Security'
@Input
String projectName = project.description
// e.g 'SEC'
@Input
String projectKey
@TaskAction
def upload() {
def accessKey = project.s3AccessKey
def secretKey = project.s3SecretAccessKey
def version = project.version.toString()
assert version.length() > 0
assert accessKey.length() > 0
assert secretKey.length() > 0
assert projectName.length() > 0
assert archiveFile.exists()
String archiveName = archiveFile.getName()
logger.info("Creating SHA checksum file...")
project.ant.checksum(file: archiveFile, algorithm: 'SHA1', fileext: '.sha1', forceoverwrite: 'true')
File shaFile = "${archiveFile}.sha1" as File
assert shaFile.exists()
AWSCredentials creds = new AWSCredentials(accessKey, secretKey);
S3Service s3 = new RestS3Service(creds)
S3Bucket bucket = new S3Bucket(bucketName)
String releaseType = releaseType(version)
String key = releaseType + '/' + projectKey + '/' + archiveName
S3Object archiveDest = new S3Object(bucket, key)
archiveDest.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ)
archiveDest.setDataInputFile(archiveFile)
archiveDest.setContentLength(archiveFile.length())
archiveDest.addMetadata('project.name', projectName)
archiveDest.addMetadata('bundle.version', version)
archiveDest.addMetadata('release.type', releaseType)
archiveDest.addMetadata('package.file.name', archiveName)
logger.info("Uploading archive " + archiveFile.getName() + " to " + archiveDest + "...")
s3.putObject(bucket, archiveDest)
logger.info("Done")
S3Object shaDest = new S3Object(bucket, key + '.sha1')
shaDest.setAcl(AccessControlList.REST_CANNED_PUBLIC_READ)
shaDest.setDataInputFile(shaFile)
shaDest.setContentLength(shaFile.length())
logger.info("Uploading SHA checksum " + shaFile.getName() + " to " + key + '.sha1' + "...")
s3.putObject(bucket, shaDest);
logger.info("Done")
}
def releaseType(String version) {
if (version.endsWith('RELEASE')) {
'release'
} else if (version.endsWith('SNAPSHOT')) {
'snapshot'
} else {
'milestone'
}
}
}
+7 -20
View File
@@ -10,23 +10,12 @@ import org.gradle.api.tasks.bundling.Compression;
class TarUpload extends Tar {
@Input
String remoteDir
Login login
@Input
String host
Login login
TarUpload() {
compression = Compression.BZIP2
if (project.configurations.findByName('antjsch') == null) {
project.configurations.add('antjsch')
project.dependencies {
antjsch 'org.apache.ant:ant-jsch:1.8.1'
}
def classpath = project.configurations.antjsch.asPath
project.ant {
taskdef(name: 'scp', classname: 'org.apache.tools.ant.taskdefs.optional.ssh.Scp', classpath: classpath)
taskdef(name: 'sshexec', classname: 'org.apache.tools.ant.taskdefs.optional.ssh.SSHExec', classpath: classpath)
}
}
}
@TaskAction
@@ -49,7 +38,6 @@ class TarUpload extends Tar {
void setLogin(Login login) {
dependsOn(login)
this.login = login
this.host = login.host
}
}
@@ -64,12 +52,11 @@ class Login extends DefaultTask {
@TaskAction
login() {
def console = System.console()
if (console) {
username = console.readLine("\nPlease enter the ssh username for host '$host': ")
password = new String(console.readPassword("Please enter the ssh password for '$host': "))
} else {
logger.error "Unable to access System.console()."
project.ant {
input("Please enter the ssh username for host '$host'", addproperty: "user.$host")
input("Please enter the ssh password '$host'", addproperty: "pass.$host")
}
username = ant.properties["user.$host"]
password = ant.properties["pass.$host"]
}
}
@@ -1,100 +0,0 @@
package aspectj
import org.gradle.api.Project
import org.gradle.api.Plugin
import org.gradle.api.tasks.TaskAction
import org.gradle.api.logging.LogLevel
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.SourceSet
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.plugins.ide.eclipse.GenerateEclipseProject
import org.gradle.plugins.ide.eclipse.GenerateEclipseClasspath
import org.gradle.plugins.ide.eclipse.model.BuildCommand
import org.gradle.tooling.model.ProjectDependency
/**
*
* @author Luke Taylor
*/
class AspectJPlugin implements Plugin<Project> {
void apply(Project project) {
if (!project.hasProperty('aspectjVersion')) {
throw new GradleException("You must set the property 'aspectjVersion' before applying the aspectj plugin")
}
if (project.configurations.findByName('ajtools') == null) {
project.configurations.add('ajtools')
project.dependencies {
ajtools "org.aspectj:aspectjtools:${project.aspectjVersion}"
compile "org.aspectj:aspectjrt:${project.aspectjVersion}"
}
}
if (project.configurations.findByName('aspectpath') == null) {
project.configurations.add('aspectpath')
}
project.tasks.add(name: 'compileJava', overwrite: true, description: 'Compiles AspectJ Source', type: Ajc) {
dependsOn project.processResources
sourceSet = project.sourceSets.main
inputs.files(sourceSet.java.srcDirs)
outputs.dir(sourceSet.classesDir)
aspectPath = project.configurations.aspectpath
}
project.tasks.add(name: 'compileTestJava', overwrite: true, description: 'Compiles AspectJ Test Source', type: Ajc) {
dependsOn project.processTestResources, project.compileJava, project.jar
sourceSet = project.sourceSets.test
inputs.files(sourceSet.java.srcDirs)
outputs.dir(sourceSet.classesDir)
aspectPath = project.files(project.configurations.aspectpath, project.jar.archivePath)
}
project.tasks.withType(GenerateEclipseProject).all {
whenConfigured { p ->
p.natures.add(0, 'org.eclipse.ajdt.ui.ajnature')
p.buildCommands = [new BuildCommand('org.eclipse.ajdt.core.ajbuilder',[:])]
}
}
project.tasks.withType(GenerateEclipseClasspath).all {
whenConfigured { classpath ->
def entries = classpath.entries.findAll { it instanceof ProjectDependency}.findAll { entry ->
def projectPath = entry.path.replaceAll('/',':')
project.rootProject.findProject(projectPath).plugins.findPlugin(AspectJPlugin)
}
entries.each { entry->
entry.entryAttributes.put('org.eclipse.ajdt.aspectpath','org.eclipse.ajdt.aspectpath')
}
}
}
}
}
class Ajc extends DefaultTask {
SourceSet sourceSet
FileCollection aspectPath
Ajc() {
logging.captureStandardOutput(LogLevel.INFO)
}
@TaskAction
def compile() {
logger.info("Running ajc ...")
ant.taskdef(resource: "org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties", classpath: project.configurations.ajtools.asPath)
ant.iajc(classpath: sourceSet.compileClasspath.asPath, fork: 'true', destDir: sourceSet.classesDir.absolutePath,
source: project.convention.plugins.java.sourceCompatibility,
target: project.convention.plugins.java.targetCompatibility,
aspectPath: aspectPath.asPath, sourceRootCopyFilter: '**/*.java', showWeaveInfo: 'true') {
sourceroots {
sourceSet.java.srcDirs.each {
pathelement(location: it.absolutePath)
}
}
}
}
}
@@ -1,150 +0,0 @@
package bundlor
import com.springsource.bundlor.ClassPath
import com.springsource.bundlor.ManifestGenerator
import com.springsource.bundlor.ManifestWriter
import com.springsource.bundlor.blint.ManifestValidator
import com.springsource.bundlor.blint.support.DefaultManifestValidatorContributorsFactory
import com.springsource.bundlor.blint.support.StandardManifestValidator
import com.springsource.bundlor.support.DefaultManifestGeneratorContributorsFactory
import com.springsource.bundlor.support.StandardManifestGenerator
import com.springsource.bundlor.support.classpath.FileSystemClassPath
import com.springsource.bundlor.support.manifestwriter.FileSystemManifestWriter
import com.springsource.bundlor.support.properties.EmptyPropertiesSource
import com.springsource.bundlor.support.properties.FileSystemPropertiesSource
import com.springsource.bundlor.support.properties.PropertiesPropertiesSource
import com.springsource.bundlor.support.properties.PropertiesSource
import com.springsource.bundlor.util.BundleManifestUtils
import com.springsource.util.parser.manifest.ManifestContents
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.FileCollection
import org.gradle.api.logging.LogLevel
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
/**
* @author Luke Taylor
*/
class BundlorPlugin implements Plugin<Project> {
void apply(Project project) {
Task bundlor = project.tasks.add('bundlor', Bundlor.class)
bundlor.setDescription('Generates OSGi manifest using bundlor tool')
bundlor.dependsOn(project.classes)
project.jar.dependsOn bundlor
}
}
public class Bundlor extends DefaultTask {
@InputFile
@Optional
File manifestTemplate
@OutputDirectory
File bundlorDir = new File("${project.buildDir}/bundlor")
@OutputFile
File manifest = project.file("${bundlorDir}/META-INF/MANIFEST.MF")
@Input
Map<String,String> expansions = [:]
@InputFile
@Optional
File osgiProfile
@InputFiles
@Optional
FileCollection inputPaths
@Input
boolean failOnWarnings = false
Bundlor() {
manifestTemplate = new File(project.projectDir, 'template.mf')
if (!manifestTemplate.exists()) {
logger.info("No bundlor template for project " + project.name)
manifestTemplate = null
}
inputPaths = project.files(project.sourceSets.main.classesDir)
if (manifestTemplate != null) {
project.jar.manifest.from manifest
project.jar.inputs.files manifest
}
}
@TaskAction
void createManifest() {
if (manifestTemplate == null) {
return;
}
logging.captureStandardOutput(LogLevel.INFO)
project.mkdir(bundlorDir)
//String inputPath = project.sourceSets.main.classesDir
List<ClassPath> inputClassPath = [] as List;
ManifestWriter manifestWriter = new FileSystemManifestWriter(project.file(bundlorDir.absolutePath));
ManifestContents mfTemplate = BundleManifestUtils.getManifest(manifestTemplate);
inputPaths.each {f ->
inputClassPath.add(new FileSystemClassPath(f))
}
// Must be a better way of doing this...
Properties p = new Properties()
expansions.each {entry ->
p.setProperty(entry.key, entry.value as String)
}
PropertiesSource expansionProps = new PropertiesPropertiesSource(p)
PropertiesSource osgiProfileProps = osgiProfile == null ? new EmptyPropertiesSource() :
new FileSystemPropertiesSource(osgiProfile);
ManifestGenerator manifestGenerator = new StandardManifestGenerator(
DefaultManifestGeneratorContributorsFactory.create(expansionProps, osgiProfileProps));
ManifestContents mf = manifestGenerator.generate(mfTemplate, inputClassPath.toArray(new ClassPath[inputClassPath.size()]));
try {
manifestWriter.write(mf);
} finally {
manifestWriter.close();
}
ManifestValidator manifestValidator = new StandardManifestValidator(DefaultManifestValidatorContributorsFactory.create());
List<String> warnings = manifestValidator.validate(mf);
if (warnings.isEmpty()) {
return
}
logger.warn("Bundlor Warnings:");
for (String warning : warnings) {
logger.warn(" " + warning);
}
if (failOnWarnings) {
throw new GradleException("Bundlor returned warnings. Please fix manifest template at " + manifestTemplate.absolutePath + " and try again.")
}
}
def inputPath(FileCollection paths) {
inputPaths = project.files(inputPaths, paths)
}
}
@@ -48,9 +48,6 @@ class DocbookPlugin implements Plugin<Project> {
Task docbookFoPdf = project.tasks.add("docbookFoPdf", DocbookFoPdf.class);
docbookFoPdf.setDescription('Generates PDF output');
docbookFoPdf.extension = 'fo'
Task docbook = project.tasks.add("docbook", DefaultTask.class);
docbook.dependsOn (docbookHtml, docbookHtmlSingle, docbookFoPdf)
}
}
@@ -72,8 +69,6 @@ public class Docbook extends DefaultTask {
String admonGraphicsPath;
String imgSrcPath;
@InputDirectory
File sourceDirectory = new File(project.getProjectDir(), "src/docbook");
@@ -117,15 +112,11 @@ public class Docbook extends DefaultTask {
}
transformer.setParameter("highlight.xslthl.config", new File(highlightingDir, "xslthl-config.xml").toURI().toURL());
}
if (admonGraphicsPath != null) {
transformer.setParameter("admon.graphics", "1");
transformer.setParameter("admon.graphics.path", admonGraphicsPath);
}
if (imgSrcPath != null) {
transformer.setParameter("img.src.path", imgSrcPath);
if (admonGraphicsPath != null) {
transformer.setParameter("admon.graphics", "1");
transformer.setParameter("admon.graphics.path", admonGraphicsPath);
}
}
preTransform(transformer, srcFile, outputFile);
@@ -263,9 +254,9 @@ class DocbookFoPdf extends Docbook {
}
}
/* if (!foFile.delete()) {
if (!foFile.delete()) {
logger.warn("Failed to delete 'fo' file " + foFile);
}*/
}
}
private File getPdfOutputFile(File foFile) {
@@ -1,114 +0,0 @@
package emma;
import org.gradle.api.*
import org.gradle.api.tasks.testing.Test
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.Input
import com.vladium.emma.instr.InstrProcessor
import com.vladium.emma.report.ReportProcessor
import org.gradle.api.tasks.InputFiles
import com.vladium.util.XProperties;
/**
*
* @author Luke Taylor
*/
class EmmaPlugin implements Plugin<Project> {
void apply(Project project) {
Project rootProject = project.rootProject
def emmaMetaDataFile = "${rootProject.buildDir}/emma/emma.em"
def emmaCoverageFile = "${rootProject.buildDir}/emma/emma.ec"
if (project.configurations.findByName('emma_rt') == null) {
project.configurations.add('emma_rt')
project.dependencies {
emma_rt 'emma:emma:2.0.5312'
}
}
project.task('emmaInstrument') {
dependsOn project.classes
doFirst {
InstrProcessor processor = InstrProcessor.create ();
String[] classesDirPath = [project.sourceSets.main.classesDir.absolutePath]
processor.setInstrPath(classesDirPath, false);
processor.setOutMode(InstrProcessor.OutMode.OUT_MODE_COPY);
processor.setInstrOutDir("${project.buildDir}/emma/classes");
processor.setMetaOutFile(emmaMetaDataFile);
processor.setMetaOutMerge(true);
//processor.setInclExclFilter (null);
processor.run();
}
}
// Modify test tasks in the project to generate coverage data
project.afterEvaluate {
if (project.hasProperty('coverage') && ['on','true'].contains(project.properties.coverage)) {
project.tasks.withType(Test.class).each { task ->
task.dependsOn project.emmaInstrument
task.configure() {
jvmArgs '-Dsec.log.level=DEBUG', "-Demma.coverage.out.file=$emmaCoverageFile"
jvmArgs '-Demma.verbosity.level=quiet'
}
task.doFirst {
classpath = project.files("${project.buildDir}/emma/classes") + project.configurations.emma_rt + classpath
}
}
}
}
List<Task> reportTasks = rootProject.getTasksByName('coverageReport', false) as List;
CoverageReport task;
if (reportTasks.isEmpty()) {
task = rootProject.tasks.add('coverageReport', CoverageReport.class);
task.dataPath = [emmaMetaDataFile, emmaCoverageFile];
} else {
task = reportTasks[0];
}
task.modules.add(project);
}
}
class CoverageReport extends DefaultTask {
@Input
List<Project> modules = [];
@Input
String[] dataPath;
@TaskAction
void generateReport() {
def buildDir = project.rootProject.buildDir
if (!buildDir.exists()) {
throw new GradleException("No coverage data. Run gradle with -Pcoverage=on if using coverageReport");
}
ReportProcessor processor = ReportProcessor.create ();
processor.setDataPath(dataPath)
def srcPath = []
modules.each {module->
module.sourceSets.main.java.srcDirs.each {
srcPath.add(it.absolutePath)
}
}
processor.setSourcePath(srcPath as String[]);
def types = ['txt', 'html']
processor.setReportTypes(types as String[]);
XProperties properties = new XProperties();
properties.setProperty('report.html.out.file', "$buildDir/emma/coverage.html");
properties.setProperty('report.txt.out.file', "$buildDir/emma/coverage.txt");
processor.setPropertyOverrides(properties)
processor.run()
}
}
@@ -1,26 +0,0 @@
package gae;
import com.google.appengine.tools.admin.AppCfg
import org.gradle.api.*;
class GaePlugin implements Plugin<Project> {
public void apply(Project project) {
if (!project.hasProperty('appEngineSdkRoot')) {
println "'appEngineSdkRoot' must be set in gradle.properties"
} else {
System.setProperty('appengine.sdk.root', project.property('appEngineSdkRoot'))
}
File explodedWar = new File(project.buildDir, "gae-exploded")
project.task('gaeDeploy') << {
AppCfg.main("update", explodedWar.toString())
}
project.gaeDeploy.dependsOn project.war
project.war.doLast {
ant.unzip(src: project.war.archivePath, dest: explodedWar)
}
}
}
@@ -1 +0,0 @@
implementation-class=aspectj.AspectJPlugin
@@ -1 +0,0 @@
implementation-class=bundlor.BundlorPlugin
@@ -1 +0,0 @@
implementation-class=emma.EmmaPlugin
@@ -1 +0,0 @@
implementation-class=gae.GaePlugin
+2 -1
View File
@@ -4,8 +4,9 @@ dependencies {
project(':spring-security-web'),
"org.springframework:spring-context:$springVersion",
"org.springframework:spring-beans:$springVersion",
"org.springframework:spring-tx:$springVersion",
"org.springframework:spring-web:$springVersion",
"org.jasig.cas.client:cas-client-core:3.1.12",
"org.jasig.cas:cas-client-core:3.1.9",
"net.sf.ehcache:ehcache:$ehcacheVersion"
provided 'javax.servlet:servlet-api:2.5'
+55
View File
@@ -0,0 +1,55 @@
<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.4.RELEASE</version>
</parent>
<artifactId>spring-security-cas-client</artifactId>
<name>Spring Security - CAS support</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-web</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jasig.cas</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.1.10</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -38,8 +38,6 @@ public class ServiceProperties implements InitializingBean {
private String service;
private boolean authenticateAllArtifacts;
private boolean sendRenew = false;
private String artifactParameter = DEFAULT_CAS_ARTIFACT_PARAMETER;
@@ -49,9 +47,7 @@ public class ServiceProperties implements InitializingBean {
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
if(!authenticateAllArtifacts) {
Assert.hasLength(this.service, "service must be specified unless authenticateAllArtifacts is true.");
}
Assert.hasLength(this.service, "service must be specified.");
Assert.hasLength(this.artifactParameter, "artifactParameter cannot be empty.");
Assert.hasLength(this.serviceParameter, "serviceParameter cannot be empty.");
}
@@ -119,19 +115,4 @@ public class ServiceProperties implements InitializingBean {
public final void setServiceParameter(final String serviceParameter) {
this.serviceParameter = serviceParameter;
}
public final boolean isAuthenticateAllArtifacts() {
return authenticateAllArtifacts;
}
/**
* If true, then any non-null artifact (ticket) should be authenticated.
* Additionally, the service will be determined dynamically in order to
* ensure the service matches the expected value for this artifact.
*
* @param authenticateAllArtifacts
*/
public final void setAuthenticateAllArtifacts(final boolean authenticateAllArtifacts) {
this.authenticateAllArtifacts = authenticateAllArtifacts;
}
}
@@ -19,7 +19,6 @@ import java.util.ArrayList;
import org.jasig.cas.client.validation.Assertion;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
/**
* Temporary authentication object needed to load the user details service.
@@ -29,8 +28,6 @@ import org.springframework.security.core.SpringSecurityCoreVersion;
*/
public final class CasAssertionAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
private final Assertion assertion;
private final String ticket;
@@ -15,8 +15,6 @@
package org.springframework.security.cas.authentication;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.TicketValidationException;
import org.jasig.cas.client.validation.TicketValidator;
@@ -30,12 +28,9 @@ import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
import org.springframework.security.core.userdetails.*;
import org.springframework.util.Assert;
@@ -53,22 +48,17 @@ import org.springframework.util.Assert;
* @author Scott Battaglia
*/
public class CasAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(CasAuthenticationProvider.class);
//~ Instance fields ================================================================================================
private AuthenticationUserDetailsService<CasAssertionAuthenticationToken> authenticationUserDetailsService;
private AuthenticationUserDetailsService authenticationUserDetailsService;
private final UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
private UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
private StatelessTicketCache statelessTicketCache = new NullStatelessTicketCache();
private String key;
private TicketValidator ticketValidator;
private ServiceProperties serviceProperties;
private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
//~ Methods ========================================================================================================
@@ -78,6 +68,7 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
Assert.notNull(this.statelessTicketCache, "A statelessTicketCache must be set");
Assert.hasText(this.key, "A Key is required so CasAuthenticationProvider can identify tokens it previously authenticated");
Assert.notNull(this.messages, "A message source must be set");
Assert.notNull(this.serviceProperties, "serviceProperties is a required field.");
}
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
@@ -137,42 +128,15 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
private CasAuthenticationToken authenticateNow(final Authentication authentication) throws AuthenticationException {
try {
final Assertion assertion = this.ticketValidator.validate(authentication.getCredentials().toString(), getServiceUrl(authentication));
final Assertion assertion = this.ticketValidator.validate(authentication.getCredentials().toString(), serviceProperties.getService());
final UserDetails userDetails = loadUserByAssertion(assertion);
userDetailsChecker.check(userDetails);
return new CasAuthenticationToken(this.key, userDetails, authentication.getCredentials(),
authoritiesMapper.mapAuthorities(userDetails.getAuthorities()), userDetails, assertion);
return new CasAuthenticationToken(this.key, userDetails, authentication.getCredentials(), userDetails.getAuthorities(), userDetails, assertion);
} catch (final TicketValidationException e) {
throw new BadCredentialsException(e.getMessage(), e);
}
}
/**
* Gets the serviceUrl. If the {@link Authentication#getDetails()} is an
* instance of {@link ServiceAuthenticationDetails}, then
* {@link ServiceAuthenticationDetails#getServiceUrl()} is used. Otherwise,
* the {@link ServiceProperties#getService()} is used.
*
* @param authentication
* @return
*/
private String getServiceUrl(Authentication authentication) {
String serviceUrl;
if(authentication.getDetails() instanceof ServiceAuthenticationDetails) {
serviceUrl = ((ServiceAuthenticationDetails)authentication.getDetails()).getServiceUrl();
}else if(serviceProperties == null){
throw new IllegalStateException("serviceProperties cannot be null unless Authentication.getDetails() implements ServiceAuthenticationDetails.");
}else if(serviceProperties.getService() == null){
throw new IllegalStateException("serviceProperties.getService() cannot be null unless Authentication.getDetails() implements ServiceAuthenticationDetails.");
}else {
serviceUrl = serviceProperties.getService();
}
if(logger.isDebugEnabled()) {
logger.debug("serviceUrl = "+serviceUrl);
}
return serviceUrl;
}
/**
* Template method for retrieving the UserDetails based on the assertion. Default is to call configured userDetailsService and pass the username. Deployers
* can override this method and retrieve the user based on any criteria they desire.
@@ -186,7 +150,6 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
}
@Deprecated
@SuppressWarnings("unchecked")
/**
* @deprecated as of 3.0. Use the {@link org.springframework.security.cas.authentication.CasAuthenticationProvider#setAuthenticationUserDetailsService(org.springframework.security.core.userdetails.AuthenticationUserDetailsService)} instead.
*/
@@ -194,7 +157,7 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
this.authenticationUserDetailsService = new UserDetailsByNameServiceWrapper(userDetailsService);
}
public void setAuthenticationUserDetailsService(final AuthenticationUserDetailsService<CasAssertionAuthenticationToken> authenticationUserDetailsService) {
public void setAuthenticationUserDetailsService(final AuthenticationUserDetailsService authenticationUserDetailsService) {
this.authenticationUserDetailsService = authenticationUserDetailsService;
}
@@ -230,11 +193,7 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
this.ticketValidator = ticketValidator;
}
public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
this.authoritiesMapper = authoritiesMapper;
}
public boolean supports(final Class<?> authentication) {
public boolean supports(final Class<? extends Object> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)) ||
(CasAuthenticationToken.class.isAssignableFrom(authentication)) ||
(CasAssertionAuthenticationToken.class.isAssignableFrom(authentication));
@@ -21,7 +21,6 @@ import java.util.Collection;
import org.jasig.cas.client.validation.Assertion;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.security.core.userdetails.UserDetails;
/**
@@ -31,10 +30,9 @@ import org.springframework.security.core.userdetails.UserDetails;
* @author Scott Battaglia
*/
public class CasAuthenticationToken extends AbstractAuthenticationToken implements Serializable {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private final Object credentials;
private final Object principal;
private final UserDetails userDetails;
@@ -15,17 +15,23 @@
package org.springframework.security.cas.authentication;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.Element;
import net.sf.ehcache.Ehcache;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.util.Assert;
/**
* Caches tickets using a Spring IoC defined <a href="http://ehcache.sourceforge.net">EHCACHE</a>.
* Caches tickets using a Spring IoC defined <A HREF="http://ehcache.sourceforge.net">EHCACHE</a>.
*
* @author Ben Alex
*/
@@ -45,13 +51,18 @@ public class EhCacheBasedTicketCache implements StatelessTicketCache, Initializi
}
public CasAuthenticationToken getByTicketId(final String serviceTicket) {
final Element element = cache.get(serviceTicket);
try {
final Element element = cache.get(serviceTicket);
if (logger.isDebugEnabled()) {
logger.debug("Cache hit: " + (element != null) + "; service ticket: " + serviceTicket);
if (logger.isDebugEnabled()) {
logger.debug("Cache hit: " + (element != null) + "; service ticket: " + serviceTicket);
}
return element == null ? null : (CasAuthenticationToken) element.getValue();
} catch (CacheException cacheException) {
throw new DataRetrievalFailureException("Cache failure: " + cacheException.getMessage());
}
return element == null ? null : (CasAuthenticationToken) element.getValue();
}
public Ehcache getCache() {
@@ -14,10 +14,13 @@
*/
package org.springframework.security.cas.userdetails;
import org.jasig.cas.client.validation.Assertion;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.core.Authentication;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.springframework.util.Assert;
import org.jasig.cas.client.validation.Assertion;
/**
* Abstract class for using the provided CAS assertion to construct a new User object. This generally is most
@@ -26,11 +29,11 @@ import org.springframework.security.core.userdetails.UserDetails;
* @author Scott Battaglia
* @since 3.0
*/
public abstract class AbstractCasAssertionUserDetailsService
implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken> {
public abstract class AbstractCasAssertionUserDetailsService implements AuthenticationUserDetailsService {
public final UserDetails loadUserDetails(final CasAssertionAuthenticationToken token) {
return loadUserDetails(token.getAssertion());
public final UserDetails loadUserDetails(final Authentication token) throws UsernameNotFoundException {
Assert.isInstanceOf(CasAssertionAuthenticationToken.class, token, "The provided token MUST be an instance of CasAssertionAuthenticationToken.class");
return loadUserDetails(((CasAssertionAuthenticationToken) token).getAssertion());
}
/**
@@ -17,7 +17,7 @@ package org.springframework.security.cas.userdetails;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.util.Assert;
import org.jasig.cas.client.validation.Assertion;
@@ -36,7 +36,7 @@ public final class GrantedAuthorityFromAssertionAttributesUserDetailsService ext
private static final String NON_EXISTENT_PASSWORD_VALUE = "NO_PASSWORD";
private final String[] attributes;
private String[] attributes;
private boolean convertToUpperCase = true;
@@ -62,11 +62,11 @@ public final class GrantedAuthorityFromAssertionAttributesUserDetailsService ext
final List list = (List) value;
for (final Object o : list) {
grantedAuthorities.add(new SimpleGrantedAuthority(this.convertToUpperCase ? o.toString().toUpperCase() : o.toString()));
grantedAuthorities.add(new GrantedAuthorityImpl(this.convertToUpperCase ? o.toString().toUpperCase() : o.toString()));
}
} else {
grantedAuthorities.add(new SimpleGrantedAuthority(this.convertToUpperCase ? value.toString().toUpperCase() : value.toString()));
grantedAuthorities.add(new GrantedAuthorityImpl(this.convertToUpperCase ? value.toString().toUpperCase() : value.toString()));
}
}
@@ -65,7 +65,6 @@ public class CasAuthenticationEntryPoint implements AuthenticationEntryPoint, In
public void afterPropertiesSet() throws Exception {
Assert.hasLength(this.loginUrl, "loginUrl must be specified");
Assert.notNull(this.serviceProperties, "serviceProperties must be specified");
Assert.notNull(this.serviceProperties.getService(),"serviceProperties.getService() cannot be null.");
}
public final void commence(final HttpServletRequest servletRequest, final HttpServletResponse response,
@@ -17,142 +17,43 @@ package org.springframework.security.cas.web;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.validation.TicketValidator;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails;
import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.util.Assert;
/**
* Processes a CAS service ticket, obtains proxy granting tickets, and processes proxy tickets.
* <h2>Service Tickets</h2>
* Processes a CAS service ticket.
* <p>
* A service ticket consists of an opaque ticket string. It arrives at this filter by the user's browser successfully
* authenticating using CAS, and then receiving a HTTP redirect to a <code>service</code>. The opaque ticket string is
* presented in the <code>ticket</code> request parameter.
* <p>
* This filter monitors the <code>service</code> URL so it can
* receive the service ticket and process it. By default this filter processes the URL <tt>/j_spring_cas_security_check</tt>.
* When processing this URL, the value of {@link ServiceProperties#getService()} is used as the <tt>service</tt> when validating
* the <code>ticket</code>. This means that it is important that {@link ServiceProperties#getService()} specifies the same value
* as the <tt>filterProcessesUrl</tt>.
* presented in the <code>ticket</code> request parameter. This filter monitors the <code>service</code> URL so it can
* receive the service ticket and process it. The CAS server knows which <code>service</code> URL to use via the
* {@link ServiceProperties#getService()} method.
* <p>
* Processing the service ticket involves creating a <code>UsernamePasswordAuthenticationToken</code> which
* uses {@link #CAS_STATEFUL_IDENTIFIER} for the <code>principal</code> and the opaque ticket string as the
* <code>credentials</code>.
* <h2>Obtaining Proxy Granting Tickets</h2>
* <p>
* If specified, the filter can also monitor the <code>proxyReceptorUrl</code>. The filter will respond to requests matching
* this url so that the CAS Server can provide a PGT to the filter. Note that in addition to the <code>proxyReceptorUrl</code> a non-null
* <code>proxyGrantingTicketStorage</code> must be provided in order for the filter to respond to proxy receptor requests. By configuring
* a shared {@link ProxyGrantingTicketStorage} between the {@link TicketValidator} and the CasAuthenticationFilter one can have the
* CasAuthenticationFilter handle the proxying requirements for CAS.
* <h2>Proxy Tickets</h2>
* <p>
* The filter can process tickets present on any url. This is useful when wanting to process proxy tickets. In order for proxy
* tickets to get processed {@link ServiceProperties#isAuthenticateAllArtifacts()} must return <code>true</code>. Additionally,
* if the request is already authenticated, authentication will <b>not</b> occur. Last, {@link AuthenticationDetailsSource#buildDetails(Object)}
* must return a {@link ServiceAuthenticationDetails}. This can be accomplished using the {@link ServiceAuthenticationDetailsSource}.
* In this case {@link ServiceAuthenticationDetails#getServiceUrl()} will be used for the service url.
* <p>
* Processing the proxy ticket involves creating a <code>UsernamePasswordAuthenticationToken</code> which
* uses {@link #CAS_STATELESS_IDENTIFIER} for the <code>principal</code> and the opaque ticket string as the
* <code>credentials</code>. When a proxy ticket is successfully authenticated, the FilterChain continues and the
* <code>authenticationSuccessHandler</code> is not used.
* <h2>Notes about the <code>AuthenticationManager</code></h2>
* <p>
* The configured <code>AuthenticationManager</code> is expected to provide a provider that can recognise
* <code>UsernamePasswordAuthenticationToken</code>s containing this special <code>principal</code> name, and process
* them accordingly by validation with the CAS server. Additionally, it should be capable of using the result of
* {@link ServiceAuthenticationDetails#getServiceUrl()} as the service when validating the ticket.
* <h2>Example Configuration</h2>
* them accordingly by validation with the CAS server.
* <p>
* An example configuration that supports service tickets, obtaining proxy granting tickets, and proxy tickets is
* illustrated below:
*
* <pre>
* &lt;b:bean id=&quot;serviceProperties&quot;
* class=&quot;org.springframework.security.cas.ServiceProperties&quot;
* p:service=&quot;https://service.example.com/cas-sample/j_spring_cas_security_check&quot;
* p:authenticateAllArtifacts=&quot;true&quot;/&gt;
* &lt;b:bean id=&quot;casEntryPoint&quot;
* class=&quot;org.springframework.security.cas.web.CasAuthenticationEntryPoint&quot;
* p:serviceProperties-ref=&quot;serviceProperties&quot; p:loginUrl=&quot;https://login.example.org/cas/login&quot; /&gt;
* &lt;b:bean id=&quot;casFilter&quot;
* class=&quot;org.springframework.security.cas.web.CasAuthenticationFilter&quot;
* p:authenticationManager-ref=&quot;authManager&quot;
* p:serviceProperties-ref=&quot;serviceProperties&quot;
* p:proxyGrantingTicketStorage-ref=&quot;pgtStorage&quot;
* p:proxyReceptorUrl=&quot;/j_spring_cas_security_proxyreceptor&quot;&gt;
* &lt;b:property name=&quot;authenticationDetailsSource&quot;&gt;
* &lt;b:bean class=&quot;org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource&quot;/&gt;
* &lt;/b:property&gt;
* &lt;b:property name=&quot;authenticationFailureHandler&quot;&gt;
* &lt;b:bean class=&quot;org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler&quot;
* p:defaultFailureUrl=&quot;/casfailed.jsp&quot;/&gt;
* &lt;/b:property&gt;
* &lt;/b:bean&gt;
* &lt;!--
* NOTE: In a real application you should not use an in memory implementation. You will also want
* to ensure to clean up expired tickets by calling ProxyGrantingTicketStorage.cleanup()
* --&gt;
* &lt;b:bean id=&quot;pgtStorage&quot; class=&quot;org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl&quot;/&gt;
* &lt;b:bean id=&quot;casAuthProvider&quot; class=&quot;org.springframework.security.cas.authentication.CasAuthenticationProvider&quot;
* p:serviceProperties-ref=&quot;serviceProperties&quot;
* p:key=&quot;casAuthProviderKey&quot;&gt;
* &lt;b:property name=&quot;authenticationUserDetailsService&quot;&gt;
* &lt;b:bean
* class=&quot;org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper&quot;&gt;
* &lt;b:constructor-arg ref=&quot;userService&quot; /&gt;
* &lt;/b:bean&gt;
* &lt;/b:property&gt;
* &lt;b:property name=&quot;ticketValidator&quot;&gt;
* &lt;b:bean
* class=&quot;org.jasig.cas.client.validation.Cas20ProxyTicketValidator&quot;
* p:acceptAnyProxy=&quot;true&quot;
* p:proxyCallbackUrl=&quot;https://service.example.com/cas-sample/j_spring_cas_security_proxyreceptor&quot;
* p:proxyGrantingTicketStorage-ref=&quot;pgtStorage&quot;&gt;
* &lt;b:constructor-arg value=&quot;https://login.example.org/cas&quot; /&gt;
* &lt;/b:bean&gt;
* &lt;/b:property&gt;
* &lt;b:property name=&quot;statelessTicketCache&quot;&gt;
* &lt;b:bean class=&quot;org.springframework.security.cas.authentication.EhCacheBasedTicketCache&quot;&gt;
* &lt;b:property name=&quot;cache&quot;&gt;
* &lt;b:bean class=&quot;net.sf.ehcache.Cache&quot;
* init-method=&quot;initialise&quot;
* destroy-method=&quot;dispose&quot;&gt;
* &lt;b:constructor-arg value=&quot;casTickets&quot;/&gt;
* &lt;b:constructor-arg value=&quot;50&quot;/&gt;
* &lt;b:constructor-arg value=&quot;true&quot;/&gt;
* &lt;b:constructor-arg value=&quot;false&quot;/&gt;
* &lt;b:constructor-arg value=&quot;3600&quot;/&gt;
* &lt;b:constructor-arg value=&quot;900&quot;/&gt;
* &lt;/b:bean&gt;
* &lt;/b:property&gt;
* &lt;/b:bean&gt;
* &lt;/b:property&gt;
* &lt;/b:bean&gt;
* </pre>
* By configuring a shared {@link ProxyGrantingTicketStorage} between the {@link TicketValidator} and the
* CasAuthenticationFilter one can have the CasAuthenticationFilter handle the proxying requirements for CAS. In addition, the
* URI endpoint for the proxying would also need to be configured (i.e. the part after protocol, hostname, and port).
* <p>
* By default this filter processes the URL <tt>/j_spring_cas_security_check</tt>.
*
* @author Ben Alex
* @author Rob Winch
*/
public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
//~ Static fields/initializers =====================================================================================
@@ -179,59 +80,20 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
private String artifactParameter = ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER;
private boolean authenticateAllArtifacts;
private AuthenticationFailureHandler proxyFailureHandler = new SimpleUrlAuthenticationFailureHandler();
//~ Constructors ===================================================================================================
public CasAuthenticationFilter() {
super("/j_spring_cas_security_check");
setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler());
}
//~ Methods ========================================================================================================
@Override
protected final void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response, FilterChain chain, Authentication authResult)
throws IOException, ServletException {
boolean continueFilterChain = proxyTicketRequest(serviceTicketRequest(request, response),request);
if(!continueFilterChain) {
super.successfulAuthentication(request, response, chain, authResult);
return;
}
if (logger.isDebugEnabled()) {
logger.debug("Authentication success. Updating SecurityContextHolder to contain: " + authResult);
}
SecurityContextHolder.getContext().setAuthentication(authResult);
// Fire event
if (this.eventPublisher != null) {
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
}
chain.doFilter(request, response);
}
@Override
public Authentication attemptAuthentication(final HttpServletRequest request, final HttpServletResponse response)
throws AuthenticationException, IOException {
// if the request is a proxy request process it and return null to indicate the request has been processed
if(proxyReceptorRequest(request)) {
logger.debug("Responding to proxy receptor request");
CommonUtils.readAndRespondToProxyReceptorRequest(request, response, this.proxyGrantingTicketStorage);
return null;
}
final boolean serviceTicketRequest = serviceTicketRequest(request, response);
final String username = serviceTicketRequest ? CAS_STATEFUL_IDENTIFIER : CAS_STATELESS_IDENTIFIER;
String password = obtainArtifact(request);
throws AuthenticationException {
final String username = CAS_STATEFUL_IDENTIFIER;
String password = request.getParameter(this.artifactParameter);
if (password == null) {
logger.debug("Failed to obtain an artifact (cas ticket)");
password = "";
}
@@ -242,47 +104,22 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
return this.getAuthenticationManager().authenticate(authRequest);
}
/**
* If present, gets the artifact (CAS ticket) from the {@link HttpServletRequest}.
* @param request
* @return if present the artifact from the {@link HttpServletRequest}, else null
*/
protected String obtainArtifact(HttpServletRequest request) {
return request.getParameter(artifactParameter);
}
/**
* Overridden to provide proxying capabilities.
*/
@Override
protected boolean requiresAuthentication(final HttpServletRequest request, final HttpServletResponse response) {
final boolean serviceTicketRequest = serviceTicketRequest(request, response);
final boolean result = serviceTicketRequest || proxyReceptorRequest(request) || (proxyTicketRequest(serviceTicketRequest, request));
if(logger.isDebugEnabled()) {
logger.debug("requiresAuthentication = "+result);
final String requestUri = request.getRequestURI();
if (CommonUtils.isEmpty(this.proxyReceptorUrl) || !requestUri.endsWith(this.proxyReceptorUrl) || this.proxyGrantingTicketStorage == null) {
return super.requiresAuthentication(request, response);
}
return result;
}
/**
* Sets the {@link AuthenticationFailureHandler} for proxy requests.
* @param proxyFailureHandler
*/
public final void setProxyAuthenticationFailureHandler(
AuthenticationFailureHandler proxyFailureHandler) {
Assert.notNull(proxyFailureHandler,"proxyFailureHandler cannot be null");
this.proxyFailureHandler = proxyFailureHandler;
}
/**
* Wraps the {@link AuthenticationFailureHandler} to distinguish between
* handling proxy ticket authentication failures and service ticket
* failures.
*/
@Override
public final void setAuthenticationFailureHandler(
AuthenticationFailureHandler failureHandler) {
super.setAuthenticationFailureHandler(new CasAuthenticationFailureHandler(failureHandler));
try {
CommonUtils.readAndRespondToProxyReceptorRequest(request, response, this.proxyGrantingTicketStorage);
return false;
} catch (final IOException e) {
return super.requiresAuthentication(request, response);
}
}
public final void setProxyReceptorUrl(final String proxyReceptorUrl) {
@@ -296,97 +133,5 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
public final void setServiceProperties(final ServiceProperties serviceProperties) {
this.artifactParameter = serviceProperties.getArtifactParameter();
this.authenticateAllArtifacts = serviceProperties.isAuthenticateAllArtifacts();
}
/**
* Indicates if the request is elgible to process a service ticket. This method exists for readability.
* @param request
* @param response
* @return
*/
private boolean serviceTicketRequest(final HttpServletRequest request, final HttpServletResponse response) {
boolean result = super.requiresAuthentication(request, response);
if(logger.isDebugEnabled()) {
logger.debug("serviceTicketRequest = "+result);
}
return result;
}
/**
* Indicates if the request is elgible to process a proxy ticket.
* @param request
* @return
*/
private boolean proxyTicketRequest(final boolean serviceTicketRequest, final HttpServletRequest request) {
if(serviceTicketRequest) {
return false;
}
final boolean result = authenticateAllArtifacts && obtainArtifact(request) != null && !authenticated();
if(logger.isDebugEnabled()) {
logger.debug("proxyTicketRequest = "+result);
}
return result;
}
/**
* Determines if a user is already authenticated.
* @return
*/
private boolean authenticated() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return authentication != null && authentication.isAuthenticated() && !(authentication instanceof AnonymousAuthenticationToken);
}
/**
* Indicates if the request is elgible to be processed as the proxy receptor.
* @param request
* @return
*/
private boolean proxyReceptorRequest(final HttpServletRequest request) {
final String requestUri = request.getRequestURI();
final boolean result = proxyReceptorConfigured() && requestUri.endsWith(this.proxyReceptorUrl);
if(logger.isDebugEnabled()) {
logger.debug("proxyReceptorRequest = "+result);
}
return result;
}
/**
* Determines if the {@link CasAuthenticationFilter} is configured to handle the proxy receptor requests.
*
* @return
*/
private boolean proxyReceptorConfigured() {
final boolean result = this.proxyGrantingTicketStorage != null && !CommonUtils.isEmpty(this.proxyReceptorUrl);
if(logger.isDebugEnabled()) {
logger.debug("proxyReceptorConfigured = "+result);
}
return result;
}
/**
* A wrapper for the AuthenticationFailureHandler that will flex the {@link AuthenticationFailureHandler} that is used. The value
* {@link CasAuthenticationFilter#setProxyAuthenticationFailureHandler(AuthenticationFailureHandler) will be used for proxy requests
* that fail. The value {@link CasAuthenticationFilter#setAuthenticationFailureHandler(AuthenticationFailureHandler)} will be used for
* service tickets that fail.
*
* @author Rob Winch
*/
private class CasAuthenticationFailureHandler implements AuthenticationFailureHandler {
private final AuthenticationFailureHandler serviceTicketFailureHandler;
public CasAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
Assert.notNull(failureHandler,"failureHandler");
this.serviceTicketFailureHandler = failureHandler;
}
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException exception) throws IOException,
ServletException {
if(serviceTicketRequest(request, response)) {
serviceTicketFailureHandler.onAuthenticationFailure(request, response, exception);
}else {
proxyFailureHandler.onAuthenticationFailure(request, response, exception);
}
}
}
}
}
@@ -1,131 +0,0 @@
/*
* Copyright 2011 the original author or authors.
*
* 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.cas.web.authentication;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;
/**
* A default implementation of {@link ServiceAuthenticationDetails} that figures
* out the value for {@link #getServiceUrl()} by inspecting the current
* {@link HttpServletRequest} and using the current URL minus the artifact and
* the corresponding value.
*
* @author Rob Winch
*/
final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails implements ServiceAuthenticationDetails {
private static final long serialVersionUID = 6192409090610517700L;
//~ Instance fields ================================================================================================
private final String serviceUrl;
//~ Constructors ===================================================================================================
/**
* Creates a new instance
* @param request
* the current {@link HttpServletRequest} to obtain the
* {@link #getServiceUrl()} from.
* @param artifactPattern
* the {@link Pattern} that will be used to clean up the query
* string from containing the artifact name and value. This can
* be created using {@link #createArtifactPattern(String)}.
*/
DefaultServiceAuthenticationDetails(HttpServletRequest request, Pattern artifactPattern) {
super(request);
final String query = getQueryString(request,artifactPattern);
this.serviceUrl = UrlUtils.buildFullRequestUrl(request.getScheme(),
request.getServerName(), request.getServerPort(),
request.getRequestURI(), query);
}
//~ Methods ========================================================================================================
/**
* Returns the current URL minus the artifact parameter and its value, if present.
* @see org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails#getServiceUrl()
*/
public String getServiceUrl() {
return serviceUrl;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result
+ serviceUrl.hashCode();
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj) || !(obj instanceof DefaultServiceAuthenticationDetails)) {
return false;
}
ServiceAuthenticationDetails that = (ServiceAuthenticationDetails) obj;
return serviceUrl.equals(that.getServiceUrl());
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append(super.toString());
result.append("ServiceUrl: ");
result.append(serviceUrl);
return result.toString();
}
/**
* If present, removes the artifactParameterName and the corresponding value from the query String.
* @param request
* @return the query String minus the artifactParameterName and the corresponding value.
*/
private String getQueryString(final HttpServletRequest request, final Pattern artifactPattern) {
final String query = request.getQueryString();
if(query == null) {
return null;
}
final String result = artifactPattern.matcher(query).replaceFirst("");
if(result.length() == 0) {
return null;
}
// strip off the trailing & only if the artifact was the first query param
return result.startsWith("&") ? result.substring(1) : result;
}
/**
* Creates a {@link Pattern} that can be passed into the constructor. This
* allows the {@link Pattern} to be reused for every instance of
* {@link DefaultServiceAuthenticationDetails}.
*
* @param artifactParameterName
* @return
*/
static Pattern createArtifactPattern(String artifactParameterName) {
Assert.hasLength(artifactParameterName);
return Pattern.compile("&?"+Pattern.quote(artifactParameterName)+"=[^&]*");
}
}
@@ -1,43 +0,0 @@
/*
* Copyright 2011 the original author or authors.
*
* 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.cas.web.authentication;
import java.io.Serializable;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.core.Authentication;
/**
* In order for the {@link CasAuthenticationProvider} to provide the correct
* service url to authenticate the ticket, the returned value of
* {@link Authentication#getDetails()} should implement this interface when
* tickets can be sent to any URL rather than only
* {@link ServiceProperties#getService()}.
*
* @author Rob Winch
*
* @see ServiceAuthenticationDetailsSource
*/
public interface ServiceAuthenticationDetails extends Serializable {
/**
* Gets the absolute service url (i.e. https://example.com/service/).
*
* @return the service url. Cannot be <code>null</code>.
*/
String getServiceUrl();
}
@@ -1,71 +0,0 @@
/*
* Copyright 2011 the original author or authors.
*
* 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.cas.web.authentication;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.cas.ServiceProperties;
/**
* The {@code AuthenticationDetailsSource} that is set on the
* {@code CasAuthenticationFilter} should return a value that implements
* {@code ServiceAuthenticationDetails} if the application needs to authenticate
* dynamic service urls. The
* {@code ServiceAuthenticationDetailsSource#buildDetails(HttpServletRequest)}
* creates a default {@code ServiceAuthenticationDetails}.
*
* @author Rob Winch
*/
public class ServiceAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest,
ServiceAuthenticationDetails> {
//~ Instance fields ================================================================================================
private final Pattern artifactPattern;
//~ Constructors ===================================================================================================
/**
* Creates an implementation that uses the default CAS artifactParameterName.
*/
public ServiceAuthenticationDetailsSource() {
this(ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER);
}
/**
* Creates an implementation that uses the specified artifactParameterName
*
* @param artifactParameterName
* the artifactParameterName that is removed from the current
* URL. The result becomes the service url. Cannot be null and
* cannot be an empty String.
*/
public ServiceAuthenticationDetailsSource(final String artifactParameterName) {
this.artifactPattern = DefaultServiceAuthenticationDetails.createArtifactPattern(artifactParameterName);
}
//~ Methods ========================================================================================================
/**
* @param context the {@code HttpServletRequest} object.
* @return the {@code ServiceAuthenticationDetails} containing information about the current request
*/
public ServiceAuthenticationDetails buildDetails(HttpServletRequest context) {
return new DefaultServiceAuthenticationDetails(context,artifactPattern);
}
}
@@ -1,5 +0,0 @@
/**
* Authentication processing mechanisms which respond to the submission of authentication
* credentials using CAS.
*/
package org.springframework.security.cas.web.authentication;
@@ -15,31 +15,30 @@
package org.springframework.security.cas.authentication;
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
import java.util.HashMap;
import java.util.Map;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.AssertionImpl;
import org.jasig.cas.client.validation.TicketValidationException;
import org.jasig.cas.client.validation.TicketValidator;
import org.junit.*;
import org.springframework.mock.web.MockHttpServletRequest;
import org.junit.Test;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetails;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import java.util.*;
/**
@@ -48,7 +47,6 @@ import java.util.*;
* @author Ben Alex
* @author Scott Battaglia
*/
@SuppressWarnings("unchecked")
public class CasAuthenticationProviderTests {
//~ Methods ========================================================================================================
@@ -99,8 +97,8 @@ public class CasAuthenticationProviderTests {
CasAuthenticationToken casResult = (CasAuthenticationToken) result;
assertEquals(makeUserDetailsFromAuthoritiesPopulator(), casResult.getPrincipal());
assertEquals("ST-123", casResult.getCredentials());
assertTrue(casResult.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_A")));
assertTrue(casResult.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_B")));
assertTrue(casResult.getAuthorities().contains(new GrantedAuthorityImpl("ROLE_A")));
assertTrue(casResult.getAuthorities().contains(new GrantedAuthorityImpl("ROLE_B")));
assertEquals(cap.getKey().hashCode(), casResult.getKeyHash());
assertEquals("details", casResult.getDetails());
@@ -151,87 +149,6 @@ public class CasAuthenticationProviderTests {
assertEquals("ST-456", newResult.getCredentials());
}
@Test
public void authenticateAllNullService() throws Exception {
String serviceUrl = "https://service/context";
ServiceAuthenticationDetails details = mock(ServiceAuthenticationDetails.class);
when(details.getServiceUrl()).thenReturn(serviceUrl);
TicketValidator validator = mock(TicketValidator.class);
when(validator.validate(any(String.class),any(String.class))).thenReturn(new AssertionImpl("rod"));
ServiceProperties serviceProperties = makeServiceProperties();
serviceProperties.setAuthenticateAllArtifacts(true);
CasAuthenticationProvider cap = new CasAuthenticationProvider();
cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
cap.setKey("qwerty");
cap.setTicketValidator(validator);
cap.setServiceProperties(serviceProperties);
cap.afterPropertiesSet();
String ticket = "ST-456";
UsernamePasswordAuthenticationToken token =
new UsernamePasswordAuthenticationToken(CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, ticket);
Authentication result = cap.authenticate(token);
}
@Test
public void authenticateAllAuthenticationIsSuccessful() throws Exception {
String serviceUrl = "https://service/context";
ServiceAuthenticationDetails details = mock(ServiceAuthenticationDetails.class);
when(details.getServiceUrl()).thenReturn(serviceUrl);
TicketValidator validator = mock(TicketValidator.class);
when(validator.validate(any(String.class),any(String.class))).thenReturn(new AssertionImpl("rod"));
ServiceProperties serviceProperties = makeServiceProperties();
serviceProperties.setAuthenticateAllArtifacts(true);
CasAuthenticationProvider cap = new CasAuthenticationProvider();
cap.setAuthenticationUserDetailsService(new MockAuthoritiesPopulator());
cap.setKey("qwerty");
cap.setTicketValidator(validator);
cap.setServiceProperties(serviceProperties);
cap.afterPropertiesSet();
String ticket = "ST-456";
UsernamePasswordAuthenticationToken token =
new UsernamePasswordAuthenticationToken(CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER, ticket);
Authentication result = cap.authenticate(token);
verify(validator).validate(ticket, serviceProperties.getService());
serviceProperties.setAuthenticateAllArtifacts(true);
result = cap.authenticate(token);
verify(validator,times(2)).validate(ticket, serviceProperties.getService());
token.setDetails(details);
result = cap.authenticate(token);
verify(validator).validate(ticket, serviceUrl);
serviceProperties.setAuthenticateAllArtifacts(false);
serviceProperties.setService(null);
cap.setServiceProperties(serviceProperties);
cap.afterPropertiesSet();
result = cap.authenticate(token);
verify(validator,times(2)).validate(ticket, serviceUrl);
token.setDetails(new WebAuthenticationDetails(new MockHttpServletRequest()));
try {
cap.authenticate(token);
fail("Expected Exception");
}catch(IllegalStateException success) {}
cap.setServiceProperties(null);
cap.afterPropertiesSet();
try {
cap.authenticate(token);
fail("Expected Exception");
}catch(IllegalStateException success) {}
}
@Test(expected = BadCredentialsException.class)
public void missingTicketIdIsDetected() throws Exception {
CasAuthenticationProvider cap = new CasAuthenticationProvider();
@@ -338,7 +255,8 @@ public class CasAuthenticationProviderTests {
cap.setServiceProperties(makeServiceProperties());
cap.afterPropertiesSet();
TestingAuthenticationToken token = new TestingAuthenticationToken("user", "password", "ROLE_A");
TestingAuthenticationToken token = new TestingAuthenticationToken("user", "password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_A")});
assertFalse(cap.supports(TestingAuthenticationToken.class));
// Try it anyway
@@ -15,18 +15,19 @@
package org.springframework.security.cas.authentication;
import java.util.List;
import junit.framework.TestCase;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.AssertionImpl;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.*;
/**
* Tests {@link CasAuthenticationToken}.
*
@@ -107,8 +108,8 @@ public class CasAuthenticationTokenTests extends TestCase {
assertEquals("key".hashCode(), token.getKeyHash());
assertEquals(makeUserDetails(), token.getPrincipal());
assertEquals("Password", token.getCredentials());
assertTrue(token.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_ONE")));
assertTrue(token.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_TWO")));
assertTrue(token.getAuthorities().contains(new GrantedAuthorityImpl("ROLE_ONE")));
assertTrue(token.getAuthorities().contains(new GrantedAuthorityImpl("ROLE_TWO")));
assertEquals(assertion, token.getAssertion());
assertEquals(makeUserDetails().getUsername(), token.getUserDetails().getUsername());
}
@@ -1,49 +0,0 @@
package org.springframework.security.cas.userdetails;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.validation.Assertion;
import org.junit.Test;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @author Luke Taylor
*/
public class GrantedAuthorityFromAssertionAttributesUserDetailsServiceTests {
@Test
public void correctlyExtractsNamedAttributesFromAssertionAndConvertsThemToAuthorities() {
GrantedAuthorityFromAssertionAttributesUserDetailsService uds =
new GrantedAuthorityFromAssertionAttributesUserDetailsService(new String[] {"a", "b", "c", "d"});
uds.setConvertToUpperCase(false);
Assertion assertion = mock(Assertion.class);
AttributePrincipal principal = mock(AttributePrincipal.class);
Map<String, Object> attributes = new HashMap<String, Object>();
attributes.put("a", Arrays.asList("role_a1", "role_a2"));
attributes.put("b", "role_b");
attributes.put("c", "role_c");
attributes.put("d", null);
attributes.put("someother", "unused");
when(assertion.getPrincipal()).thenReturn(principal);
when(principal.getAttributes()).thenReturn(attributes);
when(principal.getName()).thenReturn("somebody");
CasAssertionAuthenticationToken token = new CasAssertionAuthenticationToken(assertion, "ticket");
UserDetails user = uds.loadUserDetails(token);
Set<String> roles = AuthorityUtils.authorityListToSet(user.getAuthorities());
assertTrue(roles.size() == 4);
assertTrue(roles.contains("role_a1"));
assertTrue(roles.contains("role_a2"));
assertTrue(roles.contains("role_b"));
assertTrue(roles.contains("role_c"));
}
}
@@ -16,62 +16,33 @@
package org.springframework.security.cas.web;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
import java.lang.reflect.Method;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
import org.junit.After;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.NullRememberMeServices;
import org.springframework.util.ReflectionUtils;
/**
* Tests {@link CasAuthenticationFilter}.
*
* @author Ben Alex
* @author Rob Winch
*/
public class CasAuthenticationFilterTests {
//~ Methods ========================================================================================================
@After
public void tearDown() {
SecurityContextHolder.clearContext();
}
@Test
public void testGettersSetters() {
public void testGetters() {
CasAuthenticationFilter filter = new CasAuthenticationFilter();
assertEquals("/j_spring_cas_security_check", filter.getFilterProcessesUrl());
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
filter.setProxyReceptorUrl("/someurl");
filter.setServiceProperties(new ServiceProperties());
}
@Test
public void testNormalOperation() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/j_spring_cas_security_check");
MockHttpServletRequest request = new MockHttpServletRequest();
request.addParameter("ticket", "ST-0-ER94xMJmn6pha35CQRoZ");
CasAuthenticationFilter filter = new CasAuthenticationFilter();
@@ -81,8 +52,6 @@ public class CasAuthenticationFilterTests {
}
});
assertTrue(filter.requiresAuthentication(request, new MockHttpServletResponse()));
Authentication result = filter.attemptAuthentication(request, new MockHttpServletResponse());
assertTrue(result != null);
}
@@ -98,116 +67,4 @@ public class CasAuthenticationFilterTests {
filter.attemptAuthentication(new MockHttpServletRequest(), new MockHttpServletResponse());
}
@Test
public void testRequiresAuthenticationFilterProcessUrl() {
CasAuthenticationFilter filter = new CasAuthenticationFilter();
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
request.setRequestURI(filter.getFilterProcessesUrl());
assertTrue(filter.requiresAuthentication(request, response));
}
@Test
public void testRequiresAuthenticationProxyRequest() {
CasAuthenticationFilter filter = new CasAuthenticationFilter();
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
request.setRequestURI("/pgtCallback");
assertFalse(filter.requiresAuthentication(request, response));
filter.setProxyReceptorUrl(request.getRequestURI());
assertFalse(filter.requiresAuthentication(request, response));
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
assertTrue(filter.requiresAuthentication(request, response));
request.setRequestURI("/other");
assertFalse(filter.requiresAuthentication(request, response));
}
@Test
public void testRequiresAuthenticationAuthAll() {
ServiceProperties properties = new ServiceProperties();
properties.setAuthenticateAllArtifacts(true);
CasAuthenticationFilter filter = new CasAuthenticationFilter();
filter.setServiceProperties(properties);
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
request.setRequestURI(filter.getFilterProcessesUrl());
assertTrue(filter.requiresAuthentication(request, response));
request.setRequestURI("/other");
assertFalse(filter.requiresAuthentication(request, response));
request.setParameter(properties.getArtifactParameter(), "value");
assertTrue(filter.requiresAuthentication(request, response));
SecurityContextHolder.getContext().setAuthentication(new AnonymousAuthenticationToken("key", "principal", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")));
assertTrue(filter.requiresAuthentication(request, response));
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("un", "principal", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")));
assertTrue(filter.requiresAuthentication(request, response));
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("un", "principal", "ROLE_ANONYMOUS"));
assertFalse(filter.requiresAuthentication(request, response));
}
@Test
public void testAuthenticateProxyUrl() throws Exception {
CasAuthenticationFilter filter = new CasAuthenticationFilter();
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
request.setRequestURI("/pgtCallback");
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
filter.setProxyReceptorUrl(request.getRequestURI());
assertNull(filter.attemptAuthentication(request, response));
}
@Test
public void testDoFilterAuthenticateAll() throws Exception {
AuthenticationSuccessHandler successHandler = mock(AuthenticationSuccessHandler.class);
AuthenticationManager manager = mock(AuthenticationManager.class);
Authentication authentication = new TestingAuthenticationToken("un", "pwd","ROLE_USER");
when(manager.authenticate(any(Authentication.class))).thenReturn(authentication);
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setAuthenticateAllArtifacts(true);
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("ticket", "ST-1-123");
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain chain = mock(FilterChain.class);
CasAuthenticationFilter filter = new CasAuthenticationFilter();
filter.setServiceProperties(serviceProperties);
filter.setAuthenticationSuccessHandler(successHandler);
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
filter.setAuthenticationManager(manager);
filter.afterPropertiesSet();
filter.doFilter(request,response,chain);
assertFalse("Authentication should not be null",SecurityContextHolder.getContext().getAuthentication() == null);
verify(chain).doFilter(request, response);
verifyZeroInteractions(successHandler);
// validate for when the filterProcessUrl matches
filter.setFilterProcessesUrl(request.getRequestURI());
SecurityContextHolder.clearContext();
filter.doFilter(request,response,chain);
verifyNoMoreInteractions(chain);
verify(successHandler).onAuthenticationSuccess(request, response, authentication);
}
// SEC-1592
@Test
public void testChainNotInvokedForProxyReceptor() throws Exception {
CasAuthenticationFilter filter = new CasAuthenticationFilter();
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain chain = mock(FilterChain.class);
request.setRequestURI("/pgtCallback");
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
filter.setProxyReceptorUrl(request.getRequestURI());
filter.doFilter(request,response,chain);
verifyZeroInteractions(chain);
}
}
}
@@ -15,55 +15,40 @@
package org.springframework.security.cas.web;
import static junit.framework.Assert.*;
import org.junit.Test;
import org.springframework.security.cas.SamlServiceProperties;
import org.springframework.security.cas.ServiceProperties;
import junit.framework.TestCase;
/**
* Tests {@link ServiceProperties}.
*
* @author Ben Alex
*/
public class ServicePropertiesTests {
public class ServicePropertiesTests extends TestCase {
//~ Methods ========================================================================================================
@Test(expected=IllegalArgumentException.class)
public void detectsMissingService() throws Exception {
public void testDetectsMissingLoginFormUrl() throws Exception {
ServiceProperties sp = new ServiceProperties();
sp.afterPropertiesSet();
}
@Test
public void allowNullServiceWhenAuthenticateAllTokens() throws Exception {
ServiceProperties sp = new ServiceProperties();
sp.setAuthenticateAllArtifacts(true);
sp.afterPropertiesSet();
sp.setAuthenticateAllArtifacts(false);
try {
sp.afterPropertiesSet();
fail("Expected Exception");
}catch(IllegalArgumentException success) {}
}
@Test
public void testGettersSetters() throws Exception {
ServiceProperties[] sps = {new ServiceProperties(), new SamlServiceProperties()};
for(ServiceProperties sp : sps) {
sp.setSendRenew(false);
assertFalse(sp.isSendRenew());
sp.setSendRenew(true);
assertTrue(sp.isSendRenew());
sp.setArtifactParameter("notticket");
assertEquals("notticket", sp.getArtifactParameter());
sp.setServiceParameter("notservice");
assertEquals("notservice", sp.getServiceParameter());
sp.setService("https://mycompany.com/service");
assertEquals("https://mycompany.com/service", sp.getService());
sp.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("service must be specified.", expected.getMessage());
}
}
public void testGettersSetters() throws Exception {
ServiceProperties sp = new ServiceProperties();
sp.setSendRenew(false);
assertFalse(sp.isSendRenew());
sp.setSendRenew(true);
assertTrue(sp.isSendRenew());
sp.setService("https://mycompany.com/service");
assertEquals("https://mycompany.com/service", sp.getService());
sp.afterPropertiesSet();
}
}
@@ -1,88 +0,0 @@
/*
* Copyright 2011 the original author or authors.
*
* 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.cas.web.authentication;
import static org.junit.Assert.assertEquals;
import java.util.regex.Pattern;
import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.web.util.UrlUtils;
/**
*
* @author Rob Winch
*/
public class DefaultServiceAuthenticationDetailsTests {
private DefaultServiceAuthenticationDetails details;
private MockHttpServletRequest request;
private Pattern artifactPattern;
@Before
public void setUp() {
request = new MockHttpServletRequest();
request.setScheme("https");
request.setServerName("localhost");
request.setServerPort(8443);
request.setRequestURI("/cas-sample/secure/");
artifactPattern = DefaultServiceAuthenticationDetails.createArtifactPattern(ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER);
}
@Test
public void getServiceUrlNullQuery() throws Exception {
details = new DefaultServiceAuthenticationDetails(request,artifactPattern);
assertEquals(UrlUtils.buildFullRequestUrl(request),details.getServiceUrl());
}
@Test
public void getServiceUrlTicketOnlyParam() {
request.setQueryString("ticket=123");
details = new DefaultServiceAuthenticationDetails(request,artifactPattern);
String serviceUrl = details.getServiceUrl();
request.setQueryString(null);
assertEquals(UrlUtils.buildFullRequestUrl(request),serviceUrl);
}
@Test
public void getServiceUrlTicketFirstMultiParam() {
request.setQueryString("ticket=123&other=value");
details = new DefaultServiceAuthenticationDetails(request,artifactPattern);
String serviceUrl = details.getServiceUrl();
request.setQueryString("other=value");
assertEquals(UrlUtils.buildFullRequestUrl(request),serviceUrl);
}
@Test
public void getServiceUrlTicketLastMultiParam() {
request.setQueryString("other=value&ticket=123");
details = new DefaultServiceAuthenticationDetails(request,artifactPattern);
String serviceUrl = details.getServiceUrl();
request.setQueryString("other=value");
assertEquals(UrlUtils.buildFullRequestUrl(request),serviceUrl);
}
@Test
public void getServiceUrlTicketMiddleMultiParam() {
request.setQueryString("other=value&ticket=123&last=this");
details = new DefaultServiceAuthenticationDetails(request,artifactPattern);
String serviceUrl = details.getServiceUrl();
request.setQueryString("other=value&last=this");
assertEquals(UrlUtils.buildFullRequestUrl(request),serviceUrl);
}
}
+12 -12
View File
@@ -5,18 +5,18 @@ Bundle-Name: Spring Security CAS
Bundle-Vendor: SpringSource
Bundle-Version: ${version}
Bundle-ManifestVersion: 2
Ignored-Existing-Headers:
Ignored-Existing-Headers:
Import-Package,
Export-Package
Import-Template:
org.apache.commons.logging.*;version="${cloggingRange}",
org.jasig.cas.client.*;version="${casRange}",
org.springframework.security.core.*;version="${secRange}",
org.springframework.security.authentication.*;version="${secRange}",
org.springframework.security.web.*;version="${secRange}",
org.springframework.beans.factory;version="${springRange}",
org.springframework.context.*;version="${springRange}",
org.springframework.dao;version="${springRange}",
org.springframework.util;version="${springRange}",
net.sf.ehcache.*;version="${ehcacheRange}";resolution:=optional,
Import-Template:
org.apache.commons.logging.*;version="[1.0.4, 2.0.0)",
org.jasig.cas.client.*;version="[3.1.1,3.2)",
org.springframework.security.core.*;version="[${version}, 3.1.0)",
org.springframework.security.authentication.*;version="[${version}, 3.1.0)",
org.springframework.security.web.*;version="[${version}, 3.1.0)",
org.springframework.beans.factory;version="[${spring.version}, 3.1.0)",
org.springframework.context.*;version="[${spring.version}, 3.1.0)",
org.springframework.dao;version="[${spring.version}, 3.1.0)",
org.springframework.util;version="[${spring.version}, 3.1.0)",
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
javax.servlet.*;version="0"
+5 -34
View File
@@ -1,53 +1,24 @@
// Config Module build file
apply plugin: 'groovy'
compileTestJava.dependsOn(':spring-security-core:compileTestJava')
configurations {
// GRADLE-1124
compile.extendsFrom = []
testCompile.extendsFrom groovy
}
dependencies {
// NB: Don't add other compile time dependencies to the config module as this breaks tooling
compile project(':spring-security-core'),
project(':spring-security-web'),
"org.aspectj:aspectjweaver:$aspectjVersion",
'aopalliance:aopalliance:1.0',
"org.aspectj:aspectjweaver:$aspectjVersion",
"org.springframework:spring-aop:$springVersion",
"org.springframework:spring-context:$springVersion",
"org.springframework:spring-web:$springVersion",
"org.springframework:spring-beans:$springVersion"
"org.springframework:spring-beans:$springVersion",
"org.springframework:spring-tx:$springVersion"
provided "javax.servlet:servlet-api:2.5"
groovy group: 'org.codehaus.groovy', name: 'groovy', version: '1.7.10'
testCompile project(':spring-security-ldap'),
project(':spring-security-openid'),
project(':spring-security-core').sourceSets.test.classes,
files(this.project(':spring-security-core').sourceSets.test.classesDir),
'javax.annotation:jsr250-api:1.0',
"org.springframework.ldap:spring-ldap-core:$springLdapVersion",
"org.springframework:spring-expression:$springVersion",
"org.springframework:spring-jdbc:$springVersion",
"org.springframework:spring-tx:$springVersion",
'org.spockframework:spock-core:0.5-groovy-1.7',
"org.slf4j:jcl-over-slf4j:$slf4jVersion"
testCompile('org.openid4java:openid4java-nodeps:0.9.6') {
exclude group: 'com.google.code.guice', module: 'guice'
}
testRuntime "hsqldb:hsqldb:$hsqlVersion",
"cglib:cglib-nodep:2.2"
}
test {
inputs.file file("$rootDir/docs/manual/src/docbook/appendix-namespace.xml")
}
integrationTest {
systemProperties['apacheDSWorkDir'] = "${buildDir}/apacheDSWork"
"org.springframework:spring-jdbc:$springVersion"
}
+2 -2
View File
@@ -3,9 +3,9 @@
pushd src/main/resources/org/springframework/security/config/
echo "Converting rnc file to xsd ..."
java -jar ~/bin/trang.jar spring-security-3.1.rnc spring-security-3.1.xsd
java -jar ~/bin/trang.jar spring-security-3.0.4.rnc spring-security-3.0.4.xsd
echo "Applying XSL transformation to xsd ..."
xsltproc --output spring-security-3.1.xsd spring-security.xsl spring-security-3.1.xsd
xsltproc --output spring-security-3.0.4.xsd spring-security.xsl spring-security-3.0.4.xsd
popd
+113
View File
@@ -0,0 +1,113 @@
<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.4.RELEASE</version>
</parent>
<packaging>jar</packaging>
<artifactId>spring-security-config</artifactId>
<name>Spring Security - Namespace Configuration Module</name>
<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-web</artifactId>
<version>${project.version}</version>
<optional>true</optional>
</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.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${project.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-openid</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.directory.server</groupId>
<artifactId>apacheds-core</artifactId>
<version>1.5.5</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.directory.server</groupId>
<artifactId>apacheds-server-jndi</artifactId>
<version>1.5.5</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -1,153 +0,0 @@
package org.springframework.security.config.ldap
import java.text.MessageFormat
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
import org.springframework.security.config.AbstractXmlConfigTests
import org.springframework.security.config.BeanIds
import org.springframework.security.util.FieldUtils
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.context.ApplicationContextException
import org.springframework.security.core.AuthenticationException
import org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper
/**
* @author Luke Taylor
*/
class LdapProviderBeanDefinitionParserTests extends AbstractXmlConfigTests {
// SEC-1182
def multipleProvidersAreSupported() {
xml.'ldap-server'(url: 'ldap://blah:389/dc=blah')
xml.'authentication-manager'() {
'ldap-authentication-provider'('group-search-filter': 'member={0}')
'ldap-authentication-provider'('group-search-filter': 'uniqueMember={0}')
}
createAppContext('')
def providers = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER).providers
expect:
providers.size() == 2
providers[0].authoritiesPopulator.groupSearchFilter == "member={0}"
providers[1].authoritiesPopulator.groupSearchFilter == "uniqueMember={0}"
}
def simpleProviderAuthenticatesCorrectly() {
xml.'ldap-server'()
xml.'authentication-manager'{
'ldap-authentication-provider'('group-search-filter':'member={0}')
}
createAppContext('')
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
when:
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"))
def ben = auth.principal;
then:
ben.authorities.size() == 3
}
def missingServerEltCausesConfigException() {
xml.'authentication-manager'{
'ldap-authentication-provider'()
}
when:
createAppContext('')
then:
thrown(ApplicationContextException)
}
def supportsPasswordComparisonAuthentication() {
xml.'ldap-server'()
xml.'authentication-manager'{
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people')
'password-compare'
}
createAppContext('')
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
when:
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"))
then:
auth != null
notThrown(AuthenticationException)
}
def supportsPasswordComparisonAuthenticationWithHashAttribute() {
xml.'ldap-server'()
xml.'authentication-manager'{
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
'password-compare'('password-attribute': 'uid', hash: 'plaintext')
}
}
createAppContext('')
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
when:
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"))
then:
auth != null
notThrown(AuthenticationException)
}
def supportsPasswordComparisonAuthenticationWithPasswordEncoder() {
xml.'ldap-server'()
xml.'authentication-manager'{
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
'password-compare'('password-attribute': 'uid') {
'password-encoder'(hash: 'plaintext')
}
}
}
createAppContext('')
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
when:
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"))
then:
auth != null
notThrown(AuthenticationException)
}
def inetOrgContextMapperIsSupported() {
xml.'ldap-server'(url: 'ldap://127.0.0.1:343/dc=springframework,dc=org')
xml.'authentication-manager'{
'ldap-authentication-provider'('user-details-class' :'inetOrgPerson')
}
createAppContext('')
expect:
appContext.getBean(BeanIds.AUTHENTICATION_MANAGER).providers[0].userDetailsContextMapper instanceof InetOrgPersonContextMapper
}
def ldapAuthenticationProviderWorksWithPlaceholders() {
System.setProperty('udp','people')
System.setProperty('gsf','member')
xml.'ldap-server'()
xml.'authentication-manager'{
'ldap-authentication-provider'('user-dn-pattern':'uid={0},ou=${udp}','group-search-filter':'${gsf}={0}')
}
bean(PropertyPlaceholderConfigurer.class.name, PropertyPlaceholderConfigurer.class)
createAppContext('')
def provider = this.appContext.getBean(BeanIds.AUTHENTICATION_MANAGER).providers[0]
expect:
[new MessageFormat("uid={0},ou=people")] == FieldUtils.getFieldValue(provider,"authenticator.userDnFormat")
"member={0}" == FieldUtils.getFieldValue(provider, "authoritiesPopulator.groupSearchFilter")
}
}
@@ -1,19 +0,0 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.springframework.security" level="${sec.log.level}:-WARN"/>
<logger name="org.apache.directory" level="ERROR"/>
<logger name="JdbmTable" level="INFO"/>
<logger name="JdbmIndex" level="INFO"/>
<logger name="org.apache.mina" level="WARN"/>
<root level="${root.level}:-WARN">
<appender-ref ref="STDOUT" />
</root>
</configuration>
@@ -6,7 +6,6 @@ package org.springframework.security.config;
* These are intended for internal use.
*
* @author Ben Alex
* @author Luke Taylor
*/
public abstract class BeanIds {
private static final String PREFIX = "org.springframework.security.";
@@ -20,16 +19,12 @@ public abstract class BeanIds {
public static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = PREFIX + "contextSettingPostProcessor";
public static final String USER_DETAILS_SERVICE = PREFIX + "userDetailsService";
public static final String USER_DETAILS_SERVICE_FACTORY = PREFIX + "userDetailsServiceFactory";
public static final String METHOD_ACCESS_MANAGER = PREFIX + "defaultMethodAccessManager";
public static final String FILTER_CHAIN_PROXY = PREFIX + "filterChainProxy";
public static final String FILTER_CHAINS = PREFIX + "filterChains";
public static final String METHOD_SECURITY_METADATA_SOURCE_ADVISOR = PREFIX + "methodSecurityMetadataSourceAdvisor";
public static final String EMBEDDED_APACHE_DS = PREFIX + "apacheDirectoryServerContainer";
public static final String CONTEXT_SOURCE = PREFIX + "securityContextSource";
public static final String DEBUG_FILTER = PREFIX + "debugFilter";
}
@@ -1,20 +0,0 @@
package org.springframework.security.config;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.config.debug.SecurityDebugBeanFactoryPostProcessor;
import org.w3c.dom.Element;
/**
* @author Luke Taylor
*/
public class DebugBeanDefinitionParser implements BeanDefinitionParser {
public BeanDefinition parse(Element element, ParserContext parserContext) {
RootBeanDefinition debugPP = new RootBeanDefinition(SecurityDebugBeanFactoryPostProcessor.class);
parserContext.getReaderContext().registerWithGeneratedName(debugPP);
return null;
}
}
@@ -1,7 +1,7 @@
package org.springframework.security.config;
/**
* Contains all the element names used by Spring Security 3 namespace support.
* Contains all the element names used by Spring Security 2 namespace support.
*
* @author Ben Alex
*/
@@ -46,12 +46,9 @@ public abstract class Elements {
public static final String CUSTOM_FILTER = "custom-filter";
public static final String REQUEST_CACHE = "request-cache";
public static final String X509 = "x509";
public static final String JEE = "jee";
public static final String FILTER_SECURITY_METADATA_SOURCE = "filter-security-metadata-source";
public static final String METHOD_SECURITY_METADATA_SOURCE = "method-security-metadata-source";
@Deprecated
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
public static final String DEBUG = "debug";
public static final String HTTP_FIREWALL = "http-firewall";
}
@@ -1,5 +1,8 @@
package org.springframework.security.config;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -12,7 +15,6 @@ import org.springframework.security.config.authentication.AuthenticationManagerB
import org.springframework.security.config.authentication.AuthenticationProviderBeanDefinitionParser;
import org.springframework.security.config.authentication.JdbcUserServiceBeanDefinitionParser;
import org.springframework.security.config.authentication.UserServiceBeanDefinitionParser;
import org.springframework.security.config.http.FilterChainBeanDefinitionParser;
import org.springframework.security.config.http.FilterChainMapBeanDefinitionDecorator;
import org.springframework.security.config.http.FilterInvocationSecurityMetadataSourceParser;
import org.springframework.security.config.http.HttpFirewallBeanDefinitionParser;
@@ -22,14 +24,11 @@ import org.springframework.security.config.ldap.LdapServerBeanDefinitionParser;
import org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser;
import org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParser;
import org.springframework.security.config.method.InterceptMethodsBeanDefinitionDecorator;
import org.springframework.security.config.method.MethodSecurityMetadataSourceBeanDefinitionParser;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.util.ClassUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import java.util.*;
/**
* Parses elements from the "security" namespace (http://www.springframework.org/schema/security).
*
@@ -39,6 +38,7 @@ import java.util.*;
*/
public final class SecurityNamespaceHandler implements NamespaceHandler {
private final Log logger = LogFactory.getLog(getClass());
private final Map<String, BeanDefinitionParser> parsers = new HashMap<String, BeanDefinitionParser>();
private final BeanDefinitionDecorator interceptMethodsBDD = new InterceptMethodsBeanDefinitionDecorator();
private BeanDefinitionDecorator filterChainMapBDD;
@@ -63,8 +63,9 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
public BeanDefinition parse(Element element, ParserContext pc) {
if (!namespaceMatchesVersion(element)) {
pc.getReaderContext().fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd schema " +
"with Spring Security 3.1. Please update your schema declarations to the 3.1 schema.", element);
pc.getReaderContext().fatal("You must use a 3.0 schema with Spring Security 3.0." +
"(2.0 or 3.1 versions are not valid)" +
" Please update your schema declarations to the 3.0.3 schema (spring-security-3.0.3.xsd).", element);
}
String name = pc.getDelegate().getLocalName(element);
BeanDefinitionParser parser = parsers.get(name);
@@ -75,20 +76,18 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
}
if (parser == null) {
if (Elements.HTTP.equals(name) || Elements.FILTER_SECURITY_METADATA_SOURCE.equals(name) ||
Elements.FILTER_CHAIN_MAP.equals(name) || Elements.FILTER_CHAIN.equals(name)) {
if (Elements.HTTP.equals(name) || Elements.FILTER_SECURITY_METADATA_SOURCE.equals(name)) {
reportMissingWebClasses(name, pc, element);
} else {
reportUnsupportedNodeType(name, pc, element);
}
return null;
}
return parser.parse(element, pc);
}
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext pc) {
BeanDefinitionDecorator decorator = null;
String name = pc.getDelegate().getLocalName(node);
// We only handle elements
@@ -108,7 +107,9 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
}
}
reportUnsupportedNodeType(name, pc, node);
if (decorator == null) {
reportUnsupportedNodeType(name, pc, node);
}
return null;
}
@@ -119,8 +120,8 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
}
private void reportMissingWebClasses(String nodeName, ParserContext pc, Node node) {
pc.getReaderContext().fatal("The classes from the spring-security-web jar " +
"(or one of its dependencies) are not available. You need these to use <" + nodeName + ">", node);
pc.getReaderContext().fatal("spring-security-web classes are not available. " +
"You need these to use <" + Elements.FILTER_CHAIN_MAP + ">", node);
}
public void init() {
@@ -138,30 +139,21 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
parsers.put(Elements.AUTHENTICATION_PROVIDER, new AuthenticationProviderBeanDefinitionParser());
parsers.put(Elements.GLOBAL_METHOD_SECURITY, new GlobalMethodSecurityBeanDefinitionParser());
parsers.put(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser());
parsers.put(Elements.METHOD_SECURITY_METADATA_SOURCE, new MethodSecurityMetadataSourceBeanDefinitionParser());
// Only load the web-namespace parsers if the web classes are available
try {
ClassUtils.forName("org.springframework.security.web.FilterChainProxy", getClass().getClassLoader());
parsers.put(Elements.DEBUG, new DebugBeanDefinitionParser());
if (ClassUtils.isPresent("org.springframework.security.web.FilterChainProxy", getClass().getClassLoader())) {
parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
parsers.put(Elements.HTTP_FIREWALL, new HttpFirewallBeanDefinitionParser());
parsers.put(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
parsers.put(Elements.FILTER_CHAIN, new FilterChainBeanDefinitionParser());
filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
} catch(Throwable t) {
logger.error("Failed to load required web classes", t);
}
}
/**
* Check that the schema location declared in the source file being parsed matches the Spring Security version.
* The old 2.0 schema is not compatible with the 3.1 parser, so it is an error to explicitly use
* 2.0.
* <p>
* There are also differences between 3.0 and 3.1 which are sufficient that we report using 3.0 as an error too.
* It might be an error to declare spring-security.xsd as an alias, but you are only going to find that out
* The old 2.0 schema is not compatible with the new 3.0 parser, so it is an error to explicitly use
* 3.0. It might be an error to declare spring-security.xsd as an alias, but you are only going to find that out
* when one of the sub parsers breaks.
*
* @param element the element that is to be parsed next
@@ -173,8 +165,8 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
private boolean matchesVersionInternal(Element element) {
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
return schemaLocation.matches("(?m).*spring-security-3\\.1.*.xsd.*")
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
return schemaLocation.matches("(?m).*spring-security-3\\.0.*xsd.*")
|| schemaLocation.matches("(?m).*spring-security\\.xsd.*")
|| !schemaLocation.matches("(?m).*spring-security.*");
}
@@ -38,14 +38,8 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
private static final String ATT_ERASE_CREDENTIALS = "erase-credentials";
public BeanDefinition parse(Element element, ParserContext pc) {
String id = element.getAttribute("id");
if (!StringUtils.hasText(id)) {
if (pc.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER)) {
pc.getReaderContext().warning("Overriding globally registered AuthenticationManager", pc.extractSource(element));
}
id = BeanIds.AUTHENTICATION_MANAGER;
}
Assert.state(!pc.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER),
"AuthenticationManager has already been registered!");
pc.pushContainingComponent(new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element)));
BeanDefinitionBuilder providerManagerBldr = BeanDefinitionBuilder.rootBeanDefinition(ProviderManager.class);
@@ -63,24 +57,13 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
if (node instanceof Element) {
Element providerElt = (Element)node;
if (StringUtils.hasText(providerElt.getAttribute(ATT_REF))) {
if (providerElt.getAttributes().getLength() > 1) {
pc.getReaderContext().error("authentication-provider element cannot be used with other attributes " +
"when using 'ref' attribute", pc.extractSource(element));
}
NodeList providerChildren = providerElt.getChildNodes();
for (int j = 0; j < providerChildren.getLength(); j++) {
if (providerChildren.item(j) instanceof Element) {
pc.getReaderContext().error("authentication-provider element cannot have child elements when used " +
"with 'ref' attribute", pc.extractSource(element));
}
}
providers.add(new RuntimeBeanReference(providerElt.getAttribute(ATT_REF)));
} else {
BeanDefinition provider = resolver.resolve(providerElt.getNamespaceURI()).parse(providerElt, pc);
Assert.notNull(provider, "Parser for " + providerElt.getNodeName() + " returned a null bean definition");
String providerId = pc.getReaderContext().generateBeanName(provider);
pc.registerBeanComponent(new BeanComponentDefinition(provider, providerId));
providers.add(new RuntimeBeanReference(providerId));
String id = pc.getReaderContext().generateBeanName(provider);
pc.registerBeanComponent(new BeanComponentDefinition(provider, id));
providers.add(new RuntimeBeanReference(id));
}
}
}
@@ -89,23 +72,24 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
providers.add(new RootBeanDefinition(NullAuthenticationProvider.class));
}
providerManagerBldr.addConstructorArgValue(providers);
providerManagerBldr.addPropertyValue("providers", providers);
if ("false".equals(element.getAttribute(ATT_ERASE_CREDENTIALS))) {
providerManagerBldr.addPropertyValue("eraseCredentialsAfterAuthentication", false);
if ("true".equals(element.getAttribute(ATT_ERASE_CREDENTIALS))) {
providerManagerBldr.addPropertyValue("eraseCredentialsAfterAuthentication", true);
}
// Add the default event publisher
BeanDefinition publisher = new RootBeanDefinition(DefaultAuthenticationEventPublisher.class);
String pubId = pc.getReaderContext().generateBeanName(publisher);
pc.registerBeanComponent(new BeanComponentDefinition(publisher, pubId));
providerManagerBldr.addPropertyReference("authenticationEventPublisher", pubId);
String id = pc.getReaderContext().generateBeanName(publisher);
pc.registerBeanComponent(new BeanComponentDefinition(publisher, id));
providerManagerBldr.addPropertyReference("authenticationEventPublisher", id);
pc.registerBeanComponent(new BeanComponentDefinition(providerManagerBldr.getBeanDefinition(), id));
pc.registerBeanComponent(
new BeanComponentDefinition(providerManagerBldr.getBeanDefinition(), BeanIds.AUTHENTICATION_MANAGER));
if (StringUtils.hasText(alias)) {
pc.getRegistry().registerAlias(id, alias);
pc.getReaderContext().fireAliasRegistered(id, alias, pc.extractSource(element));
pc.getRegistry().registerAlias(BeanIds.AUTHENTICATION_MANAGER, alias);
pc.getReaderContext().fireAliasRegistered(BeanIds.AUTHENTICATION_MANAGER, alias, pc.extractSource(element));
}
pc.popAndRegisterContainingComponent();
@@ -133,7 +117,7 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
return null;
}
public boolean supports(Class<?> authentication) {
public boolean supports(Class<? extends Object> authentication) {
return false;
}
}
@@ -19,9 +19,8 @@ import org.springframework.security.config.BeanIds;
*/
public class AuthenticationManagerFactoryBean implements FactoryBean<AuthenticationManager>, BeanFactoryAware {
private BeanFactory bf;
public static final String MISSING_BEAN_ERROR_MESSAGE = "Did you forget to add a gobal <authentication-manager> element " +
"to your configuration (with child <authentication-provider> elements)? Alternatively you can use the " +
"authentication-manager-ref attribute on your <http> and <global-method-security> elements.";
public static final String MISSING_BEAN_ERROR_MESSAGE = "Did you forget to add an <authentication-manager> element " +
"to your configuration (with child <authentication-provider> elements) ?";
public AuthenticationManager getObject() throws Exception {
try {
@@ -18,7 +18,7 @@ import org.w3c.dom.Element;
* @author Luke Taylor
*/
public class AuthenticationProviderBeanDefinitionParser implements BeanDefinitionParser {
private static final String ATT_USER_DETAILS_REF = "user-service-ref";
private static String ATT_USER_DETAILS_REF = "user-service-ref";
public BeanDefinition parse(Element element, ParserContext pc) {
RootBeanDefinition authProvider = new RootBeanDefinition(DaoAuthenticationProvider.class);
@@ -13,7 +13,7 @@ import org.springframework.util.Assert;
*/
public class CachingUserDetailsService implements UserDetailsService {
private UserCache userCache = new NullUserCache();
private final UserDetailsService delegate;
private UserDetailsService delegate;
CachingUserDetailsService(UserDetailsService delegate) {
this.delegate = delegate;
@@ -55,7 +55,7 @@ public class PasswordEncoderParser {
ENCODER_CLASSES.put(OPT_HASH_LDAP_SSHA, LdapShaPasswordEncoder.class);
}
private static final Log logger = LogFactory.getLog(PasswordEncoderParser.class);
private static Log logger = LogFactory.getLog(PasswordEncoderParser.class);
private BeanMetadataElement passwordEncoder;
private BeanMetadataElement saltSource;
@@ -69,7 +69,7 @@ public class PasswordEncoderParser {
boolean useBase64 = false;
if (StringUtils.hasText(element.getAttribute(ATT_BASE_64))) {
useBase64 = Boolean.valueOf(element.getAttribute(ATT_BASE_64)).booleanValue();
useBase64 = new Boolean(element.getAttribute(ATT_BASE_64)).booleanValue();
}
String ref = element.getAttribute(ATT_REF);
@@ -93,7 +93,7 @@ public class PasswordEncoderParser {
BeanDefinitionBuilder beanBldr = BeanDefinitionBuilder.rootBeanDefinition(beanClass);
if (OPT_HASH_SHA256.equals(hash)) {
beanBldr.addConstructorArgValue(Integer.valueOf(256));
beanBldr.addConstructorArgValue(new Integer(256));
}
if (useBase64) {
@@ -9,12 +9,12 @@ import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.core.userdetails.memory.UserMap;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
@@ -24,6 +24,7 @@ import org.w3c.dom.Element;
* @author Luke Taylor
* @author Ben Alex
*/
@SuppressWarnings("deprecation")
public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser {
static final String ATT_PASSWORD = "password";
@@ -37,7 +38,7 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
private SecureRandom random;
protected String getBeanClassName(Element element) {
return InMemoryUserDetailsManager.class.getName();
return "org.springframework.security.core.userdetails.memory.InMemoryDaoImpl";
}
@SuppressWarnings("unchecked")
@@ -53,20 +54,21 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
BeanDefinition bd = new RootBeanDefinition(PropertiesFactoryBean.class);
bd.getPropertyValues().addPropertyValue("location", userProperties);
builder.addConstructorArgValue(bd);
builder.addPropertyValue("userProperties", bd);
return;
}
if (CollectionUtils.isEmpty(userElts)) {
if(CollectionUtils.isEmpty(userElts)) {
throw new BeanDefinitionStoreException("You must supply user definitions, either with <" + ELT_USER + "> child elements or a " +
"properties file (using the '" + ATT_PROPERTIES + "' attribute)" );
}
ManagedList<BeanDefinition> users = new ManagedList<BeanDefinition>();
BeanDefinition userMap = new RootBeanDefinition(UserMap.class);
ManagedMap<String, BeanDefinition> users = new ManagedMap<String, BeanDefinition>();
for (Object elt : userElts) {
Element userElt = (Element) elt;
for (Iterator i = userElts.iterator(); i.hasNext();) {
Element userElt = (Element) i.next();
String userName = userElt.getAttribute(ATT_NAME);
String password = userElt.getAttribute(ATT_PASSWORD);
@@ -89,10 +91,12 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
user.addConstructorArgValue(!locked);
user.addConstructorArgValue(authorities.getBeanDefinition());
users.add(user.getBeanDefinition());
users.put(userName.toLowerCase(), user.getBeanDefinition());
}
builder.addConstructorArgValue(users);
userMap.getPropertyValues().addPropertyValue("users", users);
builder.addPropertyValue("userMap", userMap);
}
private String generateRandomPassword() {
@@ -1,105 +0,0 @@
package org.springframework.security.config.debug;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.*;
/**
* Spring Security debugging filter.
* <p>
* Logs information (such as session creation) to help the user understand how requests are being handled
* by Spring Security and provide them with other relevant information (such as when sessions are being created).
*
*
* @author Luke Taylor
* @since 3.1
*/
class DebugFilter extends OncePerRequestFilter {
private final FilterChainProxy fcp;
private final Logger logger = new Logger();
public DebugFilter(FilterChainProxy fcp) {
this.fcp = fcp;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
List<Filter> filters = getFilters(request);
logger.log("Request received for '" + UrlUtils.buildRequestUrl(request) + "':\n\n" +
request + "\n\n" +
"servletPath:" + request.getServletPath() + "\n" +
"pathInfo:" + request.getPathInfo() + "\n\n" +
formatFilters(filters));
fcp.doFilter(new DebugRequestWrapper(request), response, filterChain);
}
String formatFilters(List<Filter> filters) {
StringBuilder sb = new StringBuilder();
sb.append("Security filter chain: ");
if (filters == null) {
sb.append("no match");
} else if (filters.isEmpty()) {
sb.append("[] empty (bypassed by security='none') ");
} else {
sb.append("[\n");
for (Filter f : filters) {
sb.append(" ").append(f.getClass().getSimpleName()).append("\n");
}
sb.append("]");
}
return sb.toString();
}
private List<Filter> getFilters(HttpServletRequest request) {
for (SecurityFilterChain chain : fcp.getFilterChains()) {
if (chain.matches(request)) {
return chain.getFilters();
}
}
return null;
}
}
class DebugRequestWrapper extends HttpServletRequestWrapper {
private static final Logger logger = new Logger();
public DebugRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public HttpSession getSession() {
boolean sessionExists = super.getSession(false) != null;
HttpSession session = super.getSession();
if (!sessionExists) {
logger.log("New HTTP session created: " + session.getId(), true);
}
return session;
}
@Override
public HttpSession getSession(boolean create) {
if (!create) {
return super.getSession(create);
}
return getSession();
}
}
@@ -1,41 +0,0 @@
package org.springframework.security.config.debug;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Controls output for the Spring Security debug feature.
*
* @author Luke Taylor
* @since 3.1
*/
final class Logger {
final static Log logger = LogFactory.getLog("Spring Security Debugger");
void log(String message) {
log(message, false);
}
void log(String message, boolean dumpStack) {
StringBuilder output = new StringBuilder(256);
output.append("\n\n************************************************************\n\n");
output.append(message).append("\n");
if (dumpStack) {
StringWriter os = new StringWriter();
new Exception().printStackTrace(new PrintWriter(os));
StringBuffer buffer = os.getBuffer();
// Remove the exception in case it scares people.
int start = buffer.indexOf("java.lang.Exception");
buffer.replace(start, start + 19, "");
output.append("\nCall stack: \n").append(os.toString());
}
output.append("\n\n************************************************************\n\n");
logger.info(output.toString());
}
}
@@ -1,28 +0,0 @@
package org.springframework.security.config.debug;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.security.config.BeanIds;
import org.springframework.security.web.FilterChainProxy;
/**
* @author Luke Taylor
*/
public class SecurityDebugBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Logger.logger.warn("\n\n" +
"********************************************************************\n" +
"********** Security debugging is enabled. *************\n" +
"********** This may include sensitive information. *************\n" +
"********** Do not use in a production system! *************\n" +
"********************************************************************\n\n");
if (beanFactory.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN) != null) {
FilterChainProxy fcp = beanFactory.getBean(BeanIds.FILTER_CHAIN_PROXY, FilterChainProxy.class);
beanFactory.registerSingleton(BeanIds.DEBUG_FILTER, new DebugFilter(fcp));
// Overwrite the filter chain alias
beanFactory.registerAlias(BeanIds.DEBUG_FILTER, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
}
}
}
@@ -2,6 +2,11 @@ package org.springframework.security.config.http;
import static org.springframework.security.config.http.SecurityFilters.*;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanMetadataElement;
@@ -13,36 +18,28 @@ import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.authentication.AnonymousAuthenticationProvider;
import org.springframework.security.authentication.RememberMeAuthenticationProvider;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.Elements;
import org.springframework.security.core.authority.mapping.SimpleAttributes2GrantedAuthoritiesMapper;
import org.springframework.security.core.authority.mapping.SimpleMappableAttributesRetriever;
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
import org.springframework.security.web.PortResolverImpl;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesUserDetailsService;
import org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter;
import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor;
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.Assert;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
import java.security.SecureRandom;
import java.util.*;
/**
* Handles creation of authentication mechanism filters and related beans for &lt;http&gt; parsing.
*
@@ -57,13 +54,10 @@ final class AuthenticationConfigBuilder {
static final String OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS = "org.springframework.security.openid.OpenIDAuthenticationFilter";
static final String OPEN_ID_AUTHENTICATION_PROVIDER_CLASS = "org.springframework.security.openid.OpenIDAuthenticationProvider";
private static final String OPEN_ID_CONSUMER_CLASS = "org.springframework.security.openid.OpenID4JavaConsumer";
static final String OPEN_ID_CONSUMER_CLASS = "org.springframework.security.openid.OpenID4JavaConsumer";
static final String OPEN_ID_ATTRIBUTE_CLASS = "org.springframework.security.openid.OpenIDAttribute";
private static final String OPEN_ID_ATTRIBUTE_FACTORY_CLASS = "org.springframework.security.openid.RegexBasedAxFetchListFactory";
static final String AUTHENTICATION_PROCESSING_FILTER_CLASS = "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter";
static final String ATT_AUTH_DETAILS_SOURCE_REF = "authentication-details-source-ref";
private static final String ATT_AUTO_CONFIG = "auto-config";
private static final String ATT_ACCESS_DENIED_PAGE = "access-denied-page";
@@ -72,13 +66,14 @@ final class AuthenticationConfigBuilder {
private static final String ATT_USER_SERVICE_REF = "user-service-ref";
private static final String ATT_KEY = "key";
private static final String ATT_REF = "ref";
private final Element httpElt;
private final ParserContext pc;
private Element httpElt;
private ParserContext pc;
private final boolean autoConfig;
private final boolean allowSessionCreation;
private final String portMapperName;
private RootBeanDefinition anonymousFilter;
private BeanReference anonymousProviderRef;
@@ -86,47 +81,44 @@ final class AuthenticationConfigBuilder {
private String rememberMeServicesId;
private BeanReference rememberMeProviderRef;
private BeanDefinition basicFilter;
private RuntimeBeanReference basicEntryPoint;
private BeanReference basicEntryPoint;
private RootBeanDefinition formFilter;
private BeanDefinition formEntryPoint;
private RootBeanDefinition openIDFilter;
private BeanDefinition openIDEntryPoint;
private BeanReference openIDProviderRef;
private String openIDProviderId;
private String formFilterId = null;
private String openIDFilterId = null;
private BeanDefinition x509Filter;
private BeanDefinition x509EntryPoint;
private BeanReference x509ProviderRef;
private BeanDefinition jeeFilter;
private BeanReference jeeProviderRef;
private RootBeanDefinition preAuthEntryPoint;
private String x509ProviderId;
private BeanDefinition logoutFilter;
private BeanDefinition loginPageGenerationFilter;
private BeanDefinition etf;
private final BeanReference requestCache;
private BeanReference requestCache;
public AuthenticationConfigBuilder(Element element, ParserContext pc, SessionCreationPolicy sessionPolicy,
BeanReference requestCache, BeanReference authenticationManager, BeanReference sessionStrategy) {
final SecureRandom random;
public AuthenticationConfigBuilder(Element element, ParserContext pc, boolean allowSessionCreation,
String portMapperName) {
this.httpElt = element;
this.pc = pc;
this.requestCache = requestCache;
this.portMapperName = portMapperName;
autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
this.allowSessionCreation = sessionPolicy != SessionCreationPolicy.never
&& sessionPolicy != SessionCreationPolicy.stateless;
createAnonymousFilter();
createRememberMeFilter(authenticationManager);
createBasicFilter(authenticationManager);
createFormLoginFilter(sessionStrategy, authenticationManager);
createOpenIDLoginFilter(sessionStrategy, authenticationManager);
createX509Filter(authenticationManager);
createJeeFilter(authenticationManager);
createLogoutFilter();
createLoginPageFilterIfNeeded();
createUserDetailsServiceFactory();
createExceptionTranslationFilter();
this.allowSessionCreation = allowSessionCreation;
try {
random = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
// Shouldn't happen...
throw new RuntimeException("Failed find SHA1PRNG algorithm!");
}
}
void createRememberMeFilter(BeanReference authenticationManager) {
final String ATT_KEY = "key";
final String DEF_KEY = "SpringSecured";
// Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation.
Element rememberMeElt = DomUtils.getChildElementByTagName(httpElt, Elements.REMEMBER_ME);
@@ -135,10 +127,10 @@ final class AuthenticationConfigBuilder {
String key = rememberMeElt.getAttribute(ATT_KEY);
if (!StringUtils.hasText(key)) {
key = createKey();
key = DEF_KEY;
}
rememberMeFilter = new RememberMeBeanDefinitionParser(key).parse(rememberMeElt, pc);
rememberMeFilter = (RootBeanDefinition) new RememberMeBeanDefinitionParser(key).parse(rememberMeElt, pc);
rememberMeFilter.getPropertyValues().addPropertyValue("authenticationManager", authenticationManager);
rememberMeServicesId = ((RuntimeBeanReference) rememberMeFilter.getPropertyValues().getPropertyValue("rememberMeServices").getValue()).getBeanName();
createRememberMeProvider(key);
@@ -160,7 +152,6 @@ final class AuthenticationConfigBuilder {
void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
Element formLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.FORM_LOGIN);
RootBeanDefinition formFilter = null;
if (formLoginElt != null || autoConfig) {
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
@@ -175,6 +166,7 @@ final class AuthenticationConfigBuilder {
formFilter.getPropertyValues().addPropertyValue("allowSessionCreation", allowSessionCreation);
formFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
// Id is required by login page filter
formFilterId = pc.getReaderContext().generateBeanName(formFilter);
pc.registerBeanComponent(new BeanComponentDefinition(formFilter, formFilterId));
@@ -184,7 +176,6 @@ final class AuthenticationConfigBuilder {
void createOpenIDLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
Element openIDLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.OPENID_LOGIN);
RootBeanDefinition openIDFilter = null;
if (openIDLoginElt != null) {
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
@@ -194,31 +185,30 @@ final class AuthenticationConfigBuilder {
openIDFilter = parser.getFilterBean();
openIDEntryPoint = parser.getEntryPointBean();
List<Element> attrExElts = DomUtils.getChildElementsByTagName(openIDLoginElt, Elements.OPENID_ATTRIBUTE_EXCHANGE);
Element attrExElt = DomUtils.getChildElementByTagName(openIDLoginElt, Elements.OPENID_ATTRIBUTE_EXCHANGE);
if (!attrExElts.isEmpty()) {
if (attrExElt != null) {
// Set up the consumer with the required attribute list
BeanDefinitionBuilder consumerBldr = BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_CONSUMER_CLASS);
BeanDefinitionBuilder axFactory = BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_ATTRIBUTE_FACTORY_CLASS);
ManagedMap<String, ManagedList<BeanDefinition>> axMap = new ManagedMap<String, ManagedList<BeanDefinition>>();
for (Element attrExElt : attrExElts) {
String identifierMatch = attrExElt.getAttribute("identifier-match");
if (!StringUtils.hasText(identifierMatch)) {
if (attrExElts.size() > 1) {
pc.getReaderContext().error("You must supply an identifier-match attribute if using more" +
" than one " + Elements.OPENID_ATTRIBUTE_EXCHANGE + " element", attrExElt);
}
// Match anything
identifierMatch = ".*";
ManagedList<BeanDefinition> attributes = new ManagedList<BeanDefinition> ();
for (Element attElt : DomUtils.getChildElementsByTagName(attrExElt, Elements.OPENID_ATTRIBUTE)) {
String name = attElt.getAttribute("name");
String type = attElt.getAttribute("type");
String required = attElt.getAttribute("required");
String count = attElt.getAttribute("count");
BeanDefinitionBuilder attrBldr = BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_ATTRIBUTE_CLASS);
attrBldr.addConstructorArgValue(name);
attrBldr.addConstructorArgValue(type);
if (StringUtils.hasLength(required)) {
attrBldr.addPropertyValue("required", Boolean.valueOf(required));
}
axMap.put(identifierMatch, parseOpenIDAttributes(attrExElt));
if (StringUtils.hasLength(count)) {
attrBldr.addPropertyValue("count", Integer.parseInt(count));
}
attributes.add(attrBldr.getBeanDefinition());
}
axFactory.addConstructorArgValue(axMap);
consumerBldr.addConstructorArgValue(axFactory.getBeanDefinition());
consumerBldr.addConstructorArgValue(attributes);
openIDFilter.getPropertyValues().addPropertyValue("consumer", consumerBldr.getBeanDefinition());
}
}
@@ -235,43 +225,20 @@ final class AuthenticationConfigBuilder {
}
}
private ManagedList<BeanDefinition> parseOpenIDAttributes(Element attrExElt) {
ManagedList<BeanDefinition> attributes = new ManagedList<BeanDefinition> ();
for (Element attElt : DomUtils.getChildElementsByTagName(attrExElt, Elements.OPENID_ATTRIBUTE)) {
String name = attElt.getAttribute("name");
String type = attElt.getAttribute("type");
String required = attElt.getAttribute("required");
String count = attElt.getAttribute("count");
BeanDefinitionBuilder attrBldr = BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_ATTRIBUTE_CLASS);
attrBldr.addConstructorArgValue(name);
attrBldr.addConstructorArgValue(type);
if (StringUtils.hasLength(required)) {
attrBldr.addPropertyValue("required", Boolean.valueOf(required));
}
if (StringUtils.hasLength(count)) {
attrBldr.addPropertyValue("count", Integer.parseInt(count));
}
attributes.add(attrBldr.getBeanDefinition());
}
return attributes;
}
private void createOpenIDProvider() {
Element openIDLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.OPENID_LOGIN);
BeanDefinitionBuilder openIDProviderBuilder =
BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_AUTHENTICATION_PROVIDER_CLASS);
RootBeanDefinition uds = new RootBeanDefinition();
uds.setFactoryBeanName(BeanIds.USER_DETAILS_SERVICE_FACTORY);
uds.setFactoryMethodName("authenticationUserDetailsService");
uds.getConstructorArgumentValues().addGenericArgumentValue(openIDLoginElt.getAttribute(ATT_USER_SERVICE_REF));
String userService = openIDLoginElt.getAttribute(ATT_USER_SERVICE_REF);
openIDProviderBuilder.addPropertyValue("authenticationUserDetailsService", uds);
if (StringUtils.hasText(userService)) {
openIDProviderBuilder.addPropertyReference("userDetailsService", userService);
}
BeanDefinition openIDProvider = openIDProviderBuilder.getBeanDefinition();
openIDProviderRef = new RuntimeBeanReference(pc.getReaderContext().registerWithGeneratedName(openIDProvider));
openIDProviderId = pc.getReaderContext().registerWithGeneratedName(openIDProvider);
openIDProviderRef = new RuntimeBeanReference(openIDProviderId);
}
private void injectRememberMeServicesRef(RootBeanDefinition bean, String rememberMeServicesId) {
@@ -283,46 +250,41 @@ final class AuthenticationConfigBuilder {
void createBasicFilter(BeanReference authManager) {
Element basicAuthElt = DomUtils.getChildElementByTagName(httpElt, Elements.BASIC_AUTH);
if (basicAuthElt == null && !autoConfig) {
// No basic auth, do nothing
return;
}
String realm = httpElt.getAttribute(ATT_REALM);
if (!StringUtils.hasText(realm)) {
realm = DEF_REALM;
}
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicAuthenticationFilter.class);
RootBeanDefinition filter = null;
String entryPointId;
if (basicAuthElt != null || autoConfig) {
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicAuthenticationFilter.class);
if (basicAuthElt != null) {
if (StringUtils.hasText(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF))) {
String entryPointId;
if (basicAuthElt != null && StringUtils.hasText(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF))) {
basicEntryPoint = new RuntimeBeanReference(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF));
} else {
RootBeanDefinition entryPoint = new RootBeanDefinition(BasicAuthenticationEntryPoint.class);
entryPoint.setSource(pc.extractSource(httpElt));
entryPoint.getPropertyValues().addPropertyValue("realmName", realm);
entryPointId = pc.getReaderContext().generateBeanName(entryPoint);
pc.registerBeanComponent(new BeanComponentDefinition(entryPoint, entryPointId));
basicEntryPoint = new RuntimeBeanReference(entryPointId);
}
injectAuthenticationDetailsSource(basicAuthElt, filterBuilder);
filterBuilder.addPropertyValue("authenticationManager", authManager);
filterBuilder.addPropertyValue("authenticationEntryPoint", basicEntryPoint);
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
}
if (basicEntryPoint == null) {
RootBeanDefinition entryPoint = new RootBeanDefinition(BasicAuthenticationEntryPoint.class);
entryPoint.setSource(pc.extractSource(httpElt));
entryPoint.getPropertyValues().addPropertyValue("realmName", realm);
entryPointId = pc.getReaderContext().generateBeanName(entryPoint);
pc.registerBeanComponent(new BeanComponentDefinition(entryPoint, entryPointId));
basicEntryPoint = new RuntimeBeanReference(entryPointId);
}
filterBuilder.addPropertyValue("authenticationManager", authManager);
filterBuilder.addPropertyValue("authenticationEntryPoint", basicEntryPoint);
basicFilter = filterBuilder.getBeanDefinition();
basicFilter = filter;
}
void createX509Filter(BeanReference authManager) {
Element x509Elt = DomUtils.getChildElementByTagName(httpElt, Elements.X509);
RootBeanDefinition filter = null;
RootBeanDefinition entryPoint = null;
if (x509Elt != null) {
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(X509AuthenticationFilter.class);
@@ -337,102 +299,37 @@ final class AuthenticationConfigBuilder {
filterBuilder.addPropertyValue("principalExtractor", extractor.getBeanDefinition());
}
injectAuthenticationDetailsSource(x509Elt, filterBuilder);
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
createPrauthEntryPoint(x509Elt);
entryPoint = new RootBeanDefinition(Http403ForbiddenEntryPoint.class);
entryPoint.setSource(pc.extractSource(x509Elt));
createX509Provider();
}
x509Filter = filter;
}
private void injectAuthenticationDetailsSource(Element elt, BeanDefinitionBuilder filterBuilder) {
String authDetailsSourceRef = elt.getAttribute(AuthenticationConfigBuilder.ATT_AUTH_DETAILS_SOURCE_REF);
if (StringUtils.hasText(authDetailsSourceRef)) {
filterBuilder.addPropertyReference("authenticationDetailsSource", authDetailsSourceRef);
}
x509EntryPoint = entryPoint;
}
private void createX509Provider() {
Element x509Elt = DomUtils.getChildElementByTagName(httpElt, Elements.X509);
BeanDefinition provider = new RootBeanDefinition(PreAuthenticatedAuthenticationProvider.class);
RootBeanDefinition uds = new RootBeanDefinition();
uds.setFactoryBeanName(BeanIds.USER_DETAILS_SERVICE_FACTORY);
uds.setFactoryMethodName("authenticationUserDetailsService");
uds.getConstructorArgumentValues().addGenericArgumentValue(x509Elt.getAttribute(ATT_USER_SERVICE_REF));
String userServiceRef = x509Elt.getAttribute(ATT_USER_SERVICE_REF);
provider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService", uds);
x509ProviderRef = new RuntimeBeanReference(pc.getReaderContext().registerWithGeneratedName(provider));
}
private void createPrauthEntryPoint(Element source) {
if (preAuthEntryPoint == null) {
preAuthEntryPoint = new RootBeanDefinition(Http403ForbiddenEntryPoint.class);
preAuthEntryPoint.setSource(pc.extractSource(source));
}
}
void createJeeFilter(BeanReference authManager) {
final String ATT_MAPPABLE_ROLES = "mappable-roles";
Element jeeElt = DomUtils.getChildElementByTagName(httpElt, Elements.JEE);
RootBeanDefinition filter = null;
if (jeeElt != null) {
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(J2eePreAuthenticatedProcessingFilter.class);
filterBuilder.getRawBeanDefinition().setSource(pc.extractSource(jeeElt));
filterBuilder.addPropertyValue("authenticationManager", authManager);
BeanDefinitionBuilder adsBldr = BeanDefinitionBuilder.rootBeanDefinition(J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource.class);
adsBldr.addPropertyValue("userRoles2GrantedAuthoritiesMapper", new RootBeanDefinition(SimpleAttributes2GrantedAuthoritiesMapper.class));
String roles = jeeElt.getAttribute(ATT_MAPPABLE_ROLES);
Assert.state(StringUtils.hasText(roles));
BeanDefinitionBuilder rolesBuilder = BeanDefinitionBuilder.rootBeanDefinition(StringUtils.class);
rolesBuilder.addConstructorArgValue(roles);
rolesBuilder.setFactoryMethod("commaDelimitedListToSet");
RootBeanDefinition mappableRolesRetriever = new RootBeanDefinition(SimpleMappableAttributesRetriever.class);
mappableRolesRetriever.getPropertyValues().addPropertyValue("mappableAttributes", rolesBuilder.getBeanDefinition());
adsBldr.addPropertyValue("mappableRolesRetriever", mappableRolesRetriever);
filterBuilder.addPropertyValue("authenticationDetailsSource", adsBldr.getBeanDefinition());
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
createPrauthEntryPoint(jeeElt);
createJeeProvider();
if (StringUtils.hasText(userServiceRef)) {
RootBeanDefinition preAuthUserService = new RootBeanDefinition(UserDetailsByNameServiceWrapper.class);
preAuthUserService.setSource(pc.extractSource(x509Elt));
preAuthUserService.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(userServiceRef));
provider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService", preAuthUserService);
}
jeeFilter = filter;
x509ProviderId = pc.getReaderContext().registerWithGeneratedName(provider);
x509ProviderRef = new RuntimeBeanReference(x509ProviderId);
}
private void createJeeProvider() {
Element jeeElt = DomUtils.getChildElementByTagName(httpElt, Elements.JEE);
BeanDefinition provider = new RootBeanDefinition(PreAuthenticatedAuthenticationProvider.class);
RootBeanDefinition uds;
if (StringUtils.hasText(jeeElt.getAttribute(ATT_USER_SERVICE_REF))) {
uds = new RootBeanDefinition();
uds.setFactoryBeanName(BeanIds.USER_DETAILS_SERVICE_FACTORY);
uds.setFactoryMethodName("authenticationUserDetailsService");
uds.getConstructorArgumentValues().addGenericArgumentValue(jeeElt.getAttribute(ATT_USER_SERVICE_REF));
} else {
uds = new RootBeanDefinition(PreAuthenticatedGrantedAuthoritiesUserDetailsService.class);
}
provider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService", uds);
jeeProviderRef = new RuntimeBeanReference(pc.getReaderContext().registerWithGeneratedName(provider));
}
void createLoginPageFilterIfNeeded() {
boolean needLoginPage = formFilterId != null || openIDFilterId != null;
boolean needLoginPage = formFilter != null || openIDFilter != null;
String formLoginPage = getLoginFormUrl(formEntryPoint);
String openIDLoginPage = getLoginFormUrl(openIDEntryPoint);
@@ -443,11 +340,11 @@ final class AuthenticationConfigBuilder {
BeanDefinitionBuilder loginPageFilter =
BeanDefinitionBuilder.rootBeanDefinition(DefaultLoginPageGeneratingFilter.class);
if (formFilterId != null) {
if (formFilter != null) {
loginPageFilter.addConstructorArgReference(formFilterId);
}
if (openIDFilterId != null) {
if (openIDFilter != null) {
loginPageFilter.addConstructorArgReference(openIDFilterId);
}
@@ -477,7 +374,7 @@ final class AuthenticationConfigBuilder {
if (anonymousElt != null) {
grantedAuthority = anonymousElt.getAttribute("granted-authority");
username = anonymousElt.getAttribute("username");
key = anonymousElt.getAttribute(ATT_KEY);
key = anonymousElt.getAttribute("key");
source = pc.extractSource(anonymousElt);
}
@@ -491,7 +388,7 @@ final class AuthenticationConfigBuilder {
if (!StringUtils.hasText(key)) {
// Generate a random key for the Anonymous provider
key = createKey();
key = Long.toString(random.nextLong());
}
anonymousFilter = new RootBeanDefinition(AnonymousAuthenticationFilter.class);
@@ -511,11 +408,6 @@ final class AuthenticationConfigBuilder {
}
private String createKey() {
SecureRandom random = new SecureRandom();
return Long.toString(random.nextLong());
}
void createExceptionTranslationFilter() {
BeanDefinitionBuilder etfBuilder = BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
etfBuilder.addPropertyValue("accessDeniedHandler", createAccessDeniedHandler(httpElt, pc));
@@ -526,6 +418,28 @@ final class AuthenticationConfigBuilder {
etf = etfBuilder.getBeanDefinition();
}
void createRequestCache() {
Element requestCacheElt = DomUtils.getChildElementByTagName(httpElt, Elements.REQUEST_CACHE);
if (requestCacheElt != null) {
requestCache = new RuntimeBeanReference(requestCacheElt.getAttribute(ATT_REF));
return;
}
BeanDefinitionBuilder requestCacheBldr = BeanDefinitionBuilder.rootBeanDefinition(HttpSessionRequestCache.class);
BeanDefinitionBuilder portResolver = BeanDefinitionBuilder.rootBeanDefinition(PortResolverImpl.class);
portResolver.addPropertyReference("portMapper", portMapperName);
requestCacheBldr.addPropertyValue("createSessionAllowed", allowSessionCreation);
requestCacheBldr.addPropertyValue("portResolver", portResolver.getBeanDefinition());
BeanDefinition bean = requestCacheBldr.getBeanDefinition();
String id = pc.getReaderContext().generateBeanName(bean);
pc.registerBeanComponent(new BeanComponentDefinition(bean, id));
this.requestCache = new RuntimeBeanReference(id);
}
private BeanMetadataElement createAccessDeniedHandler(Element element, ParserContext pc) {
String accessDeniedPage = element.getAttribute(ATT_ACCESS_DENIED_PAGE);
WebConfigUtils.validateHttpRedirect(accessDeniedPage, pc, pc.extractSource(element));
@@ -589,18 +503,18 @@ final class AuthenticationConfigBuilder {
"but not both.", pc.extractSource(openIDLoginElt));
}
if (formFilterId != null && openIDLoginPage == null) {
if (formFilter != null && openIDLoginPage == null) {
return formEntryPoint;
}
// Otherwise use OpenID if enabled
if (openIDFilterId != null) {
if (openIDFilter != null) {
return openIDEntryPoint;
}
// If X.509 or JEE have been enabled, use the preauth entry point.
if (preAuthEntryPoint != null) {
return preAuthEntryPoint;
// If X.509 has been enabled, use the preauth entry point.
if (DomUtils.getChildElementByTagName(httpElt, Elements.X509) != null) {
return x509EntryPoint;
}
pc.getReaderContext().error("No AuthenticationEntryPoint could be established. Please " +
@@ -629,14 +543,14 @@ final class AuthenticationConfigBuilder {
return (String) pv.getValue();
}
private void createUserDetailsServiceFactory() {
if (pc.getRegistry().containsBeanDefinition(BeanIds.USER_DETAILS_SERVICE_FACTORY)) {
// Multiple <http> case
return;
}
RootBeanDefinition bean = new RootBeanDefinition(UserDetailsServiceFactoryBean.class);
bean.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
pc.registerBeanComponent(new BeanComponentDefinition(bean, BeanIds.USER_DETAILS_SERVICE_FACTORY));
void createUserServiceInjector() {
BeanDefinitionBuilder userServiceInjector =
BeanDefinitionBuilder.rootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
userServiceInjector.addConstructorArgValue(x509ProviderId);
userServiceInjector.addConstructorArgValue(rememberMeServicesId);
userServiceInjector.addConstructorArgValue(openIDProviderId);
userServiceInjector.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
pc.getReaderContext().registerWithGeneratedName(userServiceInjector.getBeanDefinition());
}
List<OrderDecorator> getFilters() {
@@ -658,16 +572,12 @@ final class AuthenticationConfigBuilder {
filters.add(new OrderDecorator(x509Filter, X509_FILTER));
}
if (jeeFilter != null) {
filters.add(new OrderDecorator(jeeFilter, PRE_AUTH_FILTER));
if (formFilter != null) {
filters.add(new OrderDecorator(formFilter, FORM_LOGIN_FILTER));
}
if (formFilterId != null) {
filters.add(new OrderDecorator(new RuntimeBeanReference(formFilterId), FORM_LOGIN_FILTER));
}
if (openIDFilterId != null) {
filters.add(new OrderDecorator(new RuntimeBeanReference(openIDFilterId), OPENID_FILTER));
if (openIDFilter != null) {
filters.add(new OrderDecorator(openIDFilter, OPENID_FILTER));
}
if (loginPageGenerationFilter != null) {
@@ -702,11 +612,11 @@ final class AuthenticationConfigBuilder {
providers.add(x509ProviderRef);
}
if (jeeProviderRef != null) {
providers.add(jeeProviderRef);
}
return providers;
}
public BeanReference getRequestCache() {
return requestCache;
}
}

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