1
0
mirror of synced 2026-07-09 12:50:19 +00:00

Compare commits

...

139 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
Luke Taylor a2c3635d78 Moved class to test treee 2006-06-15 00:41:53 +00:00
Luke Taylor 552c275e8f Accidentally checked into source tree rather than test source 2006-06-15 00:37:18 +00:00
Luke Taylor aaf51c4bee Added test for non-String role. 2006-06-14 23:20:51 +00:00
Luke Taylor 49da801096 SEC-303: Check from null role attribute in LdapUserDetailsMapper 2006-06-14 22:44:39 +00:00
Luke Taylor eb3e954ae4 Added chained append call in toString method 2006-06-14 21:46:21 +00:00
Luke Taylor b0caa72e80 Added template method for role creation, as requested in the forum. 2006-06-13 13:18:45 +00:00
Luke Taylor 7475906218 Remove Javadoc errors 2006-06-12 22:32:59 +00:00
Luke Taylor 18680e8fab Remove Jalopy mistakes 2006-06-12 22:31:10 +00:00
Ray Krueger cada23f57d Synchronized MockFilterConfig uses for Spring 1.2.6 and 1.2.8 2006-06-11 01:20:29 +00:00
Ray Krueger fa3c61b19b Call to getCookies() should return Cookies, not SavedCookies 2006-06-11 01:19:44 +00:00
Luke Taylor 88825089a7 Removed "final" from getGroupMembershipRoles 2006-06-07 13:31:11 +00:00
Luke Taylor 2a7caff95f SEC-295: Changed to use getDefaultTargetUrl() accessor internally rather than accessing property directly. Allows for overriding method to supply different Urls. 2006-06-04 15:14:33 +00:00
Ray Krueger 9fd0bbd694 Added Serializable check just to be sure... 2006-06-03 13:40:39 +00:00
Ray Krueger 1a9629b197 http://opensource.atlassian.com/projects/spring/browse/SEC-289
Wraps disassembles cookies into a SavedCookie that is serializable
2006-06-03 13:36:51 +00:00
Ben Alex f7020755be SEC-291: Avoid unnecessary creation of SecurityContextHolderStrategy. 2006-06-01 14:02:56 +00:00
Luke Taylor da780e4567 Tidy up XML formatting in comment 2006-05-31 21:56:16 +00:00
Luke Taylor 9f41b9f470 Wrap any DataAccessExceptions thrown by the Ldaptemplate with AuthenticationServiceFailureExceptions 2006-05-31 21:46:16 +00:00
Luke Taylor 5d7a75a421 SEC-284: Removed allowEmptyPassword flag.. 2006-05-31 20:12:12 +00:00
Luke Taylor d2ee383e06 Changed to reject empty passwords by default. 2006-05-31 18:22:05 +00:00
Luke Taylor ee50d6e334 SEC-281: Modified to use Spring 1.2 compatible exception class for incorrect search results size. 2006-05-31 16:54:27 +00:00
Luke Taylor 02e7bbb982 SEC-284: added allowEmptyPasswords property with default value "true" 2006-05-31 15:00:59 +00:00
Ben Alex 7957d54d67 SEC-282: Tutorial for securing Petclinic using Acegi Security. 2006-05-31 07:40:45 +00:00
Ray Krueger 00620b6992 http://opensource.atlassian.com/projects/spring/browse/SEC-96
Refactored Digest encoding for better support of all MessageDigest algorithms, such as the SHA family.
2006-05-31 03:03:18 +00:00
Carlos Sanchez 35093e09f6 Bump version to 1.1.0-SNAPSHOT 2006-05-31 00:52:26 +00:00
Scott McCrory 0eab6903e8 SEC-280: Fixed Eclipse classpath to correctly point to Maven's Spring Framework jars 2006-05-30 22:45:22 +00:00
Luke Taylor b6282423e3 Added info on Ldap changes and fixed HTML. 2006-05-30 20:37:29 +00:00
193 changed files with 5169 additions and 2960 deletions
+4 -5
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"/>
@@ -33,8 +32,8 @@
<classpathentry kind="src" path="core/src/test/java"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="MAVEN_REPO/com.caucho/jars/resin-3.0.9.jar"/>
<classpathentry sourcepath="/MAVEN_REPO/springframework/src/spring-2.0-m2.zip" kind="var" path="MAVEN_REPO/springframework/jars/spring-2.0-m2.jar"/>
<classpathentry sourcepath="/MAVEN_REPO/springframework/src/spring-2.0-m2.zip" kind="var" path="MAVEN_REPO/springframework/jars/spring-mock-2.0-m2.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/org.springframework/jars/spring-2.0-m2.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/org.springframework/jars/spring-mock-2.0-m2.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/aopalliance/jars/aopalliance-1.0.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/aspectj/jars/aspectjrt-1.2.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/cas/jars/casclient-2.0.11.jar"/>
@@ -76,7 +75,7 @@
<classpathentry kind="var" path="MAVEN_REPO/org.apache.directory.shared/jars/shared-ldap-0.9.5.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/antlr/jars/antlr-2.7.2.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/ldapsdk/jars/ldapsdk-4.1.jar"/>
<classpathentry sourcepath="/MAVEN_REPO/springframework/src/spring-2.0-m2.zip" kind="var" path="MAVEN_REPO/springframework/jars/spring-hibernate3-2.0-m2.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/org.springframework/jars/spring-hibernate3-2.0-m2.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/cas/jars/cas-server-3.0.4.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/net.sourceforge.retroweaver/jars/retroweaver-1.0fcs.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/taglibs/jars/standard-1.0.6.jar"/>
+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.0.0</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.0.0</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.0.0</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.0.0</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.0.0</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.0.0</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.0.0</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.0.0</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;
@@ -71,16 +71,12 @@ import javax.servlet.http.HttpSession;
public class HttpSessionContextIntegrationFilter implements InitializingBean, Filter {
//~ Static fields/initializers =====================================================================================
// ~ Static fields/initializers
// =============================================
protected static final Log logger = LogFactory.getLog(HttpSessionContextIntegrationFilter.class);
private static final String FILTER_APPLIED = "__acegi_session_integration_filter_applied";
public static final String ACEGI_SECURITY_CONTEXT_KEY = "ACEGI_SECURITY_CONTEXT";
//~ Instance fields ================================================================================================
// ~ Instance fields
// ========================================================
private Class context = SecurityContextImpl.class;
private Object contextObject;
@@ -104,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 {
@@ -117,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();
}
/**
@@ -287,8 +285,6 @@ public class HttpSessionContextIntegrationFilter implements InitializingBean, Fi
return allowSessionCreation;
}
// ~ Methods
// ================================================================
public boolean isForceEagerSessionCreation() {
return forceEagerSessionCreation;
}
@@ -30,11 +30,11 @@ import java.lang.reflect.Constructor;
* three valid <code>MODE_</code> settings defined as <code>static final</code> fields, or a fully qualified classname
* to a concrete implementation of {@link org.acegisecurity.context.SecurityContextHolderStrategy} that provides a
* public no-argument constructor.</p>
* <p>There are two ways to specify the desired mode <code>String</code>. The first is to specify it via the
* system property keyed on {@link #SYSTEM_PROPERTY}. The second is to call {@link #setStrategyName(String)} before
* using the class. If neither approach is used, the class will default to using {@link #MODE_THREADLOCAL}, which is
* backwards compatible, has fewer JVM incompatibilities and is appropriate on servers (whereas {@link #MODE_GLOBAL}
* is not).</p>
* <p>There are two ways to specify the desired strategy mode <code>String</code>. The first is to specify it via
* the system property keyed on {@link #SYSTEM_PROPERTY}. The second is to call {@link #setStrategyName(String)}
* before using the class. If neither approach is used, the class will default to using {@link #MODE_THREADLOCAL},
* which is backwards compatible, has fewer JVM incompatibilities and is appropriate on servers (whereas {@link
* #MODE_GLOBAL} is definitely inappropriate for server use).</p>
*
* @author Ben Alex
* @version $Id$
@@ -49,8 +49,12 @@ public class SecurityContextHolder {
public static final String MODE_GLOBAL = "MODE_GLOBAL";
public static final String SYSTEM_PROPERTY = "acegi.security.strategy";
private static String strategyName = System.getProperty(SYSTEM_PROPERTY);
private static Constructor customStrategy;
private static SecurityContextHolderStrategy strategy;
private static int initializeCount = 0;
static {
initialize();
}
//~ Methods ========================================================================================================
@@ -58,7 +62,6 @@ public class SecurityContextHolder {
* Explicitly clears the context value from the current thread.
*/
public static void clearContext() {
initialize();
strategy.clearContext();
}
@@ -68,11 +71,20 @@ public class SecurityContextHolder {
* @return the security context (never <code>null</code>)
*/
public static SecurityContext getContext() {
initialize();
return strategy.getContext();
}
/**
* Primarily for troubleshooting purposes, this method shows how many times the class has reinitialized its
* <code>SecurityContextHolderStrategy</code>.
*
* @return the count (should be one unless you've called {@link #setStrategyName(String)} to switch to an alternate
* strategy.
*/
public static int getInitializeCount() {
return initializeCount;
}
private static void initialize() {
if ((strategyName == null) || "".equals(strategyName)) {
// Set default
@@ -88,16 +100,15 @@ public class SecurityContextHolder {
} else {
// Try to load a custom strategy
try {
if (customStrategy == null) {
Class clazz = Class.forName(strategyName);
customStrategy = clazz.getConstructor(new Class[] {});
}
Class clazz = Class.forName(strategyName);
Constructor customStrategy = clazz.getConstructor(new Class[] {});
strategy = (SecurityContextHolderStrategy) customStrategy.newInstance(new Object[] {});
} catch (Exception ex) {
ReflectionUtils.handleReflectionException(ex);
}
}
initializeCount++;
}
/**
@@ -106,7 +117,6 @@ public class SecurityContextHolder {
* @param context the new <code>SecurityContext</code> (may not be <code>null</code>)
*/
public static void setContext(SecurityContext context) {
initialize();
strategy.setContext(context);
}
@@ -122,6 +132,6 @@ public class SecurityContextHolder {
}
public String toString() {
return "SecurityContextHolder[strategy='" + strategyName + "']";
return "SecurityContextHolder[strategy='" + strategyName + "'; initializeCount=" + initializeCount + "]";
}
}
@@ -72,7 +72,7 @@ public class SecurityContextImpl implements SecurityContext {
if (this.authentication == null) {
sb.append(": Null authentication");
} else {
sb.append(": Authentication: " + this.authentication);
sb.append(": Authentication: ").append(this.authentication);
}
return sb.toString();
@@ -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;
}
}
@@ -16,7 +16,6 @@
package org.acegisecurity.ldap;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.util.Assert;
@@ -28,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;
@@ -133,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();
}
@@ -234,8 +238,7 @@ public class LdapTemplate {
*
* @return the object created by the mapper from the matching entry
*
* @throws EmptyResultDataAccessException if no results are found.
* @throws IncorrectResultSizeDataAccessException if the search returns more than one result.
* @throws IncorrectResultSizeDataAccessException if no results are found or the search returns more than one result.
*/
public Object searchForSingleEntry(final String base, final String filter, final Object[] params,
final LdapEntryMapper mapper) {
@@ -245,13 +248,14 @@ public class LdapTemplate {
NamingEnumeration results = ctx.search(base, filter, params, searchControls);
if (!results.hasMore()) {
throw new EmptyResultDataAccessException(1);
throw new IncorrectResultSizeDataAccessException(1, 0);
}
SearchResult searchResult = (SearchResult) results.next();
if (results.hasMore()) {
throw new IncorrectResultSizeDataAccessException(1);
// We don't know how many results but set to 2 which is good enough
throw new IncorrectResultSizeDataAccessException(1, 2);
}
// Work out the DN of the matched entry
@@ -27,7 +27,7 @@ import org.acegisecurity.userdetails.ldap.LdapUserDetailsMapper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.util.Assert;
@@ -123,8 +123,12 @@ public class FilterBasedLdapUserSearch implements LdapUserSearch {
user.setUsername(username);
return user.createUserDetails();
} catch (EmptyResultDataAccessException notFound) {
throw new UsernameNotFoundException("User " + username + " not found in directory.");
} catch (IncorrectResultSizeDataAccessException notFound) {
if(notFound.getActualSize() == 0) {
throw new UsernameNotFoundException("User " + username + " not found in directory.");
}
// Search should never return multiple results if properly configured, so just rethrow
throw notFound;
}
}
@@ -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;
}
}
@@ -12,42 +12,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.providers.encoding;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
/**
* <p>MD5 implementation of PasswordEncoder.</p>
* <p>If a <code>null</code> password is presented, it will be treated as an empty <code>String</code> ("")
* <p>If a <code>null</code> password is presented, it will be treated as an empty <code>String</code> ("")
* password.</p>
* <P>As MD5 is a one-way hash, the salt can contain any characters.</p>
* <P>As MD5 is a one-way hash, the salt can contain any characters.</p>
*
* This is a convenience class that extends the
* {@link MessageDigestPasswordEncoder} and passes MD5 as the algorithm to use.
*
* @author Ray Krueger
* @author colin sampaleanu
* @author Ben Alex
* @version $Id$
*/
public class Md5PasswordEncoder extends BaseDigestPasswordEncoder implements PasswordEncoder {
//~ Methods ========================================================================================================
public class Md5PasswordEncoder extends MessageDigestPasswordEncoder {
public String encodePassword(String rawPass, Object salt) {
String saltedPass = mergePasswordAndSalt(rawPass, salt, false);
if (!getEncodeHashAsBase64()) {
return DigestUtils.md5Hex(saltedPass);
}
byte[] encoded = Base64.encodeBase64(DigestUtils.md5(saltedPass));
return new String(encoded);
}
public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
String pass1 = "" + encPass;
String pass2 = encodePassword(rawPass, salt);
return pass1.equals(pass2);
public Md5PasswordEncoder() {
super("MD5");
}
}
@@ -0,0 +1,114 @@
package org.acegisecurity.providers.encoding;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* <p>Base for digest password encoders.</p>
* This class can be used stand-alone, or one of the subclasses can be used for compatiblity and convenience
* <p>When using this class directly you must specify a
* <a href="http://java.sun.com/j2se/1.4.2/docs/guide/security/CryptoSpec.html#AppA">
* Message Digest Algorithm</a> to use as a constructor arg</p>
*
* The encoded password hash is normally returned as Hex (32 char) version of the hash bytes. Setting the encodeHashAsBase64
* property to true will cause the encoded pass to be returned as Base64 text, which will consume 24 characters. See {@link BaseDigestPasswordEncoder#setEncodeHashAsBase64(boolean)}
* <br/>
* This PasswordEncoder can be used directly as in the following example:<br/>
* &lt;bean id="passwordEncoder" class="org.acegisecurity.providers.encoding.MessageDigestPasswordEncoder"&gt;<br/>
* &nbsp;&nbsp;&lt;constructor-arg value="MD5"/><br/>
* &lt;/bean&gt;
*
*
* @author Ray Krueger
* @since 1.0.1
*/
public class MessageDigestPasswordEncoder extends BaseDigestPasswordEncoder {
private final String algorithm;
/**
* The digest algorithm to use
* Supports the named <a href="http://java.sun.com/j2se/1.4.2/docs/guide/security/CryptoSpec.html#AppA">
* Message Digest Algorithms</a> in the Java environment.
*
* @param algorithm
*/
public MessageDigestPasswordEncoder(String algorithm) {
this(algorithm, false);
}
/**
* Convenience constructor for specifying the algorithm and whether or not to enable base64 encoding
*
* @param algorithm
* @param encodeHashAsBase64
* @throws IllegalArgumentException if an unknown
*/
public MessageDigestPasswordEncoder(String algorithm, boolean encodeHashAsBase64) throws IllegalArgumentException {
this.algorithm = algorithm;
setEncodeHashAsBase64(encodeHashAsBase64);
//Validity Check
getMessageDigest();
}
/**
* Encodes the rawPass using a MessageDigest.
* If a salt is specified it will be merged with the password before encoding.
*
* @param rawPass The plain text password
* @param salt The salt to sprinkle
* @return Hex string of password digest (or base64 encoded string if encodeHashAsBase64 is enabled.
*/
public String encodePassword(String rawPass, Object salt) {
String saltedPass = mergePasswordAndSalt(rawPass, salt, false);
MessageDigest messageDigest = getMessageDigest();
byte[] digest = messageDigest.digest(saltedPass.getBytes());
if (getEncodeHashAsBase64()) {
return new String(Base64.encodeBase64(digest));
} else {
return new String(Hex.encodeHex(digest));
}
}
/**
* Get a MessageDigest instance for the given algorithm.
* Throws an IllegalArgumentException if <i>algorithm</i> is unknown
*
* @return MessageDigest instance
* @throws IllegalArgumentException if NoSuchAlgorithmException is thrown
*/
protected final MessageDigest getMessageDigest() throws IllegalArgumentException {
try {
return MessageDigest.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
throw new IllegalArgumentException("No such algorithm [" +
algorithm + "]");
}
}
/**
* Takes a previously encoded password and compares it with a rawpassword after mixing in the salt and
* encoding that value
*
* @param encPass previously encoded password
* @param rawPass plain text password
* @param salt salt to mix into password
* @return true or false
*/
public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
String pass1 = "" + encPass;
String pass2 = encodePassword(rawPass, salt);
return pass1.equals(pass2);
}
public String getAlgorithm() {
return algorithm;
}
}
@@ -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!
*/
@@ -12,42 +12,44 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.providers.encoding;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
/**
* <p>SHA implementation of PasswordEncoder.</p>
* <p>If a <code>null</code> password is presented, it will be treated as an empty <code>String</code> ("")
* <p>If a <code>null</code> password is presented, it will be treated as an empty <code>String</code> ("")
* password.</p>
* <P>As SHA is a one-way hash, the salt can contain any characters.</p>
* <P>As SHA is a one-way hash, the salt can contain any characters.</p>
*
* The default strength for the SHA encoding is SHA-1. If you wish to use higher strengths use the argumented constructor.
* {@link #ShaPasswordEncoder(int strength)}
* <br/>
* The applicationContext example... <br/>
* &lt;bean id="passwordEncoder" class="org.acegisecurity.providers.encoding.ShaPasswordEncoder"&gt;<br/>
* &nbsp;&nbsp;&lt;constructor-arg value="256"/><br/>
* &lt;/bean&gt;
*
*
* @author Ray Krueger
* @author colin sampaleanu
* @author Ben Alex
* @version $Id$
*/
public class ShaPasswordEncoder extends BaseDigestPasswordEncoder implements PasswordEncoder {
//~ Methods ========================================================================================================
public class ShaPasswordEncoder extends MessageDigestPasswordEncoder {
public String encodePassword(String rawPass, Object salt) {
String saltedPass = mergePasswordAndSalt(rawPass, salt, false);
if (!getEncodeHashAsBase64()) {
return DigestUtils.shaHex(saltedPass);
}
byte[] encoded = Base64.encodeBase64(DigestUtils.sha(saltedPass));
return new String(encoded);
/**
* Initializes the ShaPasswordEncoder for SHA-1 strength
*/
public ShaPasswordEncoder() {
this(1);
}
public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
String pass1 = "" + encPass;
String pass2 = encodePassword(rawPass, salt);
return pass1.equals(pass2);
/**
* Initialize the ShaPasswordEncoder with a given SHA stength as supported by the JVM
* EX: <code>ShaPasswordEncoder encoder = new ShaPasswordEncoder(256);</code> initializes with SHA-256
*
* @param strength EX: 1, 256, 384, 512
*/
public ShaPasswordEncoder(int strength) {
super("SHA-" + strength);
}
}
@@ -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 ===================================================================================================
@@ -18,6 +18,7 @@ package org.acegisecurity.providers.ldap;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.AuthenticationServiceException;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider;
@@ -31,48 +32,78 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.dao.DataAccessException;
/**
* An {@link org.acegisecurity.providers.AuthenticationProvider} implementation that provides integration with an
* LDAP server.<p>There are many ways in which an LDAP directory can be configured so this class delegates most of
* its responsibilites to two separate strategy interfaces, {@link LdapAuthenticator} and {@link
* LdapAuthoritiesPopulator}.</p>
* <h3>LdapAuthenticator</h3>This interface is responsible for performing the user authentication and retrieving
* LDAP server.
*
* <p>There are many ways in which an LDAP directory can be configured so this class delegates most of
* its responsibilites to two separate strategy interfaces, {@link LdapAuthenticator}
* and {@link LdapAuthoritiesPopulator}.</p>
*
* <h3>LdapAuthenticator</h3>
* This interface is responsible for performing the user authentication and retrieving
* the user's information from the directory. Example implementations are {@link
* org.acegisecurity.providers.ldap.authenticator.BindAuthenticator BindAuthenticator} which authenticates the user by
* "binding" as that user, and {@link org.acegisecurity.providers.ldap.authenticator.PasswordComparisonAuthenticator
* PasswordComparisonAuthenticator} which performs a comparison of the supplied password with the value stored in the
* directory, either by retrieving the password or performing an LDAP "compare" operation.<p>The task of retrieving
* the user attributes is delegated to the authenticator because the permissions on the attributes may depend on the
* type of authentication being used; for example, if binding as the user, it may be necessary to read them with the
* user's own permissions (using the same context used for the bind operation).</p>
* <h3>LdapAuthoritiesPopulator</h3>Once the user has been authenticated, this interface is called to obtain the
* set of granted authorities for the user. The {@link
* org.acegisecurity.providers.ldap.populator.DefaultLdapAuthoritiesPopulator DefaultLdapAuthoritiesPopulator} can be
* configured to obtain user role information from the user's attributes and/or to perform a search for "groups" that
* the user is a member of and map these to roles.<p>A custom implementation could obtain the roles from a
* completely different source, for example from a database.</p>
* <h3>Configuration</h3>A simple configuration might be as follows:<pre>
* directory, either by retrieving the password or performing an LDAP "compare" operation.
* <p>The task of retrieving the user attributes is delegated to the authenticator because the permissions on the
* attributes may depend on the type of authentication being used; for example, if binding as the user, it may be
* necessary to read them with the user's own permissions (using the same context used for the bind operation).</p>
*
* <h3>LdapAuthoritiesPopulator</h3>
* Once the user has been authenticated, this interface is called to obtain the set of granted authorities for the
* user.
* The
* {@link org.acegisecurity.providers.ldap.populator.DefaultLdapAuthoritiesPopulator DefaultLdapAuthoritiesPopulator}
* can be configured to obtain user role information from the user's attributes and/or to perform a search for
* "groups" that the user is a member of and map these to roles.
*
* <p>A custom implementation could obtain the roles from a completely different source, for example from a database.
* </p>
*
* <h3>Configuration</h3>A simple configuration might be as follows:
* <pre>
* &lt;bean id="initialDirContextFactory" class="org.acegisecurity.providers.ldap.DefaultInitialDirContextFactory">
* &lt;constructor-arg value="ldap://monkeymachine:389/dc=acegisecurity,dc=org"/>
* &lt;property name="managerDn">&lt;value>cn=manager,dc=acegisecurity,dc=org&lt;/value>&lt;/property>
* &lt;property name="managerPassword">&lt;value>password&lt;/value>&lt;/property> &lt;/bean>
* &lt;property name="managerPassword">&lt;value>password&lt;/value>&lt;/property>
* &lt;/bean>
*
* &lt;bean id="ldapAuthProvider" class="org.acegisecurity.providers.ldap.LdapAuthenticationProvider">
* &lt;constructor-arg> &lt;bean class="org.acegisecurity.providers.ldap.authenticator.BindAuthenticator">
* &lt;constructor-arg>&lt;ref local="initialDirContextFactory"/>&lt;/constructor-arg>
* &lt;property name="userDnPatterns">&lt;list>&lt;value>uid={0},ou=people&lt;/value>&lt;/list>&lt;/property>
* &lt;/bean> &lt;/constructor-arg> &lt;constructor-arg>
* &lt;bean class="org.acegisecurity.providers.ldap.populator.DefaultLdapAuthoritiesPopulator">
* &lt;constructor-arg>&lt;ref local="initialDirContextFactory"/>&lt;/constructor-arg>
* &lt;constructor-arg>&lt;value>ou=groups&lt;/value>&lt;/constructor-arg>
* &lt;property name="groupRoleAttribute">&lt;value>ou&lt;/value>&lt;/property> &lt;/bean>
* &lt;/constructor-arg> &lt;/bean></pre><p>This would set up the provider to access an LDAP server with URL
* &lt;constructor-arg>
* &lt;bean class="org.acegisecurity.providers.ldap.authenticator.BindAuthenticator">
* &lt;constructor-arg>&lt;ref local="initialDirContextFactory"/>&lt;/constructor-arg>
* &lt;property name="userDnPatterns">&lt;list>&lt;value>uid={0},ou=people&lt;/value>&lt;/list>&lt;/property>
* &lt;/bean>
* &lt;/constructor-arg>
* &lt;constructor-arg>
* &lt;bean class="org.acegisecurity.providers.ldap.populator.DefaultLdapAuthoritiesPopulator">
* &lt;constructor-arg>&lt;ref local="initialDirContextFactory"/>&lt;/constructor-arg>
* &lt;constructor-arg>&lt;value>ou=groups&lt;/value>&lt;/constructor-arg>
* &lt;property name="groupRoleAttribute">&lt;value>ou&lt;/value>&lt;/property>
* &lt;/bean>
* &lt;/constructor-arg>
* &lt;/bean></pre>
*
* <p>This would set up the provider to access an LDAP server with URL
* <tt>ldap://monkeymachine:389/dc=acegisecurity,dc=org</tt>. Authentication will be performed by attempting to bind
* with the DN <tt>uid=&lt;user-login-name&gt;,ou=people,dc=acegisecurity,dc=org</tt>. After successful
* authentication, roles will be assigned to the user by searching under the DN
* <tt>ou=groups,dc=acegisecurity,dc=org</tt> with the default filter <tt>(member=&lt;user's-DN&gt;)</tt>. The role
* name will be taken from the "ou" attribute of each match.</p>
* <p>
* The authenticate method will reject empty passwords outright. LDAP servers may allow an anonymous
* bind operation with an empty password, even if a DN is supplied. In practice this means that if
* the LDAP directory is configured to allow unauthenitcated access, it might be possible to
* authenticate as <i>any</i> user just by supplying an empty password.
* More information on the misuse of unauthenticated access can be found in
* <a href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-authmeth-19.txt">
* draft-ietf-ldapbis-authmeth-19.txt</a>.
* </p>
*
* @author Luke Taylor
* @version $Id$
@@ -92,18 +123,39 @@ 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)
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
if (!userDetails.getPassword().equals(authentication.getCredentials().toString())) {
throw new BadCredentialsException(messages.getMessage(
@@ -130,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]);
@@ -139,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)) {
@@ -157,8 +205,19 @@ public class LdapAuthenticationProvider extends AbstractUserDetailsAuthenticatio
String password = (String) authentication.getCredentials();
Assert.notNull(password, "Null password was supplied in authentication token");
LdapUserDetails ldapUser = authenticator.authenticate(username, password);
if (password.length() == 0) {
logger.debug("Rejecting empty password for user " + username);
throw new BadCredentialsException(messages.getMessage("LdapAuthenticationProvider.emptyPassword",
"Empty Password"));
}
return createUserDetails(ldapUser, username, password);
try {
LdapUserDetails ldapUser = getAuthenticator().authenticate(username, password);
return createUserDetails(ldapUser, username, password);
} catch (DataAccessException ldapAccessFailure) {
throw new AuthenticationServiceException(ldapAccessFailure.getMessage(), ldapAccessFailure);
}
}
}
@@ -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);
}
}
}
@@ -40,23 +40,19 @@ import javax.naming.directory.SearchControls;
/**
* The default strategy for obtaining user role information from the directory.<p>It obtains roles by
* <ul>
* <li>Reading the values of the roles specified by the attribute names in the <tt>userRoleAttributes</tt></li>
* <li>Performing a search for "groups" the user is a member of and adding those to the list of roles.</li>
* </ul>
* performing a search for "groups" the user is a member of.
* </p>
* <p>If the <tt>userRolesAttributes</tt> property is set, any matching attributes amongst those retrieved for the
* user will have their values added to the list of roles. If <tt>userRolesAttributes</tt> is null, no attributes will
* be mapped to roles.</p>
* <p>A typical group search scenario would be where each group/role is specified using the <tt>groupOfNames</tt>
* (or <tt>groupOfUniqueNames</tt>) LDAP objectClass and the user's DN is listed in the <tt>member</tt> (or
* <tt>uniqueMember</tt>) attribute to indicate that they should be assigned that role. The following LDIF sample has
* the groups stored under the DN <tt>ou=groups,dc=acegisecurity,dc=org</tt> and a group called "developers" with
* "ben" and "marissa" as members:<pre>dn: ou=groups,dc=acegisecurity,dc=orgobjectClass: top
* "ben" and "marissa" as members:
* <pre>dn: ou=groups,dc=acegisecurity,dc=orgobjectClass: top
* objectClass: organizationalUnitou: groupsdn: cn=developers,ou=groups,dc=acegisecurity,dc=org
* objectClass: groupOfNamesobjectClass: topcn: developersdescription: Acegi Security Developers
* member: uid=ben,ou=people,dc=acegisecurity,dc=orgmember: uid=marissa,ou=people,dc=acegisecurity,dc=orgou: developer
* </pre></p>
* </pre>
* </p>
* <p>The group search is performed within a DN specified by the <tt>groupSearchBase</tt> property, which should
* be relative to the root DN of its <tt>InitialDirContextFactory</tt>. If the search base is null, group searching is
* disabled. The filter used in the search is defined by the <tt>groupSearchFilter</tt> property, with the filter
@@ -70,7 +66,9 @@ import javax.naming.directory.SearchControls;
* &lt;!-- the following properties are shown with their default values -->
* &lt;property name="searchSubTree">&lt;value>false&lt;/value>&lt;/property>
* &lt;property name="rolePrefix">&lt;value>ROLE_&lt;/value>&lt;/property>
* &lt;property name="convertToUpperCase">&lt;value>true&lt;/value>&lt;/property>&lt;/bean></pre>A search for
* &lt;property name="convertToUpperCase">&lt;value>true&lt;/value>&lt;/property>
* &lt;/bean>
* </pre>A search for
* roles for user "uid=ben,ou=people,dc=acegisecurity,dc=org" would return the single granted authority
* "ROLE_DEVELOPER".</p>
*
@@ -123,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 ========================================================================================================
@@ -203,19 +191,19 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
// }
public final Set getGroupMembershipRoles(String userDn, String username) {
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()) {
@@ -256,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;
@@ -81,14 +81,15 @@ import javax.servlet.http.HttpServletResponse;
* <p>To configure this filter to redirect to specific pages as the result of specific {@link
* AuthenticationException}s you can do the following. Configure the <code>exceptionMappings</code> property in your
* application xml. This property is a java.util.Properties object that maps a fully-qualified exception class name to
* a redirection url target.<br>
* For example:<br>
* <code> &lt;property name="exceptionMappings"&gt;<br>
* * &nbsp;&nbsp;&lt;props&gt;<br>
* * &nbsp;&nbsp;&nbsp;&nbsp;&lt;prop&gt; key="org.acegisecurity.BadCredentialsException"&gt;/bad_credentials.jsp&lt;/prop&gt;<br>
* * &nbsp;&nbsp;&lt;/props&gt;<br>
* * &lt;/property&gt;<br>
* * </code><br>
* a redirection url target.
* For example:
* <pre>
* &lt;property name="exceptionMappings"&gt;
* &lt;props&gt;
* &lt;prop&gt; key="org.acegisecurity.BadCredentialsException"&gt;/bad_credentials.jsp&lt;/prop&gt;
* &lt;/props&gt;
* &lt;/property&gt;
* </pre>
* The example above would redirect all {@link org.acegisecurity.BadCredentialsException}s thrown, to a page in the
* web-application called /bad_credentials.jsp.</p>
* <p>Any {@link AuthenticationException} thrown that cannot be matched in the <code>exceptionMappings</code> will
@@ -122,7 +123,7 @@ public abstract class AbstractProcessingFilter implements Filter, InitializingBe
private String authenticationFailureUrl;
/**
* Where to redirect the browser to if authentication is successful but ACEGI_SECURITY_TARGET_URL_KEY is
* Where to redirect the browser to if authentication is successful but ACEGI_SAVED_REQUEST_KEY is
* <code>null</code>
*/
private String defaultTargetUrl;
@@ -134,7 +135,7 @@ public abstract class AbstractProcessingFilter implements Filter, InitializingBe
private String filterProcessesUrl = getDefaultFilterProcessesUrl();
/**
* If <code>true</code>, will always redirect to {@link #defaultTargetUrl} upon successful authentication,
* If <code>true</code>, will always redirect to the value of {@link #getDefaultTargetUrl} upon successful authentication,
* irrespective of the page that caused the authentication request (defaults to <code>false</code>).
*/
private boolean alwaysUseDefaultTargetUrl = false;
@@ -231,6 +232,14 @@ public abstract class AbstractProcessingFilter implements Filter, InitializingBe
*/
public abstract String getDefaultFilterProcessesUrl();
/**
* Supplies the default target Url that will be used if no saved request is found or the
* <tt>alwaysUseDefaultTargetUrl</tt> propert is set to true.
* Override this method of you want to provide a customized default Url (for example if you want different Urls
* depending on the authorities of the user who has just logged in).
*
* @return the defaultTargetUrl property
*/
public String getDefaultTargetUrl() {
return defaultTargetUrl;
}
@@ -304,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) {
@@ -339,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;
}
@@ -370,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() + defaultTargetUrl;
targetUrl = getDefaultTargetUrl();
}
if (logger.isDebugEnabled()) {
@@ -393,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;
}
}
@@ -0,0 +1,86 @@
package org.acegisecurity.ui.savedrequest;
import javax.servlet.http.Cookie;
import java.io.Serializable;
/**
* Stores off the values of a cookie in a serializable holder
*
* @author Ray Krueger
*/
public class SavedCookie implements Serializable {
private java.lang.String name;
private java.lang.String value;
private java.lang.String comment;
private java.lang.String domain;
private int maxAge;
private java.lang.String path;
private boolean secure;
private int version;
public SavedCookie(String name, String value, String comment, String domain, int maxAge, String path, boolean secure, int version) {
this.name = name;
this.value = value;
this.comment = comment;
this.domain = domain;
this.maxAge = maxAge;
this.path = path;
this.secure = secure;
this.version = version;
}
public SavedCookie(Cookie cookie) {
this(cookie.getName(), cookie.getValue(), cookie.getComment(),
cookie.getDomain(), cookie.getMaxAge(), cookie.getPath(), cookie.getSecure(), cookie.getVersion());
}
public String getName() {
return name;
}
public String getValue() {
return value;
}
public String getComment() {
return comment;
}
public String getDomain() {
return domain;
}
public int getMaxAge() {
return maxAge;
}
public String getPath() {
return path;
}
public boolean isSecure() {
return secure;
}
public int getVersion() {
return version;
}
public Cookie getCookie() {
Cookie c = new Cookie(getName(), getValue());
if (getComment() != null)
c.setComment(getComment());
if (getDomain() != null)
c.setDomain(getDomain());
if (getPath() != null)
c.setPath(getPath());
c.setVersion(getVersion());
c.setMaxAge(getMaxAge());
c.setSecure(isSecure());
return c;
}
}
@@ -17,22 +17,19 @@ package org.acegisecurity.ui.savedrequest;
import org.acegisecurity.util.PortResolver;
import org.acegisecurity.util.UrlUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
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 javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.TreeMap;
/**
@@ -40,9 +37,9 @@ import javax.servlet.http.HttpServletRequest;
* org.acegisecurity.ui.AbstractProcessingFilter} and {@link org.acegisecurity.wrapper.SavedRequestAwareWrapper} to
* reproduce the request after successful authentication. An instance of this class is stored at the time of an
* authentication exception by {@link org.acegisecurity.ui.ExceptionTranslationFilter}.</p>
* <p><em>IMPLEMENTATION NOTE</em>: It is assumed that this object is accessed only from the context of a single
* <p><em>IMPLEMENTATION NOTE</em>: It is assumed that this object is accessed only from the context of a single
* thread, so no synchronization around internal collection classes is performed.</p>
* <p>This class is based on code in Apache Tomcat.</p>
* <p>This class is based on code in Apache Tomcat.</p>
*
* @author Craig McClanahan
* @author Andrey Grebnev
@@ -58,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;
@@ -133,7 +130,7 @@ public class SavedRequest implements java.io.Serializable {
//~ Methods ========================================================================================================
private void addCookie(Cookie cookie) {
cookies.add(cookie);
cookies.add(new SavedCookie(cookie));
}
private void addHeader(String name, String value) {
@@ -161,7 +158,6 @@ public class SavedRequest implements java.io.Serializable {
*
* @param request DOCUMENT ME!
* @param portResolver DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public boolean doesRequestMatch(HttpServletRequest request, PortResolver portResolver) {
@@ -180,7 +176,8 @@ public class SavedRequest implements java.io.Serializable {
return false;
}
if (!propertyEquals("serverPort", new Integer(this.serverPort), new Integer(portResolver.getServerPort(request)))) {
if (!propertyEquals("serverPort", new Integer(this.serverPort), new Integer(portResolver.getServerPort(request))))
{
return false;
}
@@ -212,7 +209,12 @@ public class SavedRequest implements java.io.Serializable {
}
public List getCookies() {
return cookies;
List cookieList = new ArrayList(cookies.size());
for (Iterator iterator = cookies.iterator(); iterator.hasNext();) {
SavedCookie savedCookie = (SavedCookie) iterator.next();
cookieList.add(savedCookie.getCookie());
}
return cookieList;
}
/**
@@ -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);
@@ -16,6 +16,7 @@
package org.acegisecurity.userdetails.ldap;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.ldap.LdapEntryMapper;
@@ -57,34 +58,27 @@ 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
for (int i = 0; (roleAttributes != null) && (i < roleAttributes.length); i++) {
Attribute roleAttribute = attributes.get(roleAttributes[i]);
if(roleAttribute == null) {
logger.debug("Couldn't read role attribute '" + roleAttributes[i] + "' for user " + dn);
continue;
}
NamingEnumeration attributeRoles = roleAttribute.getAll();
while (attributeRoles.hasMore()) {
Object role = attributeRoles.next();
GrantedAuthority authority = createAuthority(attributeRoles.next());
// We only handle Strings for the time being
if (role instanceof String) {
if (convertToUpperCase) {
role = ((String) role).toUpperCase();
}
essence.addAuthority(new GrantedAuthorityImpl(rolePrefix + role));
if(authority != null) {
essence.addAuthority(authority);
} else {
logger.warn("Non-String value found for role attribute " + roleAttribute.getID());
logger.debug("Failed to create an authority value from attribute with Id: " + roleAttribute.getID());
}
}
}
@@ -92,6 +86,47 @@ 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.
* <p>
* The default implementation converts string attributes to roles, making use of the <tt>rolePrefix</tt>
* and <tt>convertToUpperCase</tt> properties. Non-String attributes are ignored.
* </p>
*
* @param role the attribute returned from
* @return the authority to be added to the list of authorities for the user, or null
* if this attribute should be ignored.
*/
protected GrantedAuthority createAuthority(Object role) {
if (role instanceof String) {
if (convertToUpperCase) {
role = ((String) role).toUpperCase();
}
return new GrantedAuthorityImpl(rolePrefix + role);
}
return null;
}
/**
* Determines whether role field values will be converted to upper case when loaded.
* The default is true.
@@ -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;
@@ -38,6 +38,7 @@ SwitchUserProcessingFilter.expired=User account has expired
SwitchUserProcessingFilter.credentialsExpired=User credentials have expired
AbstractAccessDecisionManager.accessDenied=Access is denied
LdapAuthenticationProvider.emptyUsername=Empty username not allowed
LdapAuthenticationProvider.emptyPassword=Bad credentials
DefaultIntitalDirContextFactory.communicationFailure=Unable to connect to LDAP server
DefaultIntitalDirContextFactory.badCredentials=Bad credentials
DefaultIntitalDirContextFactory.unexpectedException=Failed to obtain InitialDirContext due to unexpected exception
@@ -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]);
}
}
@@ -16,22 +16,19 @@
package org.acegisecurity.concurrent;
import junit.framework.TestCase;
import org.springframework.mock.web.MockFilterConfig;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockHttpSession;
import java.io.IOException;
import java.util.Date;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.util.Date;
/**
@@ -72,7 +69,7 @@ public class ConcurrentSessionFilterTests extends TestCase {
request.setSession(session);
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterConfig config = new MockFilterConfig(null);
MockFilterConfig config = new MockFilterConfig(null, null);
// Setup our expectation that the filter chain will not be invoked, as we redirect to expiredUrl
MockFilterChain chain = new MockFilterChain(false);
@@ -122,7 +119,7 @@ public class ConcurrentSessionFilterTests extends TestCase {
request.setSession(session);
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterConfig config = new MockFilterConfig(null);
MockFilterConfig config = new MockFilterConfig(null, null);
// Setup our expectation that the filter chain will be invoked, as our session hasn't expired
MockFilterChain chain = new MockFilterChain(true);
@@ -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);
@@ -240,8 +240,8 @@ public class SecurityContextHolderTests extends TestCase {
public void testSynchronizationCustomStrategyLoading() {
SecurityContextHolder.setStrategyName(InheritableThreadLocalSecurityContextHolderStrategy.class.getName());
assertEquals("SecurityContextHolder[strategy='org.acegisecurity.context.InheritableThreadLocalSecurityContextHolderStrategy']",
new SecurityContextHolder().toString());
assertTrue(new SecurityContextHolder().toString()
.lastIndexOf("SecurityContextHolder[strategy='org.acegisecurity.context.InheritableThreadLocalSecurityContextHolderStrategy'") != -1);
loadStartAndWaitForThreads(true, "Main_", 10, false, true);
assertEquals("Thread errors detected; review log output for details", 0, errors);
}
@@ -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);
}
@@ -23,6 +23,7 @@ import junit.framework.TestCase;
*
* @author colin sampaleanu
* @author Ben Alex
* @author Ray Krueger
* @version $Id$
*/
public class Md5PasswordEncoderTests extends TestCase {
@@ -36,11 +37,17 @@ public class Md5PasswordEncoderTests extends TestCase {
String encoded = pe.encodePassword(raw, salt);
assertTrue(pe.isPasswordValid(encoded, raw, salt));
assertFalse(pe.isPasswordValid(encoded, badRaw, salt));
assertTrue(encoded.length() == 32);
assertEquals("a68aafd90299d0b137de28fb4bb68573", encoded);
assertEquals("MD5", pe.getAlgorithm());
}
// now try Base64
public void testBase64() throws Exception {
Md5PasswordEncoder pe = new Md5PasswordEncoder();
pe.setEncodeHashAsBase64(true);
encoded = pe.encodePassword(raw, salt);
String raw = "abc123";
String badRaw = "abc321";
String salt = "THIS_IS_A_SALT";
String encoded = pe.encodePassword(raw, salt);
assertTrue(pe.isPasswordValid(encoded, raw, salt));
assertFalse(pe.isPasswordValid(encoded, badRaw, salt));
assertTrue(encoded.length() != 32);
@@ -23,6 +23,7 @@ import junit.framework.TestCase;
*
* @author colin sampaleanu
* @author Ben Alex
* @author Ray Krueger
* @version $Id$
*/
public class ShaPasswordEncoderTests extends TestCase {
@@ -36,13 +37,36 @@ public class ShaPasswordEncoderTests extends TestCase {
String encoded = pe.encodePassword(raw, salt);
assertTrue(pe.isPasswordValid(encoded, raw, salt));
assertFalse(pe.isPasswordValid(encoded, badRaw, salt));
assertTrue(encoded.length() == 40);
assertEquals("b2f50ffcbd3407fe9415c062d55f54731f340d32", encoded);
// now try Base64
}
public void testBase64() throws Exception {
ShaPasswordEncoder pe = new ShaPasswordEncoder();
pe.setEncodeHashAsBase64(true);
encoded = pe.encodePassword(raw, salt);
String raw = "abc123";
String badRaw = "abc321";
String salt = "THIS_IS_A_SALT";
String encoded = pe.encodePassword(raw, salt);
assertTrue(pe.isPasswordValid(encoded, raw, salt));
assertFalse(pe.isPasswordValid(encoded, badRaw, salt));
assertTrue(encoded.length() != 40);
}
public void test256() throws Exception {
ShaPasswordEncoder pe = new ShaPasswordEncoder(256);
String encoded = pe.encodePassword("abc123", null);
assertEquals("6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090", encoded);
String encodedWithSalt = pe.encodePassword("abc123", "THIS_IS_A_SALT");
assertEquals("4b79b7de23eb23b78cc5ede227d532b8a51f89b2ec166f808af76b0dbedc47d7", encodedWithSalt);
}
public void testInvalidStrength() throws Exception {
try {
new ShaPasswordEncoder(666);
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException e) {
//expected
}
}
}
@@ -34,8 +34,7 @@ import javax.naming.directory.BasicAttributes;
/**
*
DOCUMENT ME!
* Tests {@link LdapAuthenticationProvider}.
*
* @author Luke Taylor
* @version $Id$
@@ -86,11 +85,20 @@ public class LdapAuthenticationProviderTests extends TestCase {
} catch (BadCredentialsException expected) {}
}
public void testEmptyPasswordIsRejected() {
LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(),
new MockAuthoritiesPopulator());
try {
ldapProvider.retrieveUser("jen", new UsernamePasswordAuthenticationToken("jen", ""));
fail("Expected BadCredentialsException for empty password");
} catch (BadCredentialsException expected) {}
}
public void testNormalUsage() {
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);
@@ -114,17 +122,23 @@ public class LdapAuthenticationProviderTests extends TestCase {
Attributes userAttributes = new BasicAttributes("cn", "bob");
public LdapUserDetails authenticate(String username, String password) {
LdapUserDetailsImpl.Essence userEssence = new LdapUserDetailsImpl.Essence();
userEssence.setPassword("{SHA}anencodedpassword");
userEssence.setAttributes(userAttributes);
if (username.equals("bob") && password.equals("bobspassword")) {
LdapUserDetailsImpl.Essence userEssence = new LdapUserDetailsImpl.Essence();
userEssence.setDn("cn=bob,ou=people,dc=acegisecurity,dc=org");
userEssence.setPassword("{SHA}anencodedpassword");
userEssence.setAttributes(userAttributes);
userEssence.addAuthority(new GrantedAuthorityImpl("ROLE_FROM_ENTRY"));
return userEssence.createUserDetails();
} else if (username.equals("jen") && password.equals("")) {
userEssence.setDn("cn=jen,ou=people,dc=acegisecurity,dc=org");
userEssence.addAuthority(new GrantedAuthorityImpl("ROLE_FROM_ENTRY"));
return userEssence.createUserDetails();
}
throw new BadCredentialsException("Authentication of Bob failed.");
throw new BadCredentialsException("Authentication failed.");
}
}
@@ -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;

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