1
0
mirror of synced 2026-07-11 22:00:04 +00:00

Compare commits

...

113 Commits

Author SHA1 Message Date
Ben Alex 459b1d1cde Prepare to release 1.0.2. 2006-10-04 08:57:11 +00:00
Ben Alex bcd1c3eeef Fix URL. 2006-10-04 08:55:59 +00:00
Ben Alex 23e2338800 Prepare to release 1.0.2. 2006-10-04 08:55:13 +00:00
Ben Alex d150b1aad2 Note that JAR files are no longer signed. 2006-10-04 08:35:19 +00:00
Ben Alex 21dd050d7b SEC-348: Limit Basic automatic reauthentication scope to UsernamePasswordAuthenticationToken (specifically avoid CasAuthenticationToken). 2006-09-29 08:41:25 +00:00
Ben Alex ab7816db41 SEC-8: Removed from sandbox as development will continue via code drops in the JIRA task. 2006-09-29 08:13:33 +00:00
Ben Alex d2fb473a4e Formatting only. 2006-09-29 07:33:45 +00:00
Ben Alex 49a2de8f0f SEC-366: Initial commit. 2006-09-29 07:29:13 +00:00
Ben Alex cc03675776 SEC-340: Invalidate HttpSession on logout. 2006-09-29 06:45:40 +00:00
Scott McCrory db96650d99 SEC-319: Reverted to 1.0.1 version to delay these changes to 1.1.0, based on small breakage of backward compatability. 2006-09-23 19:48:39 +00:00
Ben Alex ef6d6cd03e SEC-347: Describe requirements for login page when using secure channels. 2006-09-23 06:20:29 +00:00
Ben Alex 2fdf96e7cf Change Ben's blog URL. 2006-09-18 02:16:31 +00:00
Carlos Sanchez 558fd5d75d Add scm info because we don't use artifactid as folder name 2006-09-17 21:06:22 +00:00
Ben Alex 0c7a342fdf Add sandbox contains ACLs. 2006-09-16 01:31:14 +00:00
Ben Alex c5aa605068 More JavaDocs as per discussion on acegisecurity-developer list 16 Sep 06. 2006-09-15 22:25:31 +00:00
Ben Alex 55b7b2129d Add Plazma. 2006-09-15 10:53:40 +00:00
Ben Alex b0056568f0 SEC-338: Serializable and serialVersionUID missing for Authentication-related objects. 2006-09-15 08:38:11 +00:00
Ben Alex 7313d5def0 SEC-324: Ensure IllegalStateException no longer occurs. 2006-09-15 07:55:57 +00:00
Ben Alex 324789d544 SEC-311: Must observe symmetry requirement of Object.equals(Object) contract. 2006-09-15 06:27:45 +00:00
Ben Alex 9e3ce85dd5 SEC-330: Make UserMap work with UserDetails, not User concrete class. 2006-09-15 03:47:17 +00:00
Ben Alex f0b259a32e SEC-349: GrantedAuthority constructor argument can be null. 2006-09-15 03:42:11 +00:00
Ben Alex 58d3f0c56f SEC-290: Correct bug with generation of SimpleMethodInvocation. 2006-09-15 03:38:36 +00:00
Ben Alex 5364db2c27 SEC-328: Avoid unnecessarily hitting backend a second time, if the cache wasn't used in first place. 2006-09-15 03:36:51 +00:00
Ben Alex 53beadb7bf SEC-290: Correct bug with generation of SimpleMethodInvocation. 2006-09-15 03:27:26 +00:00
Ben Alex 03df6a90eb SEC-293: Modified collection remove logic to use removeList. 2006-09-15 03:20:08 +00:00
Ben Alex e0108f3982 SEC-283: Docs correction for ConcuressSessionFilter. 2006-09-15 03:13:13 +00:00
Ben Alex d4b4cd68d2 Remove old sandbox locations. NB: New locations NOT added back in due to missing import errors. 2006-09-15 03:10:21 +00:00
Ben Alex 1292420476 SEC-311: Must observe symmetry requirement of Object.equals(Object) contract. 2006-09-15 03:09:05 +00:00
Ray Krueger cf91104b69 Made parameters case-insensitive 2006-09-14 20:47:17 +00:00
Ray Krueger 6779d97546 Made parameters case-insensitive 2006-09-14 20:39:37 +00:00
Carlos Sanchez 757062e8f9 Initialization of exceptionMappings was broken in last commit 2006-09-13 08:20:08 +00:00
Ben Alex 5e56d6f6ea Add JTrac. 2006-09-08 22:53:49 +00:00
Carlos Sanchez 30f6871124 Take another apporach and throw all unhandled exceptions wrapped in a ServletException 2006-09-06 17:18:36 +00:00
Carlos Sanchez e8de53b87c Add more info about the problem 2006-09-06 17:12:17 +00:00
Carlos Sanchez 6c0ddbfa9d Add WebWork support to handle Acegi exceptions 2006-09-06 16:54:18 +00:00
Carlos Sanchez 881d50e2a6 Split sandbox in subprojects 2006-09-06 16:37:28 +00:00
Carlos Sanchez 87c1117b47 Remove outdated m1 build 2006-09-06 16:36:52 +00:00
Carlos Sanchez 1554ae4cc6 Splitting sandbox in subpojects 2006-09-06 16:29:50 +00:00
Carlos Sanchez 3226a90fcd Split sandbox in subprojects 2006-09-06 16:27:39 +00:00
Ray Krueger 73cea493c6 Fixing unit test issues 2006-09-06 03:11:13 +00:00
Ray Krueger d88adf3f9e Fixed Java 1.3 incompatible IllegalStateException constructor.
Also fixed a potential NPE in getAccessibleField
2006-09-06 03:02:29 +00:00
Carlos Sanchez 3c223fd193 Explicitly set source plugin version, 2.0.1 seems to have a problem 2006-09-04 22:44:58 +00:00
Carlos Sanchez 4d070eab25 Add setAuthoritiesAsString to UserAttribute 2006-09-04 21:54:15 +00:00
Luke Taylor 000f9ab7ac SEC-321: truncate from first question mark, not last. 2006-09-03 22:12:13 +00:00
Ben Alex 9769394c92 Fixes to new ACL implementation. Thanks to Nathan Sarr. 2006-08-30 22:15:29 +00:00
Ben Alex a33ce2e7f0 Add Tapestry. 2006-08-30 11:57:10 +00:00
Ben Alex e5fd83624d Add Grails. 2006-08-30 08:30:26 +00:00
Ben Alex 265b719a39 Add Grails link. 2006-08-30 07:50:15 +00:00
Luke Taylor 557cf75745 Moved to branch 2006-08-28 22:03:20 +00:00
Luke Taylor 4e65b24253 SEC-245: Add mapPassword method to allow customized translation of password attribute. 2006-08-28 20:58:26 +00:00
Luke Taylor 1149da6137 Changed test server details. 2006-08-28 20:10:34 +00:00
Luke Taylor 5b414ddef5 Remove duplicate classes. 2006-08-25 19:16:41 +00:00
Luke Taylor e2a83b6822 Changed version of spring-mock to 1.2.7 for consistency. 2006-08-25 16:23:27 +00:00
Luke Taylor 308212febc Moved ppolicy test to correct package. 2006-08-25 16:18:58 +00:00
Luke Taylor 760a858be6 An oracle OID specific version of BindAuthenticator which parses password policy OID exception messages. 2006-08-25 16:17:12 +00:00
Luke Taylor 139d8c2f65 Experimental UserDetailsManager interface and some ldap implementation classes. 2006-08-25 16:14:50 +00:00
Luke Taylor 1b66467f70 Added ldaptemplate, ehcache and spring-mock dependencies. 2006-08-25 16:13:44 +00:00
Luke Taylor 54fb402e60 added package for password-policy specific classes and an ldaptemplate compatible context factory. 2006-08-25 16:12:26 +00:00
Luke Taylor 57a8d2adb3 Added handleBindException method to allow subclasses to inspect the reason for bind failure. 2006-08-25 16:06:20 +00:00
Luke Taylor dc13f25dee Tidied up formatting. 2006-08-25 16:04:27 +00:00
Luke Taylor 8dd1177c02 Added property to force use of LdapContext instead of DirContext 2006-08-25 16:03:50 +00:00
Luke Taylor 92dcf694b4 added createTarget method on Essence class to allow subclassing. 2006-08-25 15:32:39 +00:00
Luke Taylor b5cbc977e1 Javadoc correction 2006-08-24 10:56:26 +00:00
Luke Taylor 3889894d16 Added extra mapping of OperationNotSupportedException to BadCredentialsException as some servers return a 53 code (unwilling to perform) when attempting a bind (e.g. is password has expired). This shouldn't be treated as an outright failure. 2006-08-24 10:32:38 +00:00
Luke Taylor 67fcf426eb Close returned context in nameExists method 2006-08-24 10:10:24 +00:00
Luke Taylor e96fee6ec1 Updated apacheds version to RC3 and slf4j to 1.0.1 2006-08-24 10:07:39 +00:00
Carlos Sanchez 27d2db9e22 Ensure that array of valid permissions can't be modified outside the class 2006-08-22 17:57:18 +00:00
Carlos Sanchez 38ec0f0d30 SEC-286: Reverted rev# 1588 as build fails without log4j (class not found exception) 2006-08-22 16:17:46 +00:00
Carlos Sanchez 69ec903088 Add MethodDefinitionSourceMapping for easier configuration 2006-08-22 16:02:44 +00:00
Carlos Sanchez 0298851ca3 Allow setting ACLs by its name 2006-08-22 16:01:34 +00:00
Carlos Sanchez 3487da0e85 Added javadoc 2006-08-22 15:53:41 +00:00
Carlos Sanchez 773a0d6969 Add clirr plugin and build test-jar 2006-08-22 15:45:18 +00:00
Luke Taylor 3498b36c14 SEC-285: Removed duplicate commons-lang dependency from pom.xml 2006-08-19 20:03:58 +00:00
Luke Taylor 5de0939b03 SEC-334: Incorrect filter name. 2006-08-19 19:39:45 +00:00
Scott McCrory 8d3a2b42d9 SEC-319: Improvements to Siteminder integration: Create its own authentication provider & reeval strategy. Note that documentation not yet complete, but code is functional, test-covered and validated in a Siteminder environment. 2006-07-27 01:13:46 +00:00
Luke Taylor 52a167acfa SEC-286: removed log4j dep as it is in the parent pom and tests run fine without it.. 2006-07-25 23:53:42 +00:00
Luke Taylor 1f89d153b2 SEC-312: wrong chapter number in Chinese book. 2006-07-25 23:07:58 +00:00
Carlos Sanchez f7cb31a301 Fix broken test 2006-07-20 18:43:58 +00:00
Carlos Sanchez 9a337d2fea Removed default constructors added in rev# 1573 2006-07-20 13:15:55 +00:00
Carlos Sanchez 85a67c6b7c Use better repository ids 2006-07-18 17:34:27 +00:00
Luke Taylor 4930657e57 Remove typo in method name "getAuthoritiesPopulator" 2006-07-16 20:17:20 +00:00
Scott McCrory 442c51bb30 SEC-318: Rename AuthenticationDao to UserDetailsService in local variables and logging messages 2006-07-15 15:18:51 +00:00
Ray Krueger d485e30fd5 SavedCookieTest was renamed to SavedCookieTests 2006-07-12 10:33:14 +00:00
Ray Krueger ca863ce4f7 http://opensource.atlassian.com/projects/spring/browse/SEC-308
Headers should remain case-insensitive.
2006-07-12 10:25:32 +00:00
Carlos Sanchez 91799c9290 Added missing resources 2006-07-11 21:42:42 +00:00
Carlos Sanchez 156af5b8b6 Added missing tld and notice file to jar 2006-07-11 18:54:04 +00:00
Carlos Sanchez e5c2ef2d98 Update TLD uri to new acegisecurity.org location 2006-07-11 18:47:47 +00:00
Carlos Sanchez 5d15856ccc Use 1.1-SNAPSHOT as parent version 2006-07-11 18:27:36 +00:00
Carlos Sanchez 288fdb3df8 Fixed M2 pom 2006-07-11 18:22:21 +00:00
Carlos Sanchez 94a9acedad Added checks to ensure object is properly initialized 2006-07-10 11:48:35 +00:00
Carlos Sanchez 488abe58fb Added default constructor for easier use 2006-07-10 11:24:18 +00:00
Carlos Sanchez 80c1ae3bde fix problems when not loaded through Spring context 2006-07-09 22:08:21 +00:00
Carlos Sanchez 00b73e8331 Fix failing tests keeping old behaviour. 2006-07-06 17:56:50 +00:00
Carlos Sanchez 46af400466 Added FilterInvocationDefinition interface to unify FilterInvocationDefinitionSource and FilterInvocationDefinitionMap 2006-07-06 17:05:08 +00:00
Carlos Sanchez 9e87bd6789 Add javadocs 2006-07-06 17:03:48 +00:00
Carlos Sanchez aa52124d72 Simplify configuration of FilterInvocationDefinitionMap 2006-07-05 22:00:21 +00:00
Carlos Sanchez 9560636380 Simplify configuration of FilterInvocationDefinitionMap 2006-07-05 20:58:50 +00:00
Carlos Sanchez 9d539a13d9 Use accessor instead of field 2006-07-05 20:03:52 +00:00
Carlos Sanchez 0edb75d4aa Added setUsers and setAuthorities for easier configuration 2006-07-05 16:16:13 +00:00
Carlos Sanchez 41f7bb3755 Improve javadoc formatting 2006-07-05 16:00:51 +00:00
Carlos Sanchez 27de814d54 Prevent NullPointerException when not loaded from application context 2006-07-05 15:59:17 +00:00
Carlos Sanchez d847772c81 Prevent NullPointerException when not loaded from application context 2006-07-05 15:58:20 +00:00
Luke Taylor ae55e04522 SEC-297: Stop prepending of context path to full url default targets. Also added more stringent checks on format of injected defaultTargetUrl property. 2006-06-27 23:26:25 +00:00
Luke Taylor 55f7960e5c SEC-292: Corrected ldap package names 2006-06-27 21:48:49 +00:00
Carlos Sanchez 2c1ba76027 Bump version to 1.1-SNAPSHOT 2006-06-22 17:51:32 +00:00
Carlos Sanchez 18c6838bec [maven-release-plugin] prepare for next development iteration 2006-06-22 17:29:52 +00:00
Carlos Sanchez c7bcbe1b35 [maven-release-plugin] prepare release release_1_0_1 2006-06-22 17:27:29 +00:00
Carlos Sanchez f2ff448071 Fork tests 2006-06-22 16:56:09 +00:00
Carlos Sanchez 4a48cd4425 Set pmd jdk to 1.5 2006-06-22 16:55:22 +00:00
Carlos Sanchez d332b5ce18 Maven 2 improvements, added a bunch of reports 2006-06-19 23:24:06 +00:00
Carlos Sanchez e9b961d0f8 Apache snapshot repo was moved 2006-06-16 17:49:55 +00:00
Carlos Sanchez 9255004495 Prepare release of 1.0.1 2006-06-16 17:48:05 +00:00
Carlos Sanchez 4e612922ac SEC-281: Go back to spring 1.2.7 to prevent backwards compatibility issues 2006-06-16 17:25:05 +00:00
178 changed files with 4256 additions and 2609 deletions
+1 -2
View File
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="samples/attributes/src/main/java"/>
<classpathentry kind="src" path="sandbox/other/src/main/java"/>
<classpathentry kind="src" path="samples/acegifier/src/test/resources"/>
<classpathentry kind="src" path="samples/acegifier/src/main/resources"/>
<classpathentry kind="src" path="samples/acegifier/src/main/java"/>
@@ -17,8 +18,6 @@
<classpathentry kind="src" path="core/src/main/resources"/>
<classpathentry kind="src" path="core/src/test/resources"/>
<classpathentry kind="src" path="samples/contacts/src/main/java"/>
<classpathentry kind="src" path="sandbox/src/main/java"/>
<classpathentry kind="src" path="sandbox/src/test/java"/>
<classpathentry kind="src" path="adapters/cas/src/main/java"/>
<classpathentry kind="src" path="adapters/cas/src/test/java"/>
<classpathentry kind="src" path="adapters/catalina/src/main/java"/>
+3 -6
View File
@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<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">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security-adapters</artifactId>
<version>1.1.0-SNAPSHOT</version>
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>acegi-security-cas</artifactId>
<name>Acegi Security System for Spring - CAS adapter</name>
@@ -22,4 +19,4 @@
<version>2.0.12</version>
</dependency>
</dependencies>
</project>
</project>
+3 -6
View File
@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<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">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security-adapters</artifactId>
<version>1.1.0-SNAPSHOT</version>
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>acegi-security-catalina</artifactId>
<name>Acegi Security System for Spring - Catalina adapter</name>
@@ -17,4 +14,4 @@
<version>4.1.9</version>
</dependency>
</dependencies>
</project>
</project>
+3 -6
View File
@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<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">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security-adapters</artifactId>
<version>1.1.0-SNAPSHOT</version>
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>acegi-security-jboss</artifactId>
<name>Acegi Security System for Spring - JBoss adapter</name>
@@ -23,4 +20,4 @@
<scope>provided</scope>
</dependency>
</dependencies>
</project>
</project>
+3 -6
View File
@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<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">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security-adapters</artifactId>
<version>1.1.0-SNAPSHOT</version>
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>acegi-security-jetty</artifactId>
<name>Acegi Security System for Spring - Jetty adapter</name>
@@ -17,4 +14,4 @@
<version>4.2.22</version>
</dependency>
</dependencies>
</project>
</project>
@@ -31,6 +31,7 @@ import org.mortbay.http.UserPrincipal;
public class JettyAcegiUserToken extends AbstractAdapterAuthenticationToken implements UserPrincipal {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private String password;
private String username;
+3 -6
View File
@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<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">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security-parent</artifactId>
<version>1.1.0-SNAPSHOT</version>
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>acegi-security-adapters</artifactId>
<name>Acegi Security System for Spring - Adapters</name>
@@ -30,4 +27,4 @@
<module>jetty</module>
<module>resin</module>
</modules>
</project>
</project>
+1 -1
View File
@@ -13,7 +13,7 @@
<dependency>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security</artifactId>
<version>1.0.0</version>
<version>1.0.2</version>
<type>jar</type>
<url>http://acegisecurity.org</url>
<properties>
+3 -6
View File
@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<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">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security-adapters</artifactId>
<version>1.1.0-SNAPSHOT</version>
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>acegi-security-resin</artifactId>
<name>Acegi Security System for Spring - Resin adapter</name>
@@ -23,4 +20,4 @@
<scope>provided</scope>
</dependency>
</dependencies>
</project>
</project>
+23 -7
View File
@@ -1,15 +1,19 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<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">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security-parent</artifactId>
<version>1.1.0-SNAPSHOT</version>
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>acegi-security-tiger</artifactId>
<name>Acegi Security System for Spring - Java 5 (Tiger)</name>
<scm>
<connection>scm:svn:https://svn.sourceforge.net/svnroot/acegisecurity/trunk/acegisecurity/core-tiger</connection>
<developerConnection>scm:svn:https://svn.sourceforge.net/svnroot/acegisecurity/trunk/acegisecurity/core-tiger</developerConnection>
<url>http://svn.sourceforge.net/viewcvs.cgi/acegisecurity/trunk/acegisecurity/core-tiger/</url>
</scm>
<dependencies>
<dependency>
<groupId>org.acegisecurity</groupId>
@@ -19,9 +23,10 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>1.2.6</version>
<version>1.2.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
@@ -34,4 +39,15 @@
</plugin>
</plugins>
</build>
</project>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<configuration>
<targetJdk>1.5</targetJdk>
</configuration>
</plugin>
</plugins>
</reporting>
</project>
+1 -1
View File
@@ -14,7 +14,7 @@
<dependency>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security</artifactId>
<version>1.0.0</version>
<version>1.0.2</version>
<type>jar</type>
</dependency>
</dependencies>
+45 -22
View File
@@ -1,30 +1,36 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<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">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security-parent</artifactId>
<version>1.1.0-SNAPSHOT</version>
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>acegi-security</artifactId>
<name>Acegi Security System for Spring</name>
<scm>
<connection>scm:svn:https://svn.sourceforge.net/svnroot/acegisecurity/trunk/acegisecurity/core</connection>
<developerConnection>scm:svn:https://svn.sourceforge.net/svnroot/acegisecurity/trunk/acegisecurity/core</developerConnection>
<url>http://svn.sourceforge.net/viewcvs.cgi/acegisecurity/trunk/acegisecurity/core/</url>
</scm>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-remoting</artifactId>
<version>2.0-m2</version>
<version>1.2.7</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>2.0-m2</version>
<version>1.2.7</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-support</artifactId>
<version>2.0-m2</version>
<version>1.2.7</version>
<scope>runtime</scope>
</dependency>
<dependency>
@@ -54,11 +60,6 @@
<artifactId>commons-logging</artifactId>
<version>1.0.4</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
@@ -101,19 +102,13 @@
<dependency>
<groupId>org.apache.directory.server</groupId>
<artifactId>apacheds-core</artifactId>
<version>1.0-RC1</version>
<version>1.0-RC3</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>nlog4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.0-rc5</version>
<version>1.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -126,7 +121,35 @@
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
</dependencies>
</project>
<build>
<resources>
<resource>
<directory>${basedir}/../</directory>
<targetPath>META-INF</targetPath>
<includes>
<include>notice.txt</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>${basedir}/src/main/resources/org/acegisecurity/taglibs</directory>
<targetPath>META-INF</targetPath>
<includes>
<include>*.tld</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>${basedir}/src/main/resources</directory>
<targetPath>/</targetPath>
<includes>
<include>**/*</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
@@ -29,7 +29,7 @@ public class BadCredentialsException extends AuthenticationException {
//~ Constructors ===================================================================================================
/**
/**
* Constructs a <code>BadCredentialsException</code> with the specified
* message.
*
@@ -44,7 +44,7 @@ public class BadCredentialsException extends AuthenticationException {
this.extraInformation = extraInformation;
}
/**
/**
* Constructs a <code>BadCredentialsException</code> with the specified
* message and root cause.
*
@@ -15,6 +15,8 @@
package org.acegisecurity;
import java.io.Serializable;
/**
* Represents an authority granted to an {@link Authentication} object.
*
@@ -27,7 +29,7 @@ package org.acegisecurity;
* @author Ben Alex
* @version $Id$
*/
public interface GrantedAuthority {
public interface GrantedAuthority extends Serializable {
//~ Methods ========================================================================================================
/**
@@ -28,6 +28,7 @@ import java.io.Serializable;
public class GrantedAuthorityImpl implements GrantedAuthority, Serializable {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private String role;
//~ Constructors ===================================================================================================
@@ -35,10 +35,6 @@ public class SecurityConfig implements ConfigAttribute {
//~ Methods ========================================================================================================
public boolean equals(Object obj) {
if (obj instanceof String) {
return obj.equals(this.attrib);
}
if (obj instanceof ConfigAttribute) {
ConfigAttribute attr = (ConfigAttribute) obj;
@@ -18,7 +18,6 @@ package org.acegisecurity.acl.basic;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Stores some privileges typical of a domain object.
*
@@ -45,14 +44,18 @@ public class SimpleAclEntry extends AbstractBasicAclEntry {
public static final int READ_WRITE_DELETE = READ | WRITE | DELETE;
// Array required by the abstract superclass via getValidPermissions()
private static final int[] validPermissions = {
private static final int[] VALID_PERMISSIONS = {
NOTHING, ADMINISTRATION, READ, WRITE, CREATE, DELETE, READ_WRITE_CREATE_DELETE, READ_WRITE_CREATE,
READ_WRITE, READ_WRITE_DELETE
};
private static final String[] VALID_PERMISSIONS_AS_STRING = {
"NOTHING", "ADMINISTRATION", "READ", "WRITE", "CREATE", "DELETE", "READ_WRITE_CREATE_DELETE", "READ_WRITE_CREATE",
"READ_WRITE", "READ_WRITE_DELETE" };
//~ Constructors ===================================================================================================
/**
/**
* Allows {@link BasicAclDao} implementations to construct this object
* using <code>newInstance()</code>.
*
@@ -71,8 +74,11 @@ public class SimpleAclEntry extends AbstractBasicAclEntry {
//~ Methods ========================================================================================================
/**
* @return a copy of the permissions array, changes to the values won't affect this class.
*/
public int[] getValidPermissions() {
return validPermissions;
return (int[]) VALID_PERMISSIONS.clone();
}
public String printPermissionsBlock(int i) {
@@ -110,4 +116,35 @@ public class SimpleAclEntry extends AbstractBasicAclEntry {
return sb.toString();
}
/**
* Parse a permission {@link String} literal and return associated value.
*
* @param permission one of the field names that represent a permission: <code>ADMINISTRATION</code>,
* <code>READ</code>, <code>WRITE</code>,...
* @return the value associated to that permission
* @throws IllegalArgumentException if argument is not a valid permission
*/
public static int parsePermission(String permission) {
for (int i = 0; i < VALID_PERMISSIONS_AS_STRING.length; i++) {
if (VALID_PERMISSIONS_AS_STRING[i].equalsIgnoreCase(permission)) {
return VALID_PERMISSIONS[i];
}
}
throw new IllegalArgumentException("Permission provided does not exist: " + permission);
}
/**
* Parse a list of permission {@link String} literals and return associated values.
*
* @param permissions array with permissions as {@link String}
* @see #parsePermission(String) for valid values
*/
public static int[] parsePermissions(String[] permissions) {
int[] requirepermissionAsIntArray = new int[permissions.length];
for (int i = 0; i < requirepermissionAsIntArray.length; i++) {
requirepermissionAsIntArray[i] = parsePermission(permissions[i]);
}
return requirepermissionAsIntArray;
}
}
@@ -29,6 +29,7 @@ import java.security.Principal;
public class PrincipalAcegiUserToken extends AbstractAdapterAuthenticationToken implements Principal {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private Object principal;
private String password;
private String username;
@@ -211,6 +211,16 @@ public class BasicAclEntryAfterInvocationCollectionFilteringProvider implements
this.requirePermission = requirePermission;
}
/**
* Allow setting permissions with String literals instead of integers as {@link #setRequirePermission(int[])}
*
* @param requirePermission permission literals
* @see SimpleAclEntry#parsePermissions(String[]) for valid values
*/
public void setRequirePermissionFromString(String[] requirePermission) {
setRequirePermission(SimpleAclEntry.parsePermissions(requirePermission));
}
public boolean supports(ConfigAttribute attribute) {
if ((attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute())) {
return true;
@@ -332,7 +342,7 @@ class CollectionFilterer implements Filterer {
* @see org.acegisecurity.afterinvocation.Filterer#remove(java.lang.Object)
*/
public void remove(Object object) {
collectionIter.remove();
removeList.add(object);
}
}
@@ -39,7 +39,6 @@ import org.springframework.util.Assert;
import java.util.Iterator;
/**
* <p>Given a domain object instance returned from a secure object invocation, ensures the principal has
* appropriate permission as defined by the {@link AclManager}.</p>
@@ -187,6 +186,16 @@ public class BasicAclEntryAfterInvocationProvider implements AfterInvocationProv
this.requirePermission = requirePermission;
}
/**
* Allow setting permissions with String literals instead of integers as {@link #setRequirePermission(int[])}
*
* @param requirePermission Permission literals
* @see SimpleAclEntry#parsePermissions(String[]) for valid values
*/
public void setRequirePermissionFromString(String[] requirePermission) {
setRequirePermission(SimpleAclEntry.parsePermissions(requirePermission));
}
public boolean supports(ConfigAttribute attribute) {
if ((attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute())) {
return true;
@@ -100,6 +100,10 @@ public class HttpSessionContextIntegrationFilter implements InitializingBean, Fi
*/
private boolean forceEagerSessionCreation = false;
public HttpSessionContextIntegrationFilter() throws ServletException {
this.contextObject = generateNewContext();
}
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
@@ -113,8 +117,6 @@ public class HttpSessionContextIntegrationFilter implements InitializingBean, Fi
throw new IllegalArgumentException(
"If using forceEagerSessionCreation, you must set allowSessionCreation to also be true");
}
this.contextObject = generateNewContext();
}
/**
@@ -41,6 +41,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.MessageSource;
@@ -276,7 +277,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
} catch (AccessDeniedException accessDeniedException) {
AuthorizationFailureEvent event = new AuthorizationFailureEvent(object, attr, authenticated,
accessDeniedException);
this.eventPublisher.publishEvent(event);
publishEvent(event);
throw accessDeniedException;
}
@@ -286,7 +287,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
}
AuthorizedEvent event = new AuthorizedEvent(object, attr, authenticated);
this.eventPublisher.publishEvent(event);
publishEvent(event);
// Attempt to run as a different user
Authentication runAs = this.runAsManager.buildRunAs(authenticated, object, attr);
@@ -311,7 +312,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
logger.debug("Public object - authentication not attempted");
}
this.eventPublisher.publishEvent(new PublicInvocationEvent(object));
publishEvent(new PublicInvocationEvent(object));
return null; // no further work post-invocation
}
@@ -330,7 +331,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
AuthenticationCredentialsNotFoundEvent event = new AuthenticationCredentialsNotFoundEvent(secureObject,
configAttribs, exception);
this.eventPublisher.publishEvent(event);
publishEvent(event);
throw exception;
}
@@ -431,4 +432,10 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
public void setValidateConfigAttributes(boolean validateConfigAttributes) {
this.validateConfigAttributes = validateConfigAttributes;
}
private void publishEvent(ApplicationEvent event) {
if (this.eventPublisher != null) {
this.eventPublisher.publishEvent(event);
}
}
}
@@ -17,6 +17,7 @@ package org.acegisecurity.intercept.method;
import org.acegisecurity.ConfigAttribute;
import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.SecurityConfig;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -232,4 +233,25 @@ public class MethodDefinitionMap extends AbstractMethodDefinitionSource {
definition.addConfigAttribute((ConfigAttribute) attribs.next());
}
}
/**
* Easier configuration of the instance, using {@link MethodDefinitionSourceMapping}.
*
* @param mappings {@link List} of {@link MethodDefinitionSourceMapping} objects.
*/
public void setMappings(List mappings) {
Iterator it = mappings.iterator();
while (it.hasNext()) {
MethodDefinitionSourceMapping mapping = (MethodDefinitionSourceMapping) it.next();
ConfigAttributeDefinition configDefinition = new ConfigAttributeDefinition();
Iterator configAttributesIt = mapping.getConfigAttributes().iterator();
while (configAttributesIt.hasNext()) {
String s = (String) configAttributesIt.next();
configDefinition.addConfigAttribute(new SecurityConfig(s));
}
addSecureMethod(mapping.getMethodName(), configDefinition);
}
}
}
@@ -15,17 +15,17 @@
package org.acegisecurity.intercept.method;
import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.ConfigAttributeEditor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.propertyeditors.PropertiesEditor;
import org.springframework.util.StringUtils;
import java.beans.PropertyEditorSupport;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
@@ -56,20 +56,24 @@ public class MethodDefinitionSourceEditor extends PropertyEditorSupport {
Properties props = (Properties) propertiesEditor.getValue();
// Now we have properties, process each one individually
ConfigAttributeEditor configAttribEd = new ConfigAttributeEditor();
List mappings = new ArrayList();
for (Iterator iter = props.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String value = props.getProperty(name);
// Convert value to series of security configuration attributes
configAttribEd.setAsText(value);
MethodDefinitionSourceMapping mapping = new MethodDefinitionSourceMapping();
mapping.setMethodName(name);
ConfigAttributeDefinition attr = (ConfigAttributeDefinition) configAttribEd.getValue();
String[] tokens = StringUtils.commaDelimitedListToStringArray(value);
// Register name and attribute
source.addSecureMethod(name, attr);
for (int i = 0; i < tokens.length; i++) {
mapping.addConfigAttribute(tokens[i].trim());
}
mappings.add(mapping);
}
source.setMappings(mappings);
}
setValue(source);
@@ -0,0 +1,82 @@
/* Copyright 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.intercept.method;
import java.util.ArrayList;
import java.util.List;
import org.acegisecurity.ConfigAttribute;
/**
* Configuration entry for {@link MethodDefinitionSource}, that holds
* the method to be protected and the {@link ConfigAttribute}s as {@link String}
* that apply to that url.
*
* @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
* @version $Id$
* @since 1.1
*/
public class MethodDefinitionSourceMapping {
private String methodName;
private List configAttributes = new ArrayList();
/**
* Name of the method to be secured, including package and class name.
* eg. <code>org.mydomain.MyClass.myMethod</code>
*
* @param methodName
*/
public void setMethodName(String methodName) {
this.methodName = methodName;
}
/**
* Name of the method to be secured.
*
* @return the name of the method
*/
public String getMethodName() {
return methodName;
}
/**
*
* @param roles {@link List}&lt;{@link String}>
*/
public void setConfigAttributes(List roles) {
this.configAttributes = roles;
}
/**
*
* @return {@link List}&lt;{@link String}>
*/
public List getConfigAttributes() {
return configAttributes;
}
/**
* Add a {@link ConfigAttribute} as {@link String}
*
* @param configAttribute
*/
public void addConfigAttribute(String configAttribute) {
configAttributes.add(configAttribute);
}
}
@@ -1,4 +1,4 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,25 +13,15 @@
* limitations under the License.
*/
package org.acegisecurity.providers.smb;
import org.acegisecurity.AuthenticationException;
package org.acegisecurity.intercept.web;
/**
* Thrown if
*
* @author Davide Baroncelli
* Interface to join {@link FilterInvocationDefinitionMap} and
* {@link FilterInvocationDefinitionSource}.
*
* @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
* @version $Id$
* @since 1.1
*/
public class ChallengeExpiredException extends AuthenticationException {
//~ Constructors ===================================================================================================
public ChallengeExpiredException(String msg) {
super(msg);
}
public ChallengeExpiredException(String msg, Throwable t) {
super(msg, t);
}
public interface FilterInvocationDefinition extends FilterInvocationDefinitionMap, FilterInvocationDefinitionSource {
}
@@ -0,0 +1,153 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.intercept.web;
import java.util.Iterator;
import java.util.List;
import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.SecurityConfig;
/**
* <p>
* Decorator of {@link FilterInvocationDefinition} for easier configuration,
* using {@link FilterInvocationDefinitionSourceMapping}.
* </p>
*
* <p>
* Delegates all calls to decorated object set in constructor
* {@link #FilterInvocationDefinitionDecorator(FilterInvocationDefinition)} or
* by calling {@link #setDecorated(FilterInvocationDefinition)}
* </p>
*
* @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
* @version $Id$
* @since 1.1
*/
public class FilterInvocationDefinitionDecorator implements FilterInvocationDefinition {
private FilterInvocationDefinition decorated;
private List mappings;
public FilterInvocationDefinitionDecorator() {
}
public FilterInvocationDefinitionDecorator(FilterInvocationDefinition decorated) {
this.setDecorated(decorated);
}
/**
* Set the decorated object
*
* @param decorated
* the decorated {@link FilterInvocationDefinition}
*/
public void setDecorated(FilterInvocationDefinition decorated) {
this.decorated = decorated;
}
/**
* Get decorated object
*
* @return the decorated {@link FilterInvocationDefinition}
*/
public FilterInvocationDefinition getDecorated() {
return decorated;
}
/**
* Configures the decorated {@link FilterInvocationDefinitionMap} easier,
* using {@link FilterInvocationDefinitionSourceMapping}.
*
* @param mappings
* {@link List} of
* {@link FilterInvocationDefinitionSourceMapping} objects.
*/
public void setMappings(List mappings) {
if (decorated == null) {
throw new IllegalStateException("decorated object has not been set");
}
this.mappings = mappings;
Iterator it = mappings.iterator();
while (it.hasNext()) {
FilterInvocationDefinitionSourceMapping mapping = (FilterInvocationDefinitionSourceMapping) it.next();
ConfigAttributeDefinition configDefinition = new ConfigAttributeDefinition();
Iterator configAttributesIt = mapping.getConfigAttributes().iterator();
while (configAttributesIt.hasNext()) {
String s = (String) configAttributesIt.next();
configDefinition.addConfigAttribute(new SecurityConfig(s));
}
decorated.addSecureUrl(mapping.getUrl(), configDefinition);
}
}
/**
* Get the mappings used for configuration.
*
* @return {@link List} of {@link FilterInvocationDefinitionSourceMapping}
* objects.
*/
public List getMappings() {
return mappings;
}
/**
* Delegate to decorated object
*/
public void addSecureUrl(String expression, ConfigAttributeDefinition attr) {
getDecorated().addSecureUrl(expression, attr);
}
/**
* Delegate to decorated object
*/
public boolean isConvertUrlToLowercaseBeforeComparison() {
return getDecorated().isConvertUrlToLowercaseBeforeComparison();
}
/**
* Delegate to decorated object
*/
public void setConvertUrlToLowercaseBeforeComparison(boolean convertUrlToLowercaseBeforeComparison) {
getDecorated().setConvertUrlToLowercaseBeforeComparison(convertUrlToLowercaseBeforeComparison);
}
/**
* Delegate to decorated object
*/
public ConfigAttributeDefinition getAttributes(Object object) throws IllegalArgumentException {
return getDecorated().getAttributes(object);
}
/**
* Delegate to decorated object
*/
public Iterator getConfigAttributeDefinitions() {
return getDecorated().getConfigAttributeDefinitions();
}
/**
* Delegate to decorated object
*/
public boolean supports(Class clazz) {
return getDecorated().supports(clazz);
}
}
@@ -15,9 +15,6 @@
package org.acegisecurity.intercept.web;
import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.ConfigAttributeEditor;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -27,6 +24,8 @@ import java.beans.PropertyEditorSupport;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
/**
@@ -50,14 +49,15 @@ public class FilterInvocationDefinitionSourceEditor extends PropertyEditorSuppor
//~ Methods ========================================================================================================
public void setAsText(String s) throws IllegalArgumentException {
FilterInvocationDefinitionMap source = new RegExpBasedFilterInvocationDefinitionMap();
FilterInvocationDefinitionDecorator source = new FilterInvocationDefinitionDecorator();
source.setDecorated(new RegExpBasedFilterInvocationDefinitionMap());
if ((s == null) || "".equals(s)) {
// Leave target object empty
} else {
// Check if we need to override the default definition map
if (s.lastIndexOf(DIRECTIVE_PATTERN_TYPE_APACHE_ANT) != -1) {
source = new PathBasedFilterInvocationDefinitionMap();
source.setDecorated(new PathBasedFilterInvocationDefinitionMap());
if (logger.isDebugEnabled()) {
logger.debug(("Detected " + DIRECTIVE_PATTERN_TYPE_APACHE_ANT
@@ -77,6 +77,8 @@ public class FilterInvocationDefinitionSourceEditor extends PropertyEditorSuppor
BufferedReader br = new BufferedReader(new StringReader(s));
int counter = 0;
String line;
List mappings = new ArrayList();
while (true) {
counter++;
@@ -138,7 +140,7 @@ public class FilterInvocationDefinitionSourceEditor extends PropertyEditorSuppor
// Attempt to detect malformed lines (as per SEC-204)
if (source.isConvertUrlToLowercaseBeforeComparison()
&& source instanceof PathBasedFilterInvocationDefinitionMap) {
&& source.getDecorated() instanceof PathBasedFilterInvocationDefinitionMap) {
// Should all be lowercase; check each character
// We only do this for Ant (regexp have control chars)
for (int i = 0; i < name.length(); i++) {
@@ -153,17 +155,21 @@ public class FilterInvocationDefinitionSourceEditor extends PropertyEditorSuppor
}
}
// Convert value to series of security configuration attributes
ConfigAttributeEditor configAttribEd = new ConfigAttributeEditor();
configAttribEd.setAsText(value);
FilterInvocationDefinitionSourceMapping mapping = new FilterInvocationDefinitionSourceMapping();
mapping.setUrl(name);
ConfigAttributeDefinition attr = (ConfigAttributeDefinition) configAttribEd.getValue();
String[] tokens = org.springframework.util.StringUtils
.commaDelimitedListToStringArray(value);
// Register the regular expression and its attribute
source.addSecureUrl(name, attr);
for (int i = 0; i < tokens.length; i++) {
mapping.addConfigAttribute(tokens[i].trim());
}
mappings.add(mapping);
}
source.setMappings(mappings);
}
setValue(source);
setValue(source.getDecorated());
}
}
@@ -0,0 +1,82 @@
/* Copyright 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.intercept.web;
import java.util.ArrayList;
import java.util.List;
import org.acegisecurity.ConfigAttribute;
/**
* Configuration entry for {@link FilterInvocationDefinitionSource}, that holds
* the url to be protected and the {@link ConfigAttribute}s as {@link String}
* that apply to that url.
*
* @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
* @version $Id$
* @since 1.1
*/
public class FilterInvocationDefinitionSourceMapping {
private String url;
private List configAttributes = new ArrayList();
/**
* Url to be secured.
*
* @param url
*/
public void setUrl(String url) {
this.url = url;
}
/**
* Url to be secured.
*
* @return the url
*/
public String getUrl() {
return url;
}
/**
*
* @param roles
* {@link List}&lt;{@link String}>
*/
public void setConfigAttributes(List roles) {
this.configAttributes = roles;
}
/**
*
* @return {@link List}&lt;{@link String}>
*/
public List getConfigAttributes() {
return configAttributes;
}
/**
* Add a {@link ConfigAttribute} as {@link String}
*
* @param configAttribute
*/
public void addConfigAttribute(String configAttribute) {
configAttributes.add(configAttribute);
}
}
@@ -44,7 +44,7 @@ import java.util.Vector;
* @version $Id$
*/
public class PathBasedFilterInvocationDefinitionMap extends AbstractFilterInvocationDefinitionSource
implements FilterInvocationDefinitionMap {
implements FilterInvocationDefinition {
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(PathBasedFilterInvocationDefinitionMap.class);
@@ -86,14 +86,14 @@ public class PathBasedFilterInvocationDefinitionMap extends AbstractFilterInvoca
}
public ConfigAttributeDefinition lookupAttributes(String url) {
// Strip anything after a question mark symbol, as per SEC-161.
int firstQuestionMarkIndex = url.lastIndexOf("?");
// Strip anything after a question mark symbol, as per SEC-161. See also SEC-321
int firstQuestionMarkIndex = url.indexOf("?");
if (firstQuestionMarkIndex != -1) {
url = url.substring(0, firstQuestionMarkIndex);
}
if (convertUrlToLowercaseBeforeComparison) {
if (isConvertUrlToLowercaseBeforeComparison()) {
url = url.toLowerCase();
if (logger.isDebugEnabled()) {
@@ -45,7 +45,7 @@ import java.util.Vector;
* <p>If no registered regular expressions match the HTTP URL, <code>null</code> is returned.</p>
*/
public class RegExpBasedFilterInvocationDefinitionMap extends AbstractFilterInvocationDefinitionSource
implements FilterInvocationDefinitionMap {
implements FilterInvocationDefinition {
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(RegExpBasedFilterInvocationDefinitionMap.class);
@@ -100,7 +100,7 @@ public class RegExpBasedFilterInvocationDefinitionMap extends AbstractFilterInvo
Iterator iter = requestMap.iterator();
if (convertUrlToLowercaseBeforeComparison) {
if (isConvertUrlToLowercaseBeforeComparison()) {
url = url.toLowerCase();
if (logger.isDebugEnabled()) {
@@ -34,6 +34,8 @@ import java.util.StringTokenizer;
import javax.naming.CommunicationException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.OperationNotSupportedException;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
@@ -104,13 +106,32 @@ public class DefaultInitialDirContextFactory implements InitialDirContextFactory
*/
private boolean useConnectionPool = true;
/** Set to true for ldap v3 compatible servers */
private boolean useLdapContext = false;
//~ Constructors ===================================================================================================
/**
* Create and initialize an instance to the LDAP url provided
*
* @param providerUrl a String of the form <code>ldap://localhost:389/base_dn<code>
*/
public DefaultInitialDirContextFactory(String providerUrl) {
this.providerUrl = providerUrl;
this.setProviderUrl(providerUrl);
}
//~ Methods ========================================================================================================
/**
* Set the LDAP url
*
* @param providerUrl a String of the form <code>ldap://localhost:389/base_dn<code>
*/
private void setProviderUrl(String providerUrl) {
Assert.hasLength(providerUrl, "An LDAP connection URL must be supplied.");
this.providerUrl = providerUrl;
StringTokenizer st = new StringTokenizer(providerUrl);
// Work out rootDn from the first URL and check that the other URLs (if any) match
@@ -131,7 +152,14 @@ public class DefaultInitialDirContextFactory implements InitialDirContextFactory
//Assert.isTrue(uri.getScheme().equals("ldap"), "Ldap URL must start with 'ldap://'");
}
//~ Methods ========================================================================================================
/**
* Get the LDAP url
*
* @return the url
*/
private String getProviderUrl() {
return providerUrl;
}
private InitialDirContext connect(Hashtable env) {
if (logger.isDebugEnabled()) {
@@ -145,17 +173,22 @@ public class DefaultInitialDirContextFactory implements InitialDirContextFactory
}
try {
return new InitialDirContext(env);
} catch (CommunicationException ce) {
throw new LdapDataAccessException(messages.getMessage(
"DefaultIntitalDirContextFactory.communicationFailure", "Unable to connect to LDAP server"), ce);
} catch (javax.naming.AuthenticationException ae) {
throw new BadCredentialsException(messages.getMessage("DefaultIntitalDirContextFactory.badCredentials",
"Bad credentials"), ae);
} catch (NamingException nx) {
return useLdapContext ? new InitialLdapContext(env, null) : new InitialDirContext(env);
} catch (NamingException ne) {
if ((ne instanceof javax.naming.AuthenticationException) ||
(ne instanceof OperationNotSupportedException)) {
throw new BadCredentialsException(messages.getMessage("DefaultIntitalDirContextFactory.badCredentials",
"Bad credentials"), ne);
}
if (ne instanceof CommunicationException) {
throw new LdapDataAccessException(messages.getMessage(
"DefaultIntitalDirContextFactory.communicationFailure", "Unable to connect to LDAP server"), ne);
}
throw new LdapDataAccessException(messages.getMessage(
"DefaultIntitalDirContextFactory.unexpectedException",
"Failed to obtain InitialDirContext due to unexpected exception"), nx);
"Failed to obtain InitialDirContext due to unexpected exception"), ne);
}
}
@@ -169,7 +202,7 @@ public class DefaultInitialDirContextFactory implements InitialDirContextFactory
env.put(Context.SECURITY_AUTHENTICATION, authenticationType);
env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
env.put(Context.PROVIDER_URL, providerUrl);
env.put(Context.PROVIDER_URL, getProviderUrl());
if (useConnectionPool) {
env.put(CONNECTION_POOL_KEY, "true");
@@ -280,4 +313,8 @@ public class DefaultInitialDirContextFactory implements InitialDirContextFactory
public void setUseConnectionPool(boolean useConnectionPool) {
this.useConnectionPool = useConnectionPool;
}
public void setUseLdapContext(boolean useLdapContext) {
this.useLdapContext = useLdapContext;
}
}
@@ -27,6 +27,7 @@ import java.util.Set;
import javax.naming.NameNotFoundException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.Context;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
@@ -132,17 +133,21 @@ public class LdapTemplate {
public boolean nameExists(final String dn) {
Boolean exists = (Boolean) execute(new LdapCallback() {
public Object doInDirContext(DirContext ctx)
throws NamingException {
try {
ctx.lookup(LdapUtils.getRelativeName(dn, ctx));
} catch (NameNotFoundException nnfe) {
return Boolean.FALSE;
public Object doInDirContext(DirContext ctx)
throws NamingException {
try {
Object obj = ctx.lookup(LdapUtils.getRelativeName(dn, ctx));
if (obj instanceof Context) {
LdapUtils.closeContext((Context) obj);
}
return Boolean.TRUE;
} catch (NameNotFoundException nnfe) {
return Boolean.FALSE;
}
});
return Boolean.TRUE;
}
});
return exists.booleanValue();
}
@@ -51,6 +51,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.MessageSource;
@@ -95,6 +96,7 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(ProviderManager.class);
private static final Properties DEFAULT_EXCEPTION_MAPPINGS = new Properties();
//~ Instance fields ================================================================================================
@@ -102,36 +104,39 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
private ConcurrentSessionController sessionController = new NullConcurrentSessionController();
private List providers;
protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
private Properties exceptionMappings;
private Properties exceptionMappings = new Properties();
static {
DEFAULT_EXCEPTION_MAPPINGS.put(AccountExpiredException.class.getName(),
AuthenticationFailureExpiredEvent.class.getName());
DEFAULT_EXCEPTION_MAPPINGS.put(AuthenticationServiceException.class.getName(),
AuthenticationFailureServiceExceptionEvent.class.getName());
DEFAULT_EXCEPTION_MAPPINGS.put(LockedException.class.getName(), AuthenticationFailureLockedEvent.class.getName());
DEFAULT_EXCEPTION_MAPPINGS.put(CredentialsExpiredException.class.getName(),
AuthenticationFailureCredentialsExpiredEvent.class.getName());
DEFAULT_EXCEPTION_MAPPINGS.put(DisabledException.class.getName(), AuthenticationFailureDisabledEvent.class.getName());
DEFAULT_EXCEPTION_MAPPINGS.put(BadCredentialsException.class.getName(),
AuthenticationFailureBadCredentialsEvent.class.getName());
DEFAULT_EXCEPTION_MAPPINGS.put(UsernameNotFoundException.class.getName(),
AuthenticationFailureBadCredentialsEvent.class.getName());
DEFAULT_EXCEPTION_MAPPINGS.put(ConcurrentLoginException.class.getName(),
AuthenticationFailureConcurrentLoginEvent.class.getName());
DEFAULT_EXCEPTION_MAPPINGS.put(ProviderNotFoundException.class.getName(),
AuthenticationFailureProviderNotFoundEvent.class.getName());
DEFAULT_EXCEPTION_MAPPINGS.put(ProxyUntrustedException.class.getName(),
AuthenticationFailureProxyUntrustedEvent.class.getName());
}
public ProviderManager() {
exceptionMappings.putAll(DEFAULT_EXCEPTION_MAPPINGS);
}
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
checkIfValidList(this.providers);
Assert.notNull(this.messages, "A message source must be set");
if (exceptionMappings == null) {
exceptionMappings = new Properties();
exceptionMappings.put(AccountExpiredException.class.getName(),
AuthenticationFailureExpiredEvent.class.getName());
exceptionMappings.put(AuthenticationServiceException.class.getName(),
AuthenticationFailureServiceExceptionEvent.class.getName());
exceptionMappings.put(LockedException.class.getName(), AuthenticationFailureLockedEvent.class.getName());
exceptionMappings.put(CredentialsExpiredException.class.getName(),
AuthenticationFailureCredentialsExpiredEvent.class.getName());
exceptionMappings.put(DisabledException.class.getName(), AuthenticationFailureDisabledEvent.class.getName());
exceptionMappings.put(BadCredentialsException.class.getName(),
AuthenticationFailureBadCredentialsEvent.class.getName());
exceptionMappings.put(UsernameNotFoundException.class.getName(),
AuthenticationFailureBadCredentialsEvent.class.getName());
exceptionMappings.put(ConcurrentLoginException.class.getName(),
AuthenticationFailureConcurrentLoginEvent.class.getName());
exceptionMappings.put(ProviderNotFoundException.class.getName(),
AuthenticationFailureProviderNotFoundEvent.class.getName());
exceptionMappings.put(ProxyUntrustedException.class.getName(),
AuthenticationFailureProxyUntrustedEvent.class.getName());
doAddExtraDefaultExceptionMappings(exceptionMappings);
}
doAddExtraDefaultExceptionMappings(DEFAULT_EXCEPTION_MAPPINGS);
}
private void checkIfValidList(List listToCheck) {
@@ -189,7 +194,7 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
if (result != null) {
sessionController.registerSuccessfulAuthentication(result);
applicationEventPublisher.publishEvent(new AuthenticationSuccessEvent(result));
publishEvent(new AuthenticationSuccessEvent(result));
return result;
}
@@ -222,7 +227,7 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
}
if (event != null) {
applicationEventPublisher.publishEvent(event);
publishEvent(event);
} else {
if (logger.isDebugEnabled()) {
logger.debug("No event was found for the exception " + lastException.getClass().getName());
@@ -273,6 +278,7 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
try {
currentObject = iter.next();
//TODO bad idea, should use assignable from or instance of
AuthenticationProvider attemptToCast = (AuthenticationProvider) currentObject;
} catch (ClassCastException cce) {
throw new IllegalArgumentException("AuthenticationProvider " + currentObject.getClass().getName()
@@ -292,4 +298,10 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
public void setSessionController(ConcurrentSessionController sessionController) {
this.sessionController = sessionController;
}
private void publishEvent( ApplicationEvent event ) {
if ( applicationEventPublisher != null ) {
applicationEventPublisher.publishEvent( event );
}
}
}
@@ -28,6 +28,7 @@ import org.acegisecurity.GrantedAuthority;
public class TestingAuthenticationToken extends AbstractAuthenticationToken {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private Object credentials;
private Object principal;
@@ -30,6 +30,7 @@ import org.acegisecurity.GrantedAuthority;
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private Object credentials;
private Object principal;
@@ -31,6 +31,7 @@ import java.io.Serializable;
public class AnonymousAuthenticationToken extends AbstractAuthenticationToken implements Serializable {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private Object principal;
private int keyHash;
@@ -35,6 +35,7 @@ import java.util.List;
public class CasAuthenticationToken extends AbstractAuthenticationToken implements Serializable {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private final List proxyList;
private final Object credentials;
private final Object principal;
@@ -55,7 +55,7 @@ public class DaoCasAuthoritiesPopulator implements CasAuthoritiesPopulator, Init
return userDetailsService;
}
public void setUserDetailsService(UserDetailsService authenticationDao) {
this.userDetailsService = authenticationDao;
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
}
@@ -145,10 +145,15 @@ public abstract class AbstractUserDetailsAuthenticationProvider implements Authe
try {
additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
} catch (AuthenticationException exception) {
// There was a problem, so try again after checking we're using latest data
cacheWasUsed = false;
user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
if(cacheWasUsed) {
// There was a problem, so try again after checking
// we're using latest data (ie not from the cache)
cacheWasUsed = false;
user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
} else {
throw exception;
}
}
if (!user.isCredentialsNonExpired()) {
@@ -63,7 +63,7 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
}
protected void doAfterPropertiesSet() throws Exception {
Assert.notNull(this.userDetailsService, "An Authentication DAO must be set");
Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
}
public PasswordEncoder getPasswordEncoder() {
@@ -90,7 +90,7 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
if (loadedUser == null) {
throw new AuthenticationServiceException(
"AuthenticationDao returned null, which is an interface contract violation");
"UserDetailsService returned null, which is an interface contract violation");
}
return loadedUser;
@@ -117,7 +117,7 @@ public class DaoAuthenticationProvider extends AbstractUserDetailsAuthentication
this.saltSource = saltSource;
}
public void setUserDetailsService(UserDetailsService authenticationDao) {
this.userDetailsService = authenticationDao;
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
}
@@ -48,7 +48,7 @@ public interface PasswordEncoder {
* @param salt optionally used by the implementation to "salt" the raw password before encoding. A
* <code>null</code> value is legal.
*
* @return DOCUMENT ME!
* @return encoded password
*
* @throws DataAccessException DOCUMENT ME!
*/
@@ -67,7 +67,7 @@ public interface PasswordEncoder {
* @param salt optionally used by the implementation to "salt" the raw password before encoding. A
* <code>null</code> value is legal.
*
* @return DOCUMENT ME!
* @return true if the password is valid , false otherwise
*
* @throws DataAccessException DOCUMENT ME!
*/
@@ -30,6 +30,7 @@ import javax.security.auth.login.LoginContext;
public class JaasAuthenticationToken extends UsernamePasswordAuthenticationToken {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private transient LoginContext loginContext = null;
//~ Constructors ===================================================================================================
@@ -32,6 +32,7 @@ import java.security.Principal;
public class JaasGrantedAuthority extends GrantedAuthorityImpl {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private Principal principal;
//~ Constructors ===================================================================================================
@@ -123,16 +123,37 @@ public class LdapAuthenticationProvider extends AbstractUserDetailsAuthenticatio
//~ Constructors ===================================================================================================
/**
* Create an initialized instance to the values passed as arguments
*
* @param authenticator
* @param authoritiesPopulator
*/
public LdapAuthenticationProvider(LdapAuthenticator authenticator, LdapAuthoritiesPopulator authoritiesPopulator) {
Assert.notNull(authenticator, "An LdapAuthenticator must be supplied");
Assert.notNull(authoritiesPopulator, "An LdapAuthoritiesPopulator must be supplied");
this.authenticator = authenticator;
this.authoritiesPopulator = authoritiesPopulator;
this.setAuthenticator(authenticator);
this.setAuthoritiesPopulator(authoritiesPopulator);
}
//~ Methods ========================================================================================================
private void setAuthenticator(LdapAuthenticator authenticator) {
Assert.notNull(authenticator, "An LdapAuthenticator must be supplied");
this.authenticator = authenticator;
}
private LdapAuthenticator getAuthenticator() {
return authenticator;
}
private void setAuthoritiesPopulator(LdapAuthoritiesPopulator authoritiesPopulator) {
Assert.notNull(authoritiesPopulator, "An LdapAuthoritiesPopulator must be supplied");
this.authoritiesPopulator = authoritiesPopulator;
}
protected LdapAuthoritiesPopulator getAuthoritiesPopulator() {
return authoritiesPopulator;
}
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
@@ -161,7 +182,7 @@ public class LdapAuthenticationProvider extends AbstractUserDetailsAuthenticatio
user.setUsername(username);
user.setPassword(password);
GrantedAuthority[] extraAuthorities = authoritiesPopulator.getGrantedAuthorities(ldapUser);
GrantedAuthority[] extraAuthorities = getAuthoritiesPopulator().getGrantedAuthorities(ldapUser);
for (int i = 0; i < extraAuthorities.length; i++) {
user.addAuthority(extraAuthorities[i]);
@@ -170,10 +191,6 @@ public class LdapAuthenticationProvider extends AbstractUserDetailsAuthenticatio
return user.createUserDetails();
}
protected LdapAuthoritiesPopulator getAuthoritiesPoulator() {
return authoritiesPopulator;
}
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
if (!StringUtils.hasLength(username)) {
@@ -195,7 +212,7 @@ public class LdapAuthenticationProvider extends AbstractUserDetailsAuthenticatio
}
try {
LdapUserDetails ldapUser = authenticator.authenticate(username, password);
LdapUserDetails ldapUser = getAuthenticator().authenticate(username, password);
return createUserDetails(ldapUser, username, password);
@@ -70,7 +70,29 @@ public abstract class AbstractLdapAuthenticator implements LdapAuthenticator, In
//~ Constructors ===================================================================================================
protected AbstractLdapAuthenticator(InitialDirContextFactory initialDirContextFactory) {
/**
* Create an initialized instance to the {@link InitialDirContextFactory} provided.
*
* @param initialDirContextFactory
*/
public AbstractLdapAuthenticator(InitialDirContextFactory initialDirContextFactory) {
this.setInitialDirContextFactory(initialDirContextFactory);
}
// ~ Methods
// ========================================================================================================
public void afterPropertiesSet() throws Exception {
Assert.isTrue((userDnFormat != null) || (userSearch != null),
"Either an LdapUserSearch or DN pattern (or both) must be supplied.");
}
/**
* Set the {@link InitialDirContextFactory} and initialize this instance from its data.
*
* @param initialDirContextFactory
*/
private void setInitialDirContextFactory(InitialDirContextFactory initialDirContextFactory) {
Assert.notNull(initialDirContextFactory, "initialDirContextFactory must not be null.");
this.initialDirContextFactory = initialDirContextFactory;
@@ -81,13 +103,6 @@ public abstract class AbstractLdapAuthenticator implements LdapAuthenticator, In
}
}
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
Assert.isTrue((userDnFormat != null) || (userSearch != null),
"Either an LdapUserSearch or DN pattern (or both) must be supplied.");
}
protected InitialDirContextFactory getInitialDirContextFactory() {
return initialDirContextFactory;
}
@@ -26,6 +26,7 @@ import org.acegisecurity.userdetails.ldap.LdapUserDetailsImpl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.naming.NamingException;
import java.util.Iterator;
@@ -44,6 +45,11 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
//~ Constructors ===================================================================================================
/**
* Create an initialized instance to the {@link InitialDirContextFactory} provided.
*
* @param initialDirContextFactory
*/
public BindAuthenticator(InitialDirContextFactory initialDirContextFactory) {
super(initialDirContextFactory);
}
@@ -77,10 +83,6 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
private LdapUserDetails bindWithDn(String userDn, String username, String password) {
LdapTemplate template = new LdapTemplate(getInitialDirContextFactory(), userDn, password);
if (logger.isDebugEnabled()) {
logger.debug("Attempting to bind with DN = " + userDn);
}
try {
LdapUserDetailsImpl.Essence user = (LdapUserDetailsImpl.Essence) template.retrieveEntry(userDn,
getUserDetailsMapper(), getUserAttributes());
@@ -89,12 +91,21 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
return user.createUserDetails();
} catch (BadCredentialsException e) {
// This will be thrown if an invalid user name is used and the method may
// be called multiple times to try different names, so we trap the exception.
if (logger.isDebugEnabled()) {
logger.debug("Failed to bind as " + userDn + ": " + e.getCause());
}
// be called multiple times to try different names, so we trap the exception
// unless a subclass wishes to implement more specialized behaviour.
handleBindException(userDn, username, e.getCause());
}
return null;
}
/**
* Allows subclasses to inspect the exception thrown by an attempt to bind with a particular DN.
* The default implementation just reports the failure to the debug log.
*/
void handleBindException(String userDn, String username, Throwable cause) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to bind as " + userDn + ": " + cause);
}
}
}
@@ -121,18 +121,8 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
* context factory.
*/
public DefaultLdapAuthoritiesPopulator(InitialDirContextFactory initialDirContextFactory, String groupSearchBase) {
Assert.notNull(initialDirContextFactory, "InitialDirContextFactory must not be null");
Assert.notNull(groupSearchBase, "The groupSearchBase (name to search under), must not be null.");
this.initialDirContextFactory = initialDirContextFactory;
this.groupSearchBase = groupSearchBase;
if (groupSearchBase.length() == 0) {
logger.info("groupSearchBase is empty. Searches will be performed from the root: "
+ initialDirContextFactory.getRootDn());
}
ldapTemplate = new LdapTemplate(initialDirContextFactory);
ldapTemplate.setSearchControls(searchControls);
this.setInitialDirContextFactory(initialDirContextFactory);
this.setGroupSearchBase(groupSearchBase);
}
//~ Methods ========================================================================================================
@@ -204,16 +194,16 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
public Set getGroupMembershipRoles(String userDn, String username) {
Set authorities = new HashSet();
if (groupSearchBase == null) {
if (getGroupSearchBase() == null) {
return authorities;
}
if (logger.isDebugEnabled()) {
logger.debug("Searching for roles for user '" + username + "', DN = " + "'" + userDn + "', with filter "
+ groupSearchFilter + " in search base '" + groupSearchBase + "'");
+ groupSearchFilter + " in search base '" + getGroupSearchBase() + "'");
}
Set userRoles = ldapTemplate.searchForSingleAttributeValues(groupSearchBase, groupSearchFilter,
Set userRoles = ldapTemplate.searchForSingleAttributeValues(getGroupSearchBase(), groupSearchFilter,
new String[] {userDn, username}, groupRoleAttribute);
if (logger.isDebugEnabled()) {
@@ -254,6 +244,38 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
return initialDirContextFactory;
}
/**
* Set the {@link InitialDirContextFactory}
*
* @param initialDirContextFactory supplies the contexts used to search for user roles.
*/
private void setInitialDirContextFactory(InitialDirContextFactory initialDirContextFactory) {
Assert.notNull(initialDirContextFactory, "InitialDirContextFactory must not be null");
this.initialDirContextFactory = initialDirContextFactory;
ldapTemplate = new LdapTemplate(initialDirContextFactory);
ldapTemplate.setSearchControls(searchControls);
}
/**
* Set the group search base (name to search under)
*
* @param groupSearchBase if this is an empty string the search will be performed from the root DN of the context
* factory.
*/
private void setGroupSearchBase(String groupSearchBase) {
Assert.notNull(groupSearchBase, "The groupSearchBase (name to search under), must not be null.");
this.groupSearchBase = groupSearchBase;
if (groupSearchBase.length() == 0) {
logger.info("groupSearchBase is empty. Searches will be performed from the root: "
+ getInitialDirContextFactory().getRootDn());
}
}
private String getGroupSearchBase() {
return groupSearchBase;
}
public void setConvertToUpperCase(boolean convertToUpperCase) {
this.convertToUpperCase = convertToUpperCase;
}
@@ -15,14 +15,11 @@
package org.acegisecurity.providers.rememberme;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.providers.AbstractAuthenticationToken;
import org.springframework.util.Assert;
import java.io.Serializable;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.providers.AbstractAuthenticationToken;
/**
* Represents a remembered <code>Authentication</code>.<p>A remembered <code>Authentication</code> must provide a
@@ -34,12 +31,13 @@ import java.io.Serializable;
public class RememberMeAuthenticationToken extends AbstractAuthenticationToken implements Serializable {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private Object principal;
private int keyHash;
//~ Constructors ===================================================================================================
/**
/**
* Constructor.
*
* @param key to identify if this object made by an authorised client
@@ -51,16 +49,10 @@ public class RememberMeAuthenticationToken extends AbstractAuthenticationToken i
public RememberMeAuthenticationToken(String key, Object principal, GrantedAuthority[] authorities) {
super(authorities);
if ((key == null) || ("".equals(key)) || (principal == null) || "".equals(principal) || (authorities == null)
|| (authorities.length == 0)) {
if ((key == null) || ("".equals(key)) || (principal == null) || "".equals(principal)) {
throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
}
for (int i = 0; i < authorities.length; i++) {
Assert.notNull(authorities[i],
"Granted authority element " + i + " is null - GrantedAuthority[] cannot contain any null elements");
}
this.keyHash = key.hashCode();
this.principal = principal;
setAuthenticated(true);
@@ -0,0 +1,132 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.providers.siteminder;
import org.acegisecurity.AccountExpiredException;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.AuthenticationServiceException;
import org.acegisecurity.CredentialsExpiredException;
import org.acegisecurity.DisabledException;
import org.acegisecurity.LockedException;
import org.acegisecurity.providers.AuthenticationProvider;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.util.Assert;
/**
* An {@link AuthenticationProvider} implementation that retrieves user details from an {@link UserDetailsService}.
*
* @author Scott McCrory
* @version $Id: SiteminderAuthenticationProvider.java 1582 2006-07-15 15:18:51Z smccrory $
*/
public class SiteminderAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
/**
* Our logging object
*/
private static final Log logger = LogFactory.getLog(SiteminderAuthenticationProvider.class);
//~ Instance fields ================================================================================================
/**
* Our user details service (which does the real work of checking the user against a back-end user store).
*/
private UserDetailsService userDetailsService;
//~ Methods ========================================================================================================
/**
* @see org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider#additionalAuthenticationChecks(org.acegisecurity.userdetails.UserDetails, org.acegisecurity.providers.UsernamePasswordAuthenticationToken)
*/
protected void additionalAuthenticationChecks(final UserDetails user,
final UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
// No need for password authentication checks - we only expect one identifying string
// from the HTTP Request header (as populated by Siteminder), but we do need to see if
// the user's account is OK to let them in.
if (!user.isEnabled()) {
throw new DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled",
"Account disabled"));
}
if (!user.isAccountNonExpired()) {
throw new AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired",
"Account expired"));
}
if (!user.isAccountNonLocked()) {
throw new LockedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked",
"Account locked"));
}
if (!user.isCredentialsNonExpired()) {
throw new CredentialsExpiredException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.credentialsExpired", "Credentials expired"));
}
}
/**
* @see org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider#doAfterPropertiesSet()
*/
protected void doAfterPropertiesSet() throws Exception {
Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
}
/**
* Return the user details service.
* @return The user details service.
*/
public UserDetailsService getUserDetailsService() {
return userDetailsService;
}
/**
* @see org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider#retrieveUser(java.lang.String, org.acegisecurity.providers.UsernamePasswordAuthenticationToken)
*/
protected final UserDetails retrieveUser(final String username,
final UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
UserDetails loadedUser;
try {
loadedUser = this.getUserDetailsService().loadUserByUsername(username);
} catch (DataAccessException repositoryProblem) {
throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
}
if (loadedUser == null) {
throw new AuthenticationServiceException(
"UserDetailsService returned null, which is an interface contract violation");
}
return loadedUser;
}
/**
* Sets the user details service.
* @param userDetailsService The user details service.
*/
public void setUserDetailsService(final UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
}
@@ -0,0 +1,5 @@
<html>
<body>
A Siteminder authentication provider.
</body>
</html>
@@ -31,6 +31,7 @@ import java.security.cert.X509Certificate;
public class X509AuthenticationToken extends AbstractAuthenticationToken {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private Object principal;
private X509Certificate credentials;
@@ -117,7 +117,7 @@ public class DaoX509AuthoritiesPopulator implements X509AuthoritiesPopulator, In
this.subjectDNRegex = subjectDNRegex;
}
public void setUserDetailsService(UserDetailsService authenticationDao) {
this.userDetailsService = authenticationDao;
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
}
@@ -29,6 +29,7 @@ import org.acegisecurity.providers.AbstractAuthenticationToken;
public class RunAsUserToken extends AbstractAuthenticationToken {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private Class originalAuthentication;
private Object credentials;
private Object principal;
@@ -313,13 +313,13 @@ public abstract class AbstractProcessingFilter implements Filter, InitializingBe
return uri.endsWith(request.getContextPath() + filterProcessesUrl);
}
protected void sendRedirect(HttpServletRequest request, HttpServletResponse response, String failureUrl)
protected void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url)
throws IOException {
if (!failureUrl.startsWith("http://") && !failureUrl.startsWith("https://")) {
failureUrl = request.getContextPath() + failureUrl;
if (!url.startsWith("http://") && !url.startsWith("https://")) {
url = request.getContextPath() + url;
}
response.sendRedirect(response.encodeRedirectURL(failureUrl));
response.sendRedirect(response.encodeRedirectURL(url));
}
public void setAlwaysUseDefaultTargetUrl(boolean alwaysUseDefaultTargetUrl) {
@@ -348,6 +348,8 @@ public abstract class AbstractProcessingFilter implements Filter, InitializingBe
}
public void setDefaultTargetUrl(String defaultTargetUrl) {
Assert.isTrue(defaultTargetUrl.startsWith("/") | defaultTargetUrl.startsWith("http"),
"defaultTarget must start with '/' or with 'http(s)'");
this.defaultTargetUrl = defaultTargetUrl;
}
@@ -379,14 +381,11 @@ public abstract class AbstractProcessingFilter implements Filter, InitializingBe
logger.debug("Updated SecurityContextHolder to contain the following Authentication: '" + authResult + "'");
}
String targetUrl = obtainFullRequestUrl(request);
if (alwaysUseDefaultTargetUrl) {
targetUrl = null;
}
// Don't attempt to obtain the url from the saved request if alwaysUsedefaultTargetUrl is set
String targetUrl = alwaysUseDefaultTargetUrl ? null : obtainFullRequestUrl(request);
if (targetUrl == null) {
targetUrl = request.getContextPath() + getDefaultTargetUrl();
targetUrl = getDefaultTargetUrl();
}
if (logger.isDebugEnabled()) {
@@ -402,7 +401,7 @@ public abstract class AbstractProcessingFilter implements Filter, InitializingBe
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
}
response.sendRedirect(response.encodeRedirectURL(targetUrl));
sendRedirect(request, response, targetUrl);
}
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
@@ -62,21 +62,13 @@ public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
// Perform RequestDispatcher "forward"
RequestDispatcher rd = request.getRequestDispatcher(errorPage);
try {
rd.forward(request, response);
((HttpServletResponse) response).setStatus(HttpServletResponse.SC_FORBIDDEN);
return;
} catch (Exception responseCommitted) {
if (logger.isErrorEnabled()) {
logger.error("Error processing " + request.toString(), responseCommitted);
}
}
rd.forward(request, response);
}
// Send 403 (we do this after response has been written)
((HttpServletResponse) response).sendError(HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage());
if (!response.isCommitted()) {
// Send 403 (we do this after response has been written)
((HttpServletResponse) response).sendError(HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage());
}
}
/**
@@ -15,27 +15,6 @@
package org.acegisecurity.ui.basicauth;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.ui.AuthenticationDetailsSource;
import org.acegisecurity.ui.AuthenticationDetailsSourceImpl;
import org.acegisecurity.ui.AuthenticationEntryPoint;
import org.acegisecurity.ui.rememberme.RememberMeServices;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import java.io.IOException;
import javax.servlet.Filter;
@@ -47,6 +26,21 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.ui.AuthenticationDetailsSource;
import org.acegisecurity.ui.AuthenticationDetailsSourceImpl;
import org.acegisecurity.ui.AuthenticationEntryPoint;
import org.acegisecurity.ui.rememberme.RememberMeServices;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* Processes a HTTP request's BASIC authorization headers, putting the result into the
@@ -135,7 +129,10 @@ public class BasicProcessingFilter implements Filter, InitializingBean {
// Only reauthenticate if username doesn't match SecurityContextHolder and user isn't authenticated (see SEC-53)
Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication();
if ((existingAuth == null) || !existingAuth.getName().equals(username) || !existingAuth.isAuthenticated()) {
// Limit username comparison to providers which user usernames (ie UsernamePasswordAuthenticationToken) (see SEC-348)
if ((existingAuth == null)
|| (existingAuth instanceof UsernamePasswordAuthenticationToken && !existingAuth.getName().equals(username))
|| !existingAuth.isAuthenticated()) {
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username,
password);
authRequest.setDetails(authenticationDetailsSource.buildDetails((HttpServletRequest) request));
@@ -431,7 +431,7 @@ public class DigestProcessingFilter implements Filter, InitializingBean, Message
this.userCache = userCache;
}
public void setUserDetailsService(UserDetailsService authenticationDao) {
this.userDetailsService = authenticationDao;
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
}
@@ -18,28 +18,60 @@ package org.acegisecurity.ui.logout;
import org.acegisecurity.Authentication;
import org.acegisecurity.context.SecurityContextHolder;
import org.springframework.util.Assert;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Performs a logout by modifying the {@link org.acegisecurity.context.SecurityContextHolder}.
*
* <p>Will also invalidate the {@link HttpSession} if {@link #isInvalidateHttpSession()} is
* <code>true</code> and the session is not <code>null</code>.
*
* @author Ben Alex
* @version $Id$
*/
public class SecurityContextLogoutHandler implements LogoutHandler {
//~ Methods ========================================================================================================
private boolean invalidateHttpSession = true;
/**
* Does not use any arguments. They can all be <code>null</code>.
* Requires the request to be passed in.
*
* @param request not used (can be <code>null</code>)
* @param request from which to obtain a HTTP session (cannot be null)
* @param response not used (can be <code>null</code>)
* @param authentication not used (can be <code>null</code>)
*/
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
SecurityContextHolder.clearContext();
Assert.notNull(request, "HttpServletRequest required");
if (invalidateHttpSession) {
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
}
SecurityContextHolder.clearContext();
}
public boolean isInvalidateHttpSession() {
return invalidateHttpSession;
}
/**
* Causes the {@link HttpSession} to be invalidated when this
* {@link LogoutHandler} is invoked. Defaults to true.
*
* @param invalidateHttpSession true if you wish the session to be
* invalidated (default) or false if it should not be
*/
public void setInvalidateHttpSession(boolean invalidateHttpSession) {
this.invalidateHttpSession = invalidateHttpSession;
}
}
@@ -319,7 +319,7 @@ public class TokenBasedRememberMeServices implements RememberMeServices, Initial
this.tokenValiditySeconds = tokenValiditySeconds;
}
public void setUserDetailsService(UserDetailsService authenticationDao) {
this.userDetailsService = authenticationDao;
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
}
@@ -25,11 +25,11 @@ import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
/**
@@ -55,8 +55,8 @@ public class SavedRequest implements java.io.Serializable {
private ArrayList cookies = new ArrayList();
private ArrayList locales = new ArrayList();
private HashMap headers = new HashMap();
private HashMap parameters = new HashMap();
private Map headers = new TreeMap(String.CASE_INSENSITIVE_ORDER);
private Map parameters = new TreeMap(String.CASE_INSENSITIVE_ORDER);
private String contextPath;
private String method;
private String pathInfo;
@@ -31,6 +31,7 @@ import org.acegisecurity.GrantedAuthorityImpl;
public class SwitchUserGrantedAuthority extends GrantedAuthorityImpl {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private Authentication source;
//~ Constructors ===================================================================================================
@@ -439,8 +439,8 @@ public class SwitchUserProcessingFilter implements Filter, InitializingBean, App
*
* @param authenticationDao The authentication dao
*/
public void setUserDetailsService(UserDetailsService authenticationDao) {
this.userDetailsService = authenticationDao;
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
/**
@@ -1,5 +1,5 @@
<html>
<body>
Authenticates users via a standard web form and <code>HttpSession</code>.
Authenticates users via HTTP properties, headers and session.
</body>
</html>
@@ -31,6 +31,7 @@ import org.springframework.util.Assert;
public class User implements UserDetails {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private String password;
private String username;
private GrantedAuthority[] authorities;
@@ -41,6 +41,7 @@ import javax.naming.ldap.Control;
public class LdapUserDetailsImpl implements LdapUserDetails {
//~ Static fields/initializers =====================================================================================
private static final long serialVersionUID = 1L;
private static final GrantedAuthority[] NO_AUTHORITIES = new GrantedAuthority[0];
private static final Control[] NO_CONTROLS = new Control[0];
@@ -109,7 +110,7 @@ public class LdapUserDetailsImpl implements LdapUserDetails {
* Variation of essence pattern. Used to create mutable intermediate object
*/
public static class Essence {
LdapUserDetailsImpl instance = new LdapUserDetailsImpl();
LdapUserDetailsImpl instance = createTarget();
List mutableAuthorities = new ArrayList();
public Essence() {}
@@ -127,6 +128,10 @@ public class LdapUserDetailsImpl implements LdapUserDetails {
setAuthorities(copyMe.getAuthorities());
}
LdapUserDetailsImpl createTarget() {
return new LdapUserDetailsImpl();
}
public Essence addAuthority(GrantedAuthority a) {
mutableAuthorities.add(a);
@@ -58,14 +58,7 @@ public class LdapUserDetailsMapper implements LdapEntryMapper {
Attribute passwordAttribute = attributes.get(passwordAttributeName);
if (passwordAttribute != null) {
Object retrievedPassword = passwordAttribute.get();
if (!(retrievedPassword instanceof String)) {
// Assume it's binary
retrievedPassword = new String((byte[]) retrievedPassword);
}
essence.setPassword((String) retrievedPassword);
essence.setPassword(mapPassword(passwordAttribute));
}
// Map the roles
@@ -93,6 +86,25 @@ public class LdapUserDetailsMapper implements LdapEntryMapper {
return essence;
}
/**
* Extension point to allow customized creation of the user's password from
* the attribute stored in the directory.
*
* @param passwordAttribute the attribute instance containing the password
* @return a String representation of the password.
*/
protected String mapPassword(Attribute passwordAttribute) throws NamingException {
Object retrievedPassword = passwordAttribute.get();
if (!(retrievedPassword instanceof String)) {
// Assume it's binary
retrievedPassword = new String((byte[]) retrievedPassword);
}
return (String) retrievedPassword;
}
/**
* Creates a GrantedAuthority from a role attribute. Override to customize
* authority object creation.
@@ -18,6 +18,8 @@ package org.acegisecurity.userdetails.memory;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
@@ -53,6 +55,32 @@ public class UserAttribute {
return (GrantedAuthority[]) this.authorities.toArray(toReturn);
}
/**
* Set all authorities for this user.
*
* @param authorities {@link List} &lt;{@link GrantedAuthority}>
* @since 1.1
*/
public void setAuthorities(List authorities) {
this.authorities = authorities;
}
/**
* Set all authorities for this user from String values.
* It will create the necessary {@link GrantedAuthority} objects.
*
* @param authoritiesAsString {@link List} &lt;{@link String}>
* @since 1.1
*/
public void setAuthoritiesAsString(List authoritiesAsString) {
setAuthorities(new ArrayList(authoritiesAsString.size()));
Iterator it = authoritiesAsString.iterator();
while (it.hasNext()) {
GrantedAuthority grantedAuthority = new GrantedAuthorityImpl((String) it.next());
addAuthority(grantedAuthority);
}
}
public String getPassword() {
return password;
}
@@ -15,13 +15,12 @@
package org.acegisecurity.userdetails.memory;
import org.acegisecurity.GrantedAuthorityImpl;
import java.beans.PropertyEditorSupport;
import java.util.ArrayList;
import java.util.List;
import org.springframework.util.StringUtils;
import java.beans.PropertyEditorSupport;
/**
* Property editor that creates a {@link UserAttribute} from a comma separated list of values.
*
@@ -35,6 +34,8 @@ public class UserAttributeEditor extends PropertyEditorSupport {
if (StringUtils.hasText(s)) {
String[] tokens = StringUtils.commaDelimitedListToStringArray(s);
UserAttribute userAttrib = new UserAttribute();
List authoritiesAsString = new ArrayList();
for (int i = 0; i < tokens.length; i++) {
String currentToken = tokens[i].trim();
@@ -47,10 +48,11 @@ public class UserAttributeEditor extends PropertyEditorSupport {
} else if (currentToken.toLowerCase().equals("disabled")) {
userAttrib.setEnabled(false);
} else {
userAttrib.addAuthority(new GrantedAuthorityImpl(currentToken));
authoritiesAsString.add(currentToken);
}
}
}
userAttrib.setAuthoritiesAsString(authoritiesAsString);
if (userAttrib.isValid()) {
setValue(userAttrib);
@@ -15,18 +15,15 @@
package org.acegisecurity.userdetails.memory;
import org.acegisecurity.userdetails.User;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import java.util.HashMap;
import java.util.Map;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
/**
* Used by {@link InMemoryDaoImpl} to store a list of users and their corresponding granted authorities.
@@ -68,8 +65,8 @@ public class UserMap {
*
* @throws UsernameNotFoundException if the user could not be found
*/
public User getUser(String username) throws UsernameNotFoundException {
User result = (User) this.userMap.get(username.toLowerCase());
public UserDetails getUser(String username) throws UsernameNotFoundException {
UserDetails result = (UserDetails) this.userMap.get(username.toLowerCase());
if (result == null) {
throw new UsernameNotFoundException("Could not find user: " + username);
@@ -86,4 +83,14 @@ public class UserMap {
public int getUserCount() {
return this.userMap.size();
}
/**
* Set the users in this {@link UserMap}. Overrides previously added users.
*
* @param users {@link Map} &lt;{@link String}, {@link UserDetails}> with pairs (username, userdetails)
* @since 1.1
*/
public void setUsers(Map users) {
this.userMap = users;
}
}
@@ -0,0 +1,139 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.util;
import java.io.UnsupportedEncodingException;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import org.acegisecurity.AcegiSecurityException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.Validate;
import org.springframework.util.Assert;
/**
* A static utility class that can encrypt and decrypt text.
*
* <p>This class is useful if you have simple needs and wish to use the DESede
* encryption cipher. More sophisticated requirements will need to use the
* Java crypto libraries directly.
*
* @author Alan Stewart
* @author Ben Alex
* @version $Id$
*/
public class EncryptionUtils {
/**
* This is a static class that should not be instantiated.
*/
private EncryptionUtils() {}
/**
* Converts a String into a byte array using UTF-8, falling back to the
* platform's default character set if UTF-8 fails.
*
* @param input the input (required)
* @return a byte array representation of the input string
*/
public static byte[] stringToByteArray(String input) {
Assert.hasLength(input, "Input required");
try {
return input.getBytes("UTF-8");
} catch (UnsupportedEncodingException fallbackToDefault) {
return input.getBytes();
}
}
/**
* Converts a byte array into a String using UTF-8, falling back to the
* platform's default character set if UTF-8 fails.
*
* @param byteArray the byte array to convert (required)
* @return a string representation of the byte array
*/
public static String byteArrayToString(byte[] byteArray) {
Assert.notNull(byteArray, "ByteArray required");
Assert.isTrue(byteArray.length > 0, "ByteArray cannot be empty");
try {
return new String(byteArray, "UTF8");
} catch (final UnsupportedEncodingException e) {
return new String(byteArray);
}
}
private static byte[] cipher(String key, byte[] passedBytes, int cipherMode) throws EncryptionException {
try {
final KeySpec keySpec = new DESedeKeySpec(stringToByteArray(key));
final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
final SecretKey secretKey = keyFactory.generateSecret(keySpec);
cipher.init(cipherMode, secretKey);
return cipher.doFinal(passedBytes);
} catch (final Exception e) {
throw new EncryptionException(e.getMessage(), e);
}
}
/**
* Encrypts the inputString using the key.
*
* @param key at least 24 character long key (required)
* @param inputString the string to encrypt (required)
* @return the encrypted version of the inputString
* @throws EncryptionException in the event of an encryption failure
*/
public static String encrypt(String key, String inputString) throws EncryptionException {
isValidKey(key);
final byte[] cipherText = cipher(key, stringToByteArray(inputString), Cipher.ENCRYPT_MODE);
return byteArrayToString(Base64.encodeBase64(cipherText));
}
/**
* Decrypts the inputString using the key.
*
* @param key the key used to originally encrypt the string (required)
* @param inputString the encrypted string (required)
* @return the decrypted version of inputString
* @throws EncryptionException in the event of an encryption failure
*/
public static String decrypt(String key, String inputString) throws EncryptionException {
Assert.hasText(key, "A key is required to attempt decryption");
final byte[] cipherText = cipher(key, Base64.decodeBase64(stringToByteArray(inputString)), Cipher.DECRYPT_MODE);
return byteArrayToString(cipherText);
}
private static void isValidKey(String key) {
Assert.hasText(key, "A key to perform the encryption is required");
Validate.isTrue(key.length() >= 24, "Key must be at least 24 characters long");
}
public static class EncryptionException extends AcegiSecurityException {
private static final long serialVersionUID = 1L;
public EncryptionException(String message, Throwable t) {
super(message, t);
}
public EncryptionException(String message) {
super(message);
}
}
}
@@ -28,32 +28,40 @@ import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* Delegates <code>Filter</code> requests to a Spring-managed bean.<p>This class acts as a proxy on behalf of a
* <p>Delegates <code>Filter</code> requests to a Spring-managed bean.</p>
*
* <p>This class acts as a proxy on behalf of a
* target <code>Filter</code> that is defined in the Spring bean context. It is necessary to specify which target
* <code>Filter</code> should be proxied as a filter initialization parameter.</p>
* <p>On filter initialisation, the class will use Spring's {@link
*
* <p>On filter initialisation, the class will use Spring's {@link
* WebApplicationContextUtils#getWebApplicationContext(ServletContext sc)} method to obtain an
* <code>ApplicationContext</code> instance. It will expect to find the target <code>Filter</code> in this
* <code>ApplicationContext</code>.</p>
* <p>To use this filter, it is necessary to specify <b>one</b> of the following filter initialization parameters:</p>
*
* <p>To use this filter, it is necessary to specify <b>one</b> of the following filter initialization parameters:
* <ul>
* <li><code>targetClass</code> indicates the class of the target <code>Filter</code> defined in the bean
* context. The only requirements are that this target class implements the <code>javax.servlet.Filter</code>
* interface and at least one instance is available in the <code>ApplicationContext</code>.</li>
* <li><code>targetBean</code> indicates the bean name of the target class.</li>
* </ul>
* If both initialization parameters are specified, <code>targetBean</code> takes priority.<P>An additional
* If both initialization parameters are specified, <code>targetBean</code> takes priority.</p>
*
* <p>An additional
* initialization parameter, <code>init</code>, is also supported. If set to "<code>lazy</code>" the initialization
* will take place on the first HTTP request, rather than at filter creation time. This makes it possible to use
* <code>FilterToBeanProxy</code> with the Spring <code>ContextLoaderServlet</code>. Where possible you should not use
* this initialization parameter, instead using <code>ContextLoaderListener</code>.</p>
* <p>A final optional initialization parameter, <code>lifecycle</code>, determines whether the servlet container
*
* <p>A final optional initialization parameter, <code>lifecycle</code>, determines whether the servlet container
* or the IoC container manages the lifecycle of the proxied filter. When possible you should write your filters to be
* managed via the IoC container interfaces such as {@link org.springframework.beans.factory.InitializingBean} and
* {@link org.springframework.beans.factory.DisposableBean}. If you cannot control the filters you wish to proxy (eg
@@ -72,7 +72,7 @@ public class MethodInvocationUtils {
classArgs = (Class[]) list.toArray(new Class[] {});
}
return createFromClass(object.getClass(), methodName, classArgs);
return createFromClass(object.getClass(), methodName, classArgs, args);
}
/**
@@ -84,7 +84,7 @@ public class MethodInvocationUtils {
* @return a <code>MethodInvocation</code>, or <code>null</code> if there was a problem
*/
public static MethodInvocation createFromClass(Class clazz, String methodName) {
return createFromClass(clazz, methodName, null);
return createFromClass(clazz, methodName, null, null);
}
/**
@@ -93,18 +93,18 @@ public class MethodInvocationUtils {
*
* @param clazz the class of object that will be used to find the relevant <code>Method</code>
* @param methodName the name of the method to find
* @param args arguments that are required as part of the method signature
*
* @param classArgs arguments that are required to locate the relevant method signature
* @param args the actual arguments that should be passed to SimpleMethodInvocation
* @return a <code>MethodInvocation</code>, or <code>null</code> if there was a problem
*/
public static MethodInvocation createFromClass(Class clazz, String methodName, Class[] args) {
public static MethodInvocation createFromClass(Class clazz, String methodName, Class[] classArgs, Object[] args) {
Assert.notNull(clazz, "Class required");
Assert.hasText(methodName, "MethodName required");
Method method;
try {
method = clazz.getMethod(methodName, args);
method = clazz.getMethod(methodName, classArgs);
} catch (Exception e) {
return null;
}
@@ -23,6 +23,7 @@ import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.acl.AclEntry;
import org.acegisecurity.acl.AclManager;
import org.acegisecurity.acl.basic.BasicAclEntry;
import org.acegisecurity.acl.basic.SimpleAclEntry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -143,6 +144,16 @@ public class BasicAclEntryVoter extends AbstractAclVoter implements Initializing
this.requirePermission = requirePermission;
}
/**
* Allow setting permissions with String literals instead of integers as {@link #setRequirePermission(int[])}
*
* @param requirePermission Permission literals
* @see SimpleAclEntry#parsePermissions(String[]) for valid values
*/
public void setRequirePermissionFromString(String[] requirePermission) {
setRequirePermission(SimpleAclEntry.parsePermissions(requirePermission));
}
public boolean supports(ConfigAttribute attribute) {
if ((attribute.getAttribute() != null) && attribute.getAttribute().startsWith(getProcessConfigAttribute())) {
return true;
@@ -66,8 +66,9 @@ public class SecurityConfigTests extends TestCase {
SecurityConfig security2 = new SecurityConfig("TEST");
assertEquals(security1, security2);
// SEC-311: Must observe symmetry requirement of Object.equals(Object) contract
String securityString1 = "TEST";
assertEquals(security1, securityString1);
assertNotSame(security1, securityString1);
String securityString2 = "NOT_EQUAL";
assertTrue(!security1.equals(securityString2));
@@ -17,7 +17,6 @@ package org.acegisecurity.acl.basic;
import junit.framework.TestCase;
/**
* Tests {@link SimpleAclEntry}.
*
@@ -171,4 +170,38 @@ public class SimpleAclEntryTests extends TestCase {
acl.addPermissions(new int[] {SimpleAclEntry.READ, SimpleAclEntry.WRITE, SimpleAclEntry.CREATE});
assertTrue(acl.toString().endsWith("marissa=-RWC- ............................111. (14)]"));
}
public void testParsePermission() {
assertPermission("NOTHING", SimpleAclEntry.NOTHING);
assertPermission("ADMINISTRATION", SimpleAclEntry.ADMINISTRATION);
assertPermission("READ", SimpleAclEntry.READ);
assertPermission("WRITE", SimpleAclEntry.WRITE);
assertPermission("CREATE", SimpleAclEntry.CREATE);
assertPermission("DELETE", SimpleAclEntry.DELETE);
assertPermission("READ_WRITE_DELETE", SimpleAclEntry.READ_WRITE_DELETE);
}
public void testParsePermissionWrongValues() {
try {
SimpleAclEntry.parsePermission("X");
fail(IllegalArgumentException.class.getName() + " must have been thrown.");
} catch (IllegalArgumentException e) {
// expected
}
}
private void assertPermission(String permission, int value) {
assertEquals(value, SimpleAclEntry.parsePermission(permission));
}
/**
* Check that the value returned by {@link SimpleAclEntry#getValidPermissions()} is not modifiable.
*/
public void testGetPermissions() {
SimpleAclEntry acl = new SimpleAclEntry("", new NamedEntityObjectIdentity("x", "x"), null, 0);
int[] permissions = acl.getValidPermissions();
int i = permissions[0];
permissions[0] -= 100;
assertEquals("Value returned by getValidPermissions can be modified", i, acl.getValidPermissions()[0]);
}
}
@@ -190,7 +190,8 @@ public class HttpSessionContextIntegrationFilterTests extends TestCase {
// Prepare filter
HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
filter.setContext(SecurityContextImpl.class);
filter.afterPropertiesSet();
// don't call afterPropertiesSet to test case when not instantiated by Spring
//filter.afterPropertiesSet();
// Execute filter
executeFilterInContainerSimulator(new MockFilterConfig(), filter, request, response, chain);
@@ -89,7 +89,7 @@ public class MethodInvocationPrivilegeEvaluatorTests extends TestCase {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_LOWER")});
MethodInvocation mi = MethodInvocationUtils.createFromClass(ITargetObject.class, "makeLowerCase",
new Class[] {String.class});
new Class[] {String.class}, new Object[] {"Hello world"});
MethodSecurityInterceptor interceptor = makeSecurityInterceptor();
MethodInvocationPrivilegeEvaluator mipe = new MethodInvocationPrivilegeEvaluator();
@@ -118,7 +118,7 @@ public class MethodInvocationPrivilegeEvaluatorTests extends TestCase {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_NOT_HELD")});
MethodInvocation mi = MethodInvocationUtils.createFromClass(ITargetObject.class, "makeLowerCase",
new Class[] {String.class});
new Class[] {String.class}, new Object[] {"helloWorld"});
MethodSecurityInterceptor interceptor = makeSecurityInterceptor();
MethodInvocationPrivilegeEvaluator mipe = new MethodInvocationPrivilegeEvaluator();
@@ -0,0 +1,82 @@
/* Copyright 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.intercept.web;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.SecurityConfig;
import junit.framework.TestCase;
/**
* Test for {@link FilterInvocationDefinitionDecorator}
*
* @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
* @version $Id$
*/
public class FilterInvocationDefinitionDecoratorTest extends TestCase {
private FilterInvocationDefinitionDecorator decorator;
private FilterInvocationDefinition decorated;
protected void setUp() throws Exception {
super.setUp();
decorated = new MockFilterInvocationDefinition();
decorator = new FilterInvocationDefinitionDecorator(decorated);
}
public void testFilterInvocationDefinitionMapDecorator() {
decorator = new FilterInvocationDefinitionDecorator();
decorator.setDecorated(decorated);
assertEquals(decorated, decorator.getDecorated());
}
public void testSetMappings() {
List roles = new ArrayList();
roles.add("ROLE_USER");
roles.add("ROLE_ADMIN");
FilterInvocationDefinitionSourceMapping mapping = new FilterInvocationDefinitionSourceMapping();
mapping.setUrl("/secure/**");
mapping.setConfigAttributes(roles);
List mappings = new ArrayList();
mappings.add(mapping);
decorator.setMappings(mappings);
ConfigAttributeDefinition configDefinition = new ConfigAttributeDefinition();
Iterator it = roles.iterator();
while (it.hasNext()) {
String role = (String) it.next();
configDefinition.addConfigAttribute(new SecurityConfig(role));
}
it = decorator.getConfigAttributeDefinitions();
int i = 0;
while (it.hasNext()) {
i++;
assertEquals(configDefinition, it.next());
}
assertEquals(1, i);
assertEquals(mappings, decorator.getMappings());
}
}
@@ -30,17 +30,16 @@ import org.acegisecurity.MockAuthenticationManager;
import org.acegisecurity.MockRunAsManager;
import org.acegisecurity.RunAsManager;
import org.acegisecurity.SecurityConfig;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
@@ -231,6 +230,33 @@ public class FilterSecurityInterceptorTests extends TestCase {
SecurityContextHolder.clearContext();
}
public void testNotLoadedFromApplicationContext() throws Exception {
FilterInvocationDefinitionSourceMapping mapping = new FilterInvocationDefinitionSourceMapping();
mapping.setUrl("/secure/**");
mapping.addConfigAttribute("ROLE_USER");
List mappings = new ArrayList(1);
mappings.add(mapping);
PathBasedFilterInvocationDefinitionMap filterInvocationDefinitionSource = new PathBasedFilterInvocationDefinitionMap();
filterInvocationDefinitionSource
.setConvertUrlToLowercaseBeforeComparison(true);
FilterInvocationDefinitionDecorator decorator = new FilterInvocationDefinitionDecorator(
filterInvocationDefinitionSource);
decorator.setMappings(mappings);
FilterSecurityInterceptor filter = new FilterSecurityInterceptor();
filter.setObjectDefinitionSource(filterInvocationDefinitionSource);
MockFilterChain filterChain = new MockFilterChain();
filterChain.expectToProceed = true;
FilterInvocation fi = new FilterInvocation(
new MockHttpServletRequest(), new MockHttpServletResponse(),
filterChain);
filter.invoke(fi);
}
//~ Inner Classes ==================================================================================================
private class MockFilterChain implements FilterChain {
@@ -0,0 +1,64 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.intercept.web;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.acegisecurity.ConfigAttributeDefinition;
/**
* Mock for {@link FilterInvocationDefinitionMap}
*
* @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
* @version $Id: MockFilterInvocationDefinitionSource.java 1496 2006-05-23
* 13:38:33Z benalex $
*/
public class MockFilterInvocationDefinition implements FilterInvocationDefinition {
private Map secureUrls = new HashMap();
private boolean convertUrlToLowercaseBeforeComparison = false;
public void addSecureUrl(String expression, ConfigAttributeDefinition attr) {
secureUrls.put(expression, attr);
}
public boolean isConvertUrlToLowercaseBeforeComparison() {
return convertUrlToLowercaseBeforeComparison;
}
public void setConvertUrlToLowercaseBeforeComparison(boolean convertUrlToLowercaseBeforeComparison) {
this.convertUrlToLowercaseBeforeComparison = convertUrlToLowercaseBeforeComparison;
}
public ConfigAttributeDefinition getSecureUrl(String expression) {
return (ConfigAttributeDefinition) secureUrls.get(expression);
}
public ConfigAttributeDefinition getAttributes(Object object) throws IllegalArgumentException {
return (ConfigAttributeDefinition) secureUrls.get(object);
}
public Iterator getConfigAttributeDefinitions() {
return secureUrls.values().iterator();
}
public boolean supports(Class clazz) {
return true;
}
}
@@ -24,7 +24,7 @@ import java.util.Vector;
/**
* DOCUMENT ME!
* Mock for {@link FilterInvocationDefinitionSource}
*
* @author Ben Alex
* @version $Id$
@@ -45,14 +45,6 @@ public class PathBasedFilterDefinitionMapTests extends TestCase {
//~ Methods ========================================================================================================
public static void main(String[] args) {
junit.textui.TestRunner.run(PathBasedFilterDefinitionMapTests.class);
}
public final void setUp() throws Exception {
super.setUp();
}
public void testConvertUrlToLowercaseIsFalseByDefault() {
PathBasedFilterInvocationDefinitionMap map = new PathBasedFilterInvocationDefinitionMap();
assertFalse(map.isConvertUrlToLowercaseBeforeComparison());
@@ -73,14 +65,7 @@ public class PathBasedFilterDefinitionMapTests extends TestCase {
def.addConfigAttribute(new SecurityConfig("ROLE_ONE"));
map.addSecureUrl("/secure/super/**", def);
// Build a HTTP request
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI(null);
MockHttpServletRequest req = request;
req.setServletPath("/SeCuRE/super/somefile.html");
FilterInvocation fi = new FilterInvocation(req, new MockHttpServletResponse(), new MockFilterChain());
FilterInvocation fi = createFilterinvocation("/SeCuRE/super/somefile.html");
ConfigAttributeDefinition response = map.lookupAttributes(fi.getRequestUrl());
assertEquals(def, response);
@@ -94,14 +79,7 @@ public class PathBasedFilterDefinitionMapTests extends TestCase {
def.addConfigAttribute(new SecurityConfig("ROLE_ONE"));
map.addSecureUrl("/secure/super/**", def);
// Build a HTTP request
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI(null);
MockHttpServletRequest req = request;
req.setServletPath("/SeCuRE/super/somefile.html");
FilterInvocation fi = new FilterInvocation(req, new MockHttpServletResponse(), new MockFilterChain());
FilterInvocation fi = createFilterinvocation("/SeCuRE/super/somefile.html");
ConfigAttributeDefinition response = map.lookupAttributes(fi.getRequestUrl());
assertEquals(null, response);
@@ -115,14 +93,7 @@ public class PathBasedFilterDefinitionMapTests extends TestCase {
def.addConfigAttribute(new SecurityConfig("ROLE_ONE"));
map.addSecureUrl("/secure/super/**", def);
// Build a HTTP request
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI(null);
MockHttpServletRequest req = request;
req.setServletPath("/secure/super/somefile.html");
FilterInvocation fi = new FilterInvocation(req, new MockHttpServletResponse(), new MockFilterChain());
FilterInvocation fi = createFilterinvocation("/secure/super/somefile.html");
ConfigAttributeDefinition response = map.lookupAttributes(fi.getRequestUrl());
assertEquals(def, response);
@@ -136,16 +107,38 @@ public class PathBasedFilterDefinitionMapTests extends TestCase {
def.addConfigAttribute(new SecurityConfig("ROLE_ONE"));
map.addSecureUrl("/someAdminPage.html**", def);
// Build a HTTP request
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI(null);
MockHttpServletRequest req = request;
req.setServletPath("/someAdminPage.html?a=/test");
FilterInvocation fi = new FilterInvocation(req, new MockHttpServletResponse(), new MockFilterChain());
FilterInvocation fi = createFilterinvocation("/someAdminPage.html?a=/test");
ConfigAttributeDefinition response = map.lookupAttributes(fi.getRequestUrl());
assertEquals(def, response); // see SEC-161 (it should truncate after ? sign)
}
/** Check fixes for SEC-321 */
public void testExtraQuestionMarkStillMatches() {
PathBasedFilterInvocationDefinitionMap map = new PathBasedFilterInvocationDefinitionMap();
assertFalse(map.isConvertUrlToLowercaseBeforeComparison());
ConfigAttributeDefinition def = new ConfigAttributeDefinition();
def.addConfigAttribute(new SecurityConfig("ROLE_ONE"));
map.addSecureUrl("/someAdminPage.html*", def);
FilterInvocation fi = createFilterinvocation("/someAdminPage.html?x=2/aa?y=3");
ConfigAttributeDefinition response = map.lookupAttributes(fi.getRequestUrl());
assertEquals(def, response);
fi = createFilterinvocation("/someAdminPage.html??");
response = map.lookupAttributes(fi.getRequestUrl());
assertEquals(def, response);
}
private FilterInvocation createFilterinvocation(String path) {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI(null);
request.setServletPath(path);
return new FilterInvocation(request, new MockHttpServletResponse(), new MockFilterChain());
}
}
@@ -341,7 +341,7 @@ public class DaoAuthenticationProviderTests extends TestCase {
provider.authenticate(token);
fail("Should have thrown AuthenticationServiceException");
} catch (AuthenticationServiceException expected) {
assertEquals("AuthenticationDao returned null, which is an interface contract violation",
assertEquals("UserDetailsService returned null, which is an interface contract violation",
expected.getMessage());
}
}
@@ -417,10 +417,10 @@ public class DaoAuthenticationProviderTests extends TestCase {
public void testStartupSuccess() throws Exception {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
UserDetailsService dao = new MockAuthenticationDaoUserMarissa();
provider.setUserDetailsService(dao);
UserDetailsService userDetailsService = new MockAuthenticationDaoUserMarissa();
provider.setUserDetailsService(userDetailsService);
provider.setUserCache(new MockUserCache());
assertEquals(dao, provider.getUserDetailsService());
assertEquals(userDetailsService, provider.getUserDetailsService());
provider.afterPropertiesSet();
assertTrue(true);
}
@@ -98,7 +98,7 @@ public class LdapAuthenticationProviderTests extends TestCase {
LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(),
new MockAuthoritiesPopulator());
assertNotNull(ldapProvider.getAuthoritiesPoulator());
assertNotNull(ldapProvider.getAuthoritiesPopulator());
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken("bob", "bobspassword");
UserDetails user = ldapProvider.retrieveUser("bob", authRequest);
@@ -70,26 +70,12 @@ public class RememberMeAuthenticationTokenTests extends TestCase {
assertTrue(true);
}
try {
new RememberMeAuthenticationToken("key", "Test", null);
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
try {
new RememberMeAuthenticationToken("key", "Test", new GrantedAuthority[] {null});
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
try {
new RememberMeAuthenticationToken("key", "Test", new GrantedAuthority[] {});
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
}
public void testEqualsWhenEqual() {
@@ -0,0 +1,430 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.providers.siteminder;
import java.util.HashMap;
import java.util.Map;
import junit.framework.TestCase;
import org.acegisecurity.AccountExpiredException;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationServiceException;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.CredentialsExpiredException;
import org.acegisecurity.DisabledException;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.LockedException;
import org.acegisecurity.providers.TestingAuthenticationToken;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.providers.dao.UserCache;
import org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache;
import org.acegisecurity.providers.dao.cache.NullUserCache;
import org.acegisecurity.userdetails.User;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataRetrievalFailureException;
/**
* Tests {@link SiteminderAuthenticationProvider}.
*
* @author Ben Alex
* @version $Id: SiteminderAuthenticationProviderTests.java 1582 2006-07-15 15:18:51Z smccrory $
*/
public class SiteminderAuthenticationProviderTests extends TestCase {
//~ Methods ========================================================================================================
public static void main(String[] args) {
junit.textui.TestRunner.run(SiteminderAuthenticationProviderTests.class);
}
public final void setUp() throws Exception {
super.setUp();
}
public void testAuthenticateFailsIfAccountExpired() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter", "opal");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserPeterAccountExpired());
provider.setUserCache(new MockUserCache());
try {
provider.authenticate(token);
fail("Should have thrown AccountExpiredException");
} catch (AccountExpiredException expected) {
assertTrue(true);
}
}
public void testAuthenticateFailsIfAccountLocked() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter", "opal");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserPeterAccountLocked());
provider.setUserCache(new MockUserCache());
try {
provider.authenticate(token);
fail("Should have thrown LockedException");
} catch (LockedException expected) {
assertTrue(true);
}
}
public void testAuthenticateFailsIfCredentialsExpired() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter", "opal");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserPeterCredentialsExpired());
provider.setUserCache(new MockUserCache());
try {
provider.authenticate(token);
fail("Should have thrown CredentialsExpiredException");
} catch (CredentialsExpiredException expected) {
assertTrue(true);
}
}
public void testAuthenticateFailsIfUserDisabled() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter", "opal");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserPeter());
provider.setUserCache(new MockUserCache());
try {
provider.authenticate(token);
fail("Should have thrown DisabledException");
} catch (DisabledException expected) {
assertTrue(true);
}
}
public void testAuthenticateFailsWhenUserDetailsServiceHasBackendFailure() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa", "koala");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceSimulateBackendError());
provider.setUserCache(new MockUserCache());
try {
provider.authenticate(token);
fail("Should have thrown AuthenticationServiceException");
} catch (AuthenticationServiceException expected) {
assertTrue(true);
}
}
public void testAuthenticateFailsWithEmptyUsername() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(null, "koala");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserMarissa());
provider.setUserCache(new MockUserCache());
try {
provider.authenticate(token);
fail("Should have thrown BadCredentialsException");
} catch (BadCredentialsException expected) {
assertTrue(true);
}
}
public void testAuthenticateFailsWithInvalidUsernameAndHideUserNotFoundExceptionFalse() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("INVALID_USER", "koala");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setHideUserNotFoundExceptions(false); // we want UsernameNotFoundExceptions
provider.setUserDetailsService(new MockUserDetailsServiceUserMarissa());
provider.setUserCache(new MockUserCache());
try {
provider.authenticate(token);
fail("Should have thrown UsernameNotFoundException");
} catch (UsernameNotFoundException expected) {
assertTrue(true);
}
}
public void testAuthenticateFailsWithInvalidUsernameAndHideUserNotFoundExceptionsWithDefaultOfTrue() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("INVALID_USER", "koala");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
assertTrue(provider.isHideUserNotFoundExceptions());
provider.setUserDetailsService(new MockUserDetailsServiceUserMarissa());
provider.setUserCache(new MockUserCache());
try {
provider.authenticate(token);
fail("Should have thrown BadCredentialsException");
} catch (BadCredentialsException expected) {
assertTrue(true);
}
}
public void testAuthenticateFailsWithMixedCaseUsernameIfDefaultChanged() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("MaRiSSA", "koala");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserMarissa());
provider.setUserCache(new MockUserCache());
try {
provider.authenticate(token);
fail("Should have thrown BadCredentialsException");
} catch (BadCredentialsException expected) {
assertTrue(true);
}
}
public void testAuthenticates() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa", "koala");
token.setDetails("192.168.0.1");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserMarissa());
provider.setUserCache(new MockUserCache());
Authentication result = provider.authenticate(token);
if (!(result instanceof UsernamePasswordAuthenticationToken)) {
fail("Should have returned instance of UsernamePasswordAuthenticationToken");
}
UsernamePasswordAuthenticationToken castResult = (UsernamePasswordAuthenticationToken) result;
assertEquals(User.class, castResult.getPrincipal().getClass());
assertEquals("koala", castResult.getCredentials());
assertEquals("ROLE_ONE", castResult.getAuthorities()[0].getAuthority());
assertEquals("ROLE_TWO", castResult.getAuthorities()[1].getAuthority());
assertEquals("192.168.0.1", castResult.getDetails());
}
public void testAuthenticatesASecondTime() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa", "koala");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserMarissa());
provider.setUserCache(new MockUserCache());
Authentication result = provider.authenticate(token);
if (!(result instanceof UsernamePasswordAuthenticationToken)) {
fail("Should have returned instance of UsernamePasswordAuthenticationToken");
}
// Now try to authenticate with the previous result (with its UserDetails)
Authentication result2 = provider.authenticate(result);
if (!(result2 instanceof UsernamePasswordAuthenticationToken)) {
fail("Should have returned instance of UsernamePasswordAuthenticationToken");
}
assertEquals(result.getCredentials(), result2.getCredentials());
}
public void testAuthenticatesWithForcePrincipalAsString() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa", "koala");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserMarissa());
provider.setUserCache(new MockUserCache());
provider.setForcePrincipalAsString(true);
Authentication result = provider.authenticate(token);
if (!(result instanceof UsernamePasswordAuthenticationToken)) {
fail("Should have returned instance of UsernamePasswordAuthenticationToken");
}
UsernamePasswordAuthenticationToken castResult = (UsernamePasswordAuthenticationToken) result;
assertEquals(String.class, castResult.getPrincipal().getClass());
assertEquals("marissa", castResult.getPrincipal());
}
public void testDetectsNullBeingReturnedFromUserDetailsService() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa", "koala");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceReturnsNull());
try {
provider.authenticate(token);
fail("Should have thrown AuthenticationServiceException");
} catch (AuthenticationServiceException expected) {
assertEquals("UserDetailsService returned null, which is an interface contract violation", expected
.getMessage());
}
}
public void testGettersSetters() {
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserCache(new EhCacheBasedUserCache());
assertEquals(EhCacheBasedUserCache.class, provider.getUserCache().getClass());
assertFalse(provider.isForcePrincipalAsString());
provider.setForcePrincipalAsString(true);
assertTrue(provider.isForcePrincipalAsString());
}
public void testStartupFailsIfNoUserDetailsService() throws Exception {
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
try {
provider.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
}
public void testStartupFailsIfNoUserCacheSet() throws Exception {
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserMarissa());
assertEquals(NullUserCache.class, provider.getUserCache().getClass());
provider.setUserCache(null);
try {
provider.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
}
public void testStartupSuccess() throws Exception {
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
UserDetailsService userDetailsService = new MockUserDetailsServiceUserMarissa();
provider.setUserDetailsService(userDetailsService);
provider.setUserCache(new MockUserCache());
assertEquals(userDetailsService, provider.getUserDetailsService());
provider.afterPropertiesSet();
assertTrue(true);
}
public void testSupports() {
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
assertTrue(provider.supports(UsernamePasswordAuthenticationToken.class));
assertTrue(!provider.supports(TestingAuthenticationToken.class));
}
//~ Inner Classes ==================================================================================================
private class MockUserDetailsServiceReturnsNull implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
return null;
}
}
private class MockUserDetailsServiceSimulateBackendError implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
throw new DataRetrievalFailureException("This mock simulator is designed to fail");
}
}
private class MockUserDetailsServiceUserMarissa implements UserDetailsService {
private String password = "koala";
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
if ("marissa".equals(username)) {
return new User("marissa", password, true, true, true, true, new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO") });
} else {
throw new UsernameNotFoundException("Could not find: " + username);
}
}
public void setPassword(String password) {
this.password = password;
}
}
private class MockUserDetailsServiceUserMarissaWithSalt implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
if ("marissa".equals(username)) {
return new User("marissa", "koala{SYSTEM_SALT_VALUE}", true, true, true, true, new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO") });
} else {
throw new UsernameNotFoundException("Could not find: " + username);
}
}
}
private class MockUserDetailsServiceUserPeter implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
if ("peter".equals(username)) {
return new User("peter", "opal", false, true, true, true, new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO") });
} else {
throw new UsernameNotFoundException("Could not find: " + username);
}
}
}
private class MockUserDetailsServiceUserPeterAccountExpired implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
if ("peter".equals(username)) {
return new User("peter", "opal", true, false, true, true, new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO") });
} else {
throw new UsernameNotFoundException("Could not find: " + username);
}
}
}
private class MockUserDetailsServiceUserPeterAccountLocked implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
if ("peter".equals(username)) {
return new User("peter", "opal", true, true, true, false, new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO") });
} else {
throw new UsernameNotFoundException("Could not find: " + username);
}
}
}
private class MockUserDetailsServiceUserPeterCredentialsExpired implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
if ("peter".equals(username)) {
return new User("peter", "opal", true, true, false, true, new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO") });
} else {
throw new UsernameNotFoundException("Could not find: " + username);
}
}
}
private class MockUserCache implements UserCache {
private Map cache = new HashMap();
public UserDetails getUserFromCache(String username) {
return (User) cache.get(username);
}
public void putUserInCache(UserDetails user) {
cache.put(user.getUsername(), user);
}
public void removeUserFromCache(String username) {
}
}
}
@@ -197,13 +197,13 @@ public class ChannelDecisionManagerImplTests extends TestCase {
Iterator iter = config.getConfigAttributes();
if (failIfCalled) {
fail("Should not have called this channel processor");
fail("Should not have called this channel processor: " + configAttribute);
}
while (iter.hasNext()) {
ConfigAttribute attr = (ConfigAttribute) iter.next();
if (attr.equals(configAttribute)) {
if (attr.getAttribute().equals(configAttribute)) {
invocation.getHttpResponse().sendRedirect("/redirected");
return;
@@ -70,6 +70,7 @@ public class AbstractProcessingFilterTests extends TestCase {
request.setScheme("http");
request.setServerName("www.example.com");
request.setRequestURI("/mycontext/j_mock_post");
request.setContextPath("/mycontext");
return request;
}
@@ -154,27 +155,27 @@ public class AbstractProcessingFilterTests extends TestCase {
// Setup our test object, to deny access
MockAbstractProcessingFilter filter = new MockAbstractProcessingFilter(false);
filter.setAuthenticationFailureUrl("/myApp/failed.jsp");
filter.setAuthenticationFailureUrl("/failed.jsp");
// Test
executeFilterInContainerSimulator(config, filter, request, response, chain);
assertEquals("/myApp/failed.jsp", response.getRedirectedUrl());
assertEquals("/mycontext/failed.jsp", response.getRedirectedUrl());
assertNull(SecurityContextHolder.getContext().getAuthentication());
//Prepare again, this time using the exception mapping
filter = new MockAbstractProcessingFilter(new AccountExpiredException("You're account is expired"));
filter.setAuthenticationFailureUrl("/myApp/failed.jsp");
filter.setAuthenticationFailureUrl("/failed.jsp");
Properties exceptionMappings = filter.getExceptionMappings();
exceptionMappings.setProperty(AccountExpiredException.class.getName(), "/myApp/accountExpired.jsp");
exceptionMappings.setProperty(AccountExpiredException.class.getName(), "/accountExpired.jsp");
filter.setExceptionMappings(exceptionMappings);
response = new MockHttpServletResponse();
// Test
executeFilterInContainerSimulator(config, filter, request, response, chain);
assertEquals("/myApp/accountExpired.jsp", response.getRedirectedUrl());
assertEquals("/mycontext/accountExpired.jsp", response.getRedirectedUrl());
assertNull(SecurityContextHolder.getContext().getAuthentication());
}
@@ -199,7 +200,7 @@ public class AbstractProcessingFilterTests extends TestCase {
// Test
executeFilterInContainerSimulator(config, filter, request, response, chain);
assertEquals("/logged_in.jsp", response.getRedirectedUrl());
assertEquals("/mycontext/logged_in.jsp", response.getRedirectedUrl());
assertNotNull(SecurityContextHolder.getContext().getAuthentication());
assertEquals("test", SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
}
@@ -226,6 +227,19 @@ public class AbstractProcessingFilterTests extends TestCase {
assertEquals("/fail", filter.getAuthenticationFailureUrl());
}
public void testDefaultUrlMuststartWithSlashOrHttpScheme() {
AbstractProcessingFilter filter = new MockAbstractProcessingFilter();
filter.setDefaultTargetUrl("/acceptableRelativeUrl");
filter.setDefaultTargetUrl("http://some.site.org/index.html");
filter.setDefaultTargetUrl("https://some.site.org/index.html");
try {
filter.setDefaultTargetUrl("missingSlash");
fail("Shouldn't accept default target without leading slash");
} catch (IllegalArgumentException expected) {}
}
public void testIgnoresAnyServletPathOtherThanFilterProcessesUrl()
throws Exception {
// Setup our HTTP request
@@ -269,7 +283,7 @@ public class AbstractProcessingFilterTests extends TestCase {
// Test
executeFilterInContainerSimulator(config, filter, request, response, chain);
assertEquals("/logged_in.jsp", response.getRedirectedUrl());
assertEquals("/mycontext/logged_in.jsp", response.getRedirectedUrl());
assertNotNull(SecurityContextHolder.getContext().getAuthentication());
assertEquals("test", SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
}
@@ -354,7 +368,7 @@ public class AbstractProcessingFilterTests extends TestCase {
// Test
executeFilterInContainerSimulator(config, filter, request, response, chain);
assertEquals("/logged_in.jsp", response.getRedirectedUrl());
assertEquals("/mycontext/logged_in.jsp", response.getRedirectedUrl());
assertNotNull(SecurityContextHolder.getContext().getAuthentication());
assertEquals("test", SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
@@ -397,7 +411,7 @@ public class AbstractProcessingFilterTests extends TestCase {
// Test
executeFilterInContainerSimulator(config, filter, request, response, chain);
assertEquals("/foobar", response.getRedirectedUrl());
assertEquals("/mycontext/foobar", response.getRedirectedUrl());
assertNotNull(SecurityContextHolder.getContext().getAuthentication());
}
@@ -424,6 +438,27 @@ public class AbstractProcessingFilterTests extends TestCase {
assertNotNull(SecurityContextHolder.getContext().getAuthentication());
}
/**
* SEC-297 fix.
*/
public void testFullDefaultTargetUrlDoesNotHaveContextPathPrepended() throws Exception {
MockHttpServletRequest request = createMockRequest();
MockFilterConfig config = new MockFilterConfig(null, null);
MockFilterChain chain = new MockFilterChain(true);
MockHttpServletResponse response = new MockHttpServletResponse();
// Setup our test object, to grant access
MockAbstractProcessingFilter filter = new MockAbstractProcessingFilter(true);
filter.setFilterProcessesUrl("/j_mock_post");
filter.setDefaultTargetUrl("http://monkeymachine.co.uk/");
filter.setAlwaysUseDefaultTargetUrl(true);
executeFilterInContainerSimulator(config, filter, request, response, chain);
assertEquals("http://monkeymachine.co.uk/", response.getRedirectedUrl());
assertNotNull(SecurityContextHolder.getContext().getAuthentication());
}
//~ Inner Classes ==================================================================================================
private class MockAbstractProcessingFilter extends AbstractProcessingFilter {
@@ -5,7 +5,7 @@ import junit.framework.TestCase;
import javax.servlet.http.Cookie;
import java.io.Serializable;
public class SavedCookieTest extends TestCase {
public class SavedCookieTests extends TestCase {
Cookie cookie;
SavedCookie savedCookie;
@@ -0,0 +1,22 @@
package org.acegisecurity.ui.savedrequest;
import junit.framework.TestCase;
import org.acegisecurity.MockPortResolver;
import org.springframework.mock.web.MockHttpServletRequest;
public class SavedRequestTests extends TestCase {
public void testCaseInsensitveHeaders() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("USER-aGenT", "Mozilla");
SavedRequest saved = new SavedRequest(request, new MockPortResolver(8080, 8443));
assertEquals("Mozilla", saved.getHeaderValues("user-agent").next());
}
public void testCaseInsensitveParameters() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addParameter("ThisIsATest", "Hi mom");
SavedRequest saved = new SavedRequest(request, new MockPortResolver(8080, 8443));
assertEquals("Hi mom", saved.getParameterValues("thisisatest")[0]);
}
}
@@ -19,13 +19,10 @@ import junit.framework.TestCase;
import org.acegisecurity.Authentication;
import org.acegisecurity.MockAuthenticationManager;
import org.acegisecurity.ui.WebAuthenticationDetails;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
/**
* Tests SiteminderAuthenticationProcessingFilter.
*
@@ -36,18 +33,18 @@ import org.springframework.mock.web.MockHttpServletResponse;
public class SiteminderAuthenticationProcessingFilterTests extends TestCase {
//~ Constructors ===================================================================================================
/**
* Basic constructor.
*/
/**
* Basic constructor.
*/
public SiteminderAuthenticationProcessingFilterTests() {
super();
}
/**
* Argument constructor.
*
* @param arg0
*/
/**
* Argument constructor.
*
* @param arg0
*/
public SiteminderAuthenticationProcessingFilterTests(String arg0) {
super(arg0);
}
@@ -86,21 +83,15 @@ public class SiteminderAuthenticationProcessingFilterTests extends TestCase {
filter.setContinueChainBeforeSuccessfulAuthentication(true);
assertTrue(filter.isContinueChainBeforeSuccessfulAuthentication());
filter.setDefaultTargetUrl("bar");
assertEquals("bar", filter.getDefaultTargetUrl());
filter.setDefaultTargetUrl("/bar");
assertEquals("/bar", filter.getDefaultTargetUrl());
filter.setFilterProcessesUrl("foobar");
assertEquals("foobar", filter.getFilterProcessesUrl());
filter.setFormPasswordParameterKey("passwordParamKey");
assertEquals("passwordParamKey", filter.getFormPasswordParameterKey());
filter.setFormUsernameParameterKey("usernameParamKey");
assertEquals("usernameParamKey", filter.getFormUsernameParameterKey());
filter.setSiteminderPasswordHeaderKey("passwordHeaderKey");
assertEquals("passwordHeaderKey", filter.getSiteminderPasswordHeaderKey());
filter.setSiteminderUsernameHeaderKey("usernameHeaderKey");
assertEquals("usernameHeaderKey", filter.getSiteminderUsernameHeaderKey());
}
@@ -131,8 +122,7 @@ public class SiteminderAuthenticationProcessingFilterTests extends TestCase {
*
* @throws Exception
*/
public void testFormNullPasswordHandledGracefully()
throws Exception {
public void testFormNullPasswordHandledGracefully() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addParameter(SiteminderAuthenticationProcessingFilter.ACEGI_SECURITY_FORM_USERNAME_KEY, "marissa");
@@ -151,8 +141,7 @@ public class SiteminderAuthenticationProcessingFilterTests extends TestCase {
*
* @throws Exception
*/
public void testFormNullUsernameHandledGracefully()
throws Exception {
public void testFormNullUsernameHandledGracefully() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addParameter(SiteminderAuthenticationProcessingFilter.ACEGI_SECURITY_FORM_PASSWORD_KEY, "koala");
@@ -186,7 +175,6 @@ public class SiteminderAuthenticationProcessingFilterTests extends TestCase {
filter.setAuthenticationManager(authMgrThatGrantsAccess);
filter.setSiteminderUsernameHeaderKey("SM_USER");
filter.setSiteminderPasswordHeaderKey("SM_USER");
filter.init(null);
// Requests for an unknown URL should NOT require (re)authentication
@@ -220,7 +208,6 @@ public class SiteminderAuthenticationProcessingFilterTests extends TestCase {
SiteminderAuthenticationProcessingFilter filter = new SiteminderAuthenticationProcessingFilter();
filter.setAuthenticationManager(authMgr);
filter.setSiteminderUsernameHeaderKey("SM_USER");
filter.setSiteminderPasswordHeaderKey("SM_USER");
filter.init(null);
Authentication result = filter.attemptAuthentication(request);
@@ -79,4 +79,17 @@ public class LdapUserDetailsMapperTests extends TestCase {
assertEquals(0, user.getGrantedAuthorities().length);
}
public void testPasswordAttributeIsMappedCorrectly() throws Exception {
LdapUserDetailsMapper mapper = new LdapUserDetailsMapper();
mapper.setPasswordAttributeName("myappsPassword");
BasicAttributes attrs = new BasicAttributes();
attrs.put(new BasicAttribute("myappsPassword", "mypassword".getBytes()));
LdapUserDetails user =
((LdapUserDetailsImpl.Essence) mapper.mapAttributes("cn=someName", attrs)).createUserDetails();
assertEquals("mypassword", user.getPassword());
}
}
@@ -0,0 +1,109 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.util;
import junit.framework.TestCase;
import org.acegisecurity.util.EncryptionUtils.EncryptionException;
/**
* JUnit tests for EncryptionUtils.
*
* @author Alan Stewart
* @author Ben Alex
* @version $Id$
*/
public class EncryptionUtilsTests extends TestCase {
private final static String STRING_TO_ENCRYPT = "Alan K Stewart";
private final static String ENCRYPTION_KEY = "123456789012345678901234567890";
public void testEncryptsUsingDESEde() throws EncryptionException {
final String encryptedString = EncryptionUtils.encrypt(ENCRYPTION_KEY, STRING_TO_ENCRYPT);
assertEquals("3YIE8sIbaEoqGZZrHamFGQ==", encryptedString);
}
public void testEncryptionKeyCanContainLetters() throws EncryptionException {
final String encryptedString = EncryptionUtils.encrypt("ASDF asdf 1234 8983 jklasdf J2Jaf8", STRING_TO_ENCRYPT);
assertEquals("v4+DQoClx6qm5tJwBcRrkw==", encryptedString);
}
public void testDecryptsUsingDESEde() throws EncryptionException {
final String encryptedString = "3YIE8sIbaEoqGZZrHamFGQ==";
final String decryptedString = EncryptionUtils.decrypt(ENCRYPTION_KEY, encryptedString);
assertEquals(STRING_TO_ENCRYPT, decryptedString);
}
public void testCantEncryptWithNullEncryptionKey() throws EncryptionException {
try {
EncryptionUtils.encrypt(null, "");
fail("Should have thrown IAE");
} catch (final IllegalArgumentException e) {
assertTrue(true);
}
}
public void testCantEncryptWithEmptyEncryptionKey() throws EncryptionException {
try {
EncryptionUtils.encrypt("", "");
fail("Should have thrown IAE");
} catch (final IllegalArgumentException e) {
assertTrue(true);
}
}
public void testCantEncryptWithShortEncryptionKey() throws EncryptionException {
try {
EncryptionUtils.encrypt("01234567890123456789012", "");
fail("Should have thrown IAE");
} catch (final IllegalArgumentException e) {
assertTrue(true);
}
}
public void testCantDecryptWithEmptyString() throws EncryptionException {
try {
EncryptionUtils.decrypt(ENCRYPTION_KEY, "");
fail("Should have thrown IAE");
} catch (final IllegalArgumentException e) {
assertTrue(true);
}
}
public void testCantEncryptWithEmptyString() throws EncryptionException {
try {
EncryptionUtils.encrypt(ENCRYPTION_KEY, "");
fail("Should have thrown IAE");
} catch (final IllegalArgumentException e) {
assertTrue(true);
}
}
public void testCantEncryptWithNullString() throws EncryptionException {
try {
EncryptionUtils.encrypt(ENCRYPTION_KEY, null);
fail("Should have thrown IAE");
} catch (final IllegalArgumentException e) {
assertTrue(true);
}
}
public void testEncryptAndDecrypt() throws EncryptionException {
final String stringToEncrypt = "Alan Stewart";
final String encryptedString = EncryptionUtils.encrypt(ENCRYPTION_KEY, stringToEncrypt);
final String decryptedString = EncryptionUtils.decrypt(ENCRYPTION_KEY, encryptedString);
assertEquals(stringToEncrypt, decryptedString);
}
}
@@ -21,23 +21,17 @@ import org.acegisecurity.AuthorizationServiceException;
import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.MockAclManager;
import org.acegisecurity.SecurityConfig;
import org.acegisecurity.acl.AclEntry;
import org.acegisecurity.acl.AclManager;
import org.acegisecurity.acl.basic.MockAclObjectIdentity;
import org.acegisecurity.acl.basic.SimpleAclEntry;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.util.SimpleMethodInvocation;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.JoinPoint;
import java.lang.reflect.Method;
/**
* Tests {@link BasicAclEntryVoter}.
*
@@ -451,6 +445,40 @@ public class BasicAclEntryVoterTests extends TestCase {
}
}
public void testSetRequirePermissionFromString() {
assertPermission("NOTHING", SimpleAclEntry.NOTHING);
assertPermission("ADMINISTRATION", SimpleAclEntry.ADMINISTRATION);
assertPermission("READ", SimpleAclEntry.READ);
assertPermission("WRITE", SimpleAclEntry.WRITE);
assertPermission("CREATE", SimpleAclEntry.CREATE);
assertPermission("DELETE", SimpleAclEntry.DELETE);
assertPermission(new String[] { "WRITE", "CREATE" }, new int[] { SimpleAclEntry.WRITE, SimpleAclEntry.CREATE });
}
public void testSetRequirePermissionFromStringWrongValues() {
BasicAclEntryVoter voter = new BasicAclEntryVoter();
try {
voter.setRequirePermissionFromString(new String[] { "X" });
fail(IllegalArgumentException.class.getName() + " must have been thrown.");
} catch (IllegalArgumentException e) {
// expected
}
}
private void assertPermission(String text, int value) {
assertPermission(new String[] { text }, new int[] { value });
}
private void assertPermission(String[] text, int[] value) {
BasicAclEntryVoter voter = new BasicAclEntryVoter();
voter.setRequirePermissionFromString(text);
assertEquals("Test incorreclty coded", value.length, text.length);
assertEquals(value.length, voter.getRequirePermission().length);
for (int i = 0; i < value.length; i++) {
assertEquals(value[i], voter.getRequirePermission()[i]);
}
}
//~ Inner Classes ==================================================================================================
private class MockAclEntry implements AclEntry {
+50 -64
View File
@@ -26,7 +26,7 @@
<subtitle>Reference Documentation</subtitle>
<releaseinfo>1.0.0</releaseinfo>
<releaseinfo>1.0.2</releaseinfo>
<authorgroup>
<author>
@@ -117,19 +117,6 @@
<chapter id="introduction">
<title>Introduction</title>
<sect1 id="before-you-begin">
<title>Before You Begin</title>
<para>For your security, each official release JAR of Acegi Security
has been signed by the project leader. This does not in any way alter
the liability disclaimer contained in the License, but it does ensure
you are using a properly reviewed, official build of Acegi Security.
Please refer to the <literal>readme.txt</literal> file in the root of
the release distribution for instructions on how to validate the JARs
are correctly signed, and which certificate has been used to sign
them.</para>
</sect1>
<sect1 id="what-is-acegi-security">
<title>What is Acegi Security?</title>
@@ -1307,6 +1294,15 @@ if (obj instanceof UserDetails) {
wired up by default to many Acegi Security beans. Please refer to the
JavaDocs for <literal>PortResolverImpl</literal> for further
details.</para>
<para>You should note that using a secure channel is recommended if
usernames and passwords are to be kept secure during the login
process. If you do decide to use
<literal>ChannelProcessingFilter</literal> with form-based login,
please ensure that your login page is set to
<literal>REQUIRES_SECURE_CHANNEL</literal>, and that the
<literal>AuthenticationProcessingFilterEntryPoint.forceHttps</literal>
property is <literal>true</literal>.</para>
</sect1>
<sect1 id="channel-security-conclusion">
@@ -1373,7 +1369,7 @@ if (obj instanceof UserDetails) {
<literal>web.xml</literal>:</para>
<para><programlisting>&lt;taglib&gt;
&lt;taglib-uri&gt;http://acegisecurity.sf.net/authz&lt;/taglib-uri&gt;
&lt;taglib-uri&gt;http://acegisecurity.org/authz&lt;/taglib-uri&gt;
&lt;taglib-location&gt;/WEB-INF/authz.tld&lt;/taglib-location&gt;
&lt;/taglib&gt; </programlisting></para>
</sect1>
@@ -1420,7 +1416,7 @@ if (obj instanceof UserDetails) {
this:</para>
<para><programlisting>&lt;filter&gt;
&lt;filter-name&gt;Acegi HTTP Request Security Filter&lt;/filter-name&gt;
&lt;filter-name&gt;Acegi Filter Chain Proxy&lt;/filter-name&gt;
&lt;filter-class&gt;org.acegisecurity.util.FilterToBeanProxy&lt;/filter-class&gt;
&lt;init-param&gt;
&lt;param-name&gt;targetClass&lt;/param-name&gt;
@@ -1790,9 +1786,11 @@ if (obj instanceof UserDetails) {
<para>In addition, you will need to add the
<literal>org.acegisecurity.concurrent.ConcurrentSessionFilter</literal>
to your <literal>FilterChainProxy</literal>. The
ConcurrentSessionFilter requires only one property,
ConcurrentSessionFilter requires two properties,
<literal>sessionRegistry</literal>, which generally points to an
instance of <literal>SessionRegistryImpl</literal>.</para>
instance of <literal>SessionRegistryImpl</literal>, and
<literal>expiredUrl</literal>, which points to the page to display
when a session has expired.</para>
<para>The <literal>web.xml</literal>
<literal>HttpSessionEventPublisher</literal> causes an
@@ -2120,7 +2118,8 @@ if (obj instanceof UserDetails) {
Associates.</para>
<para>Acegi Security provides a filter,
<literal>SiteminderAuthenticationProcessingFilter</literal>) that can
<literal>SiteminderAuthenticationProcessingFilter</literal> and
provider, <literal>SiteminderAuthenticationProvider</literal> that can
be used to process requests that have been pre-authenticated by
Siteminder. This filter assumes that you're using Siteminder for
<emphasis>authentication</emphasis>, and that you're using Acegi
@@ -2128,13 +2127,14 @@ if (obj instanceof UserDetails) {
for <emphasis>authorization</emphasis> is not yet directly supported
by Acegi Security.</para>
<para>In Siteminder, an agent is setup on your web server to intercept
a principal's first call to your application. The agent redirect the
web request to a single sign on login page, and then your application
receives the request. Inside the HTTP headers is a header - such as
<literal>SM_USER</literal> - which identifies the authenticated
principal. Please refer to your organization's "single sign-on" group
for header details in your particular configuration.</para>
<para>When using Siteminder, an agent is setup on your web server to
intercept a principal's first call to your application. The agent
redirects the web request to a single sign-on login page, and once
authenticated, your application receives the request. Inside the HTTP
request is a header - such as <literal>SM_USER</literal> - which
identifies the authenticated principal (please refer to your
organization's "single sign-on" group for header details in your
particular configuration).</para>
</sect1>
<sect1 id="siteminder-config">
@@ -2142,9 +2142,9 @@ if (obj instanceof UserDetails) {
<para>The first step in setting up Acegi Security's Siteminder support
is to define the authentication mechanism that will inspect the HTTP
header discussed earlier. It will then generate a
<literal>UsernamePasswordAuthenticationToken</literal> that can later
on be sent to the <literal>DaoAuthenticationProvider</literal>. Let's
header discussed earlier. It will be responsible for generating a
<literal>UsernamePasswordAuthenticationToken</literal> that is later
sent to the <literal>SiteminderAuthenticationProvider</literal>. Let's
look at an example:</para>
<para><programlisting>&lt;bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.SiteminderAuthenticationProcessingFilter"&gt;
@@ -2153,51 +2153,37 @@ if (obj instanceof UserDetails) {
&lt;property name="defaultTargetUrl"&gt;&lt;value&gt;/security.do?method=getMainMenu&lt;/value&gt;&lt;/property&gt;
&lt;property name="filterProcessesUrl"&gt;&lt;value&gt;/j_acegi_security_check&lt;/value&gt;&lt;/property&gt;
&lt;property name="siteminderUsernameHeaderKey"&gt;&lt;value&gt;SM_USER&lt;/value&gt;&lt;/property&gt;
&lt;property name="siteminderPasswordHeaderKey"&gt;&lt;value&gt;SM_USER&lt;/value&gt;&lt;/property&gt;
&lt;property name="formUsernameParameterKey"&gt;&lt;value&gt;j_username&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;</programlisting></para>
<para>In our example above, the bean is being provided an
<literal>AuthenticationManager</literal>, as is normally needed by
authentication mechanisms. Several URLs are also specified, with the
values being self-explanatory. It's important to also specify the HTTP
headers that Acegi Security should inspect. Most people won't need the
password value since Siteminder has already authenticated the user, so
it's typical to use the same header for both.</para>
header that Acegi Security should inspect. If you additionally want to
support form-based authentication (i.e. in your development
environment where Siteminder is not installed), specify the form's
username parameter as well - just don't do this in production!</para>
<para>Note that you'll need a
<literal><literal>DaoAuthenticationProvider</literal></literal>
<literal><literal>SiteminderAuthenticationProvider</literal></literal>
configured against your <literal>ProviderManager</literal> in order to
use the Siteminder authentication mechanism. Normally a
<literal>DaoAuthenticationProvider</literal> expects the password
use the Siteminder authentication mechanism. Normally an
<literal>AuthenticationProvider</literal> expects the password
property to match what it retrieves from the
<literal>UserDetailsSource</literal>. In this case, authentication has
already been handled by Siteminder and you've specified the same HTTP
header for both username and password. As such, you must modify the
code of <literal>DaoAuthenticationProvider</literal> to simply make
sure the username and password values match. This may sound like a
security weakness, but remember that users have to authenticate with
Siteminder before your application ever receives the requests, so the
purpose of your custom <literal>DaoAuthenticationProvider</literal>
should simply be to build the complete
<literal>Authentication</literal> object (ie with suitable
<literal>UserDetailsSource</literal>, but in this case, authentication
has already been handled by Siteminder, so password property is not
even relevant. This may sound like a security weakness, but remember
that users have to authenticate with Siteminder before your
application ever receives the requests, so the purpose of your custom
<literal>UserDetailsService</literal> should simply be to build the
complete <literal>Authentication</literal> object (ie with suitable
<literal>GrantedAuthority[]</literal>s).</para>
<para>Advanced tip and word to the wise: the
<literal>SiteminderAuthenticationProcessingFilter</literal> actually
extends <literal>AuthenticationProcessingFilter</literal> and thus
additionally supports form validation. If you configure the filter to
support both, and code your
<literal>daoAuthenticationProvider</literal> to match the username and
passwords as described above, you'll potentially defeat any security
you have in place if the web server's Siteminder agent is deactivated.
Don't do this, especially in production!</para>
<para>TODO: We should write a dedicated
<literal>AuthenticationProvider</literal> rather than require users to
modify their <literal>DaoAuthenticationProvider</literal>. Also review
the mixed use of SiteminderAuthenticationProcessingFilter, as it's
inconsistent with the rest of Acegi Security's authentication
mechanisms which are high cohesion.</para>
<para>Advanced tip and word to the wise: If you additionally want to
support form-based authentication in your development environment
(where Siteminder is typically not installed), specify the form's
username parameter as well. Just don't do this in production!</para>
</sect1>
</chapter>
@@ -3140,14 +3126,14 @@ key: A private key to prevent modification of the remember-me token
<para>A typical configuration, using some of the beans we've discussed
above, might look like this: <programlisting>
&lt;bean id="initialDirContextFactory"
class="org.acegisecurity.providers.ldap.DefaultInitialDirContextFactory"&gt;
class="org.acegisecurity.ldap.DefaultInitialDirContextFactory"&gt;
&lt;constructor-arg value="ldap://monkeymachine:389/dc=acegisecurity,dc=org"/&gt;
&lt;property name="managerDn"&gt;&lt;value&gt;cn=manager,dc=acegisecurity,dc=org&lt;/value&gt;&lt;/property&gt;
&lt;property name="managerPassword"&gt;&lt;value&gt;password&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="userSearch"
class="org.acegisecurity.providers.ldap.search.FilterBasedLdapUserSearch"&gt;
class="org.acegisecurity.ldap.search.FilterBasedLdapUserSearch"&gt;
&lt;constructor-arg index="0"&gt;
&lt;value&gt;&lt;/value&gt;
&lt;/constructor-arg&gt;
+8
View File
@@ -9,6 +9,14 @@
<version>1.1.0-SNAPSHOT</version>
</parent>
<artifactId>acegi-security-doc</artifactId>
<!-- repeated here to avoid appending the artifactId -->
<scm>
<connection>scm:svn:https://svn.sourceforge.net/svnroot/acegisecurity/trunk/acegisecurity</connection>
<developerConnection>scm:svn:https://svn.sourceforge.net/svnroot/acegisecurity/trunk/acegisecurity</developerConnection>
<url>http://svn.sourceforge.net/viewcvs.cgi/acegisecurity/trunk/acegisecurity/</url>
</scm>
<dependencies>
</dependencies>
</project>
+4 -1
View File
@@ -37,6 +37,9 @@
<li><b><a href="mail-lists.html">Acegi Security Mailing Lists</a></b>:
If you'd like to discuss development of the project.<br><br>
</li>
<li><b><a href="powering.html">Numerous frameworks using Acegi Security</a></b>:
Look here first for how to integrate with major third-party frameworks...<br><br>
</li>
<li><b><a href="http://weblog.morosystems.cz/spring/Spring-Acegi-JCaptcha-integration">Acegi Security and Captcha Layer</a></b>:
How to use Acegi Security with JCaptcha.<br><br>
</li>
@@ -115,7 +118,7 @@
Matt Raible is including Acegi Security in Chapter 12 of his popular ebook.<br><br>
</li>
<li><b><a href="http://www.china-pub.com/computers/common/info.asp?id=24483">Mastering Spring (Chinese) Book</a></b>:
Acegi Security is included in Chapter 6 of this book.<br><br>
Acegi Security is included in Chapter 17 of this book.<br><br>
</li>
<li><b><a href="http://www.manning.com/walls2">Spring In Action</a></b>:
Craig Walls has also written another popular Spring book, which includes Acegi Security in Chapter 11.<br><br>
+1 -1
View File
@@ -39,7 +39,7 @@
<p>Often people reading this document just want to see if Acegi Security will work
for their projects. They want to deploy a sample application, and that's about it
(after all, all the reference documentation can be read online at
<a href="http://acegisecurity.sourceforge.net">http://acegisecurity.sourceforge.net</a>).
<a href="http://acegisecurity.org">http://acegisecurity.org</a>).
In this case, execute:</p>
<ol>
<pre>cd $ACEGI_SECURITY/core (or cd %ACEGI_SECURITY%/core on Windows)</pre>
+1 -1
View File
@@ -53,7 +53,7 @@
<item name="Contacts HTTPS" href="multiproject/acegi-security-sample-contacts/ssl/howto.txt"/>
<item name="Project Policies" href="policies.html"/>
<item name="Acegi Security JIRA" href="http://opensource.atlassian.com/projects/spring/secure/BrowseProject.jspa?id=10040"/>
<item name="Blog" href="http://blog.springframework.com/ben.alex/"/>
<item name="Blog" href="http://blog.interface21.com/main/author/bena/"/>
</menu>
<menu name="Projects">

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