1
0
mirror of synced 2026-07-09 04:40:13 +00:00

Compare commits

..

157 Commits

Author SHA1 Message Date
Luke Taylor beb0ec4ba9 Version 2.0.6.RELEASE 2010-10-25 17:18:16 +01:00
Luke Taylor dec2e59fba SEC-1584: Backport of namespace support for injecting custom HttpFirewall instance into FilterChainProxy. 2010-10-14 20:32:01 +01:00
Luke Taylor ed7f589998 SEC-1584: Additional integration tests. 2010-10-13 00:05:38 +01:00
Luke Taylor 8f6ddb0f17 SEC-1584: Backport to 2.0.x branch of request firewalling (normalization checks and path-parameter stripping from servletPath and pathInfo). 2010-10-13 00:04:44 +01:00
Luke Taylor 62a8aca853 .gitignore updates 2010-10-03 23:39:33 +01:00
Luke Taylor 9c6a5135a3 SEC-1532: Patch applied to 2.0.x branch 2010-08-26 14:13:01 +01:00
Luke Taylor 0acf262546 SEC-1462: Added suggested patch (effectively the same as changes in 3.0.x and master branches). 2010-04-20 18:16:45 +01:00
Luke Taylor 6ad652ae97 Update 2.0 branch pom versions. 2010-04-20 18:15:51 +01:00
Luke Taylor 068b3d48ec Add .gitignore to 2.0.x branch 2010-04-16 15:15:54 +01:00
Luke Taylor d6f6a54455 SEC-1444: Backport of changes to 2.0.x 2010-04-16 15:14:01 +01:00
Luke Taylor 4361211c21 Change release from milestone to release 2009-07-14 12:29:51 +00:00
Luke Taylor 71adc26b0f [maven-release-plugin] prepare release spring-security-2.0.5.RELEASE 2009-07-14 00:29:53 +00:00
Luke Taylor eb3288ca34 Removing unnecessary repository declarations 2009-07-13 23:53:12 +00:00
Luke Taylor f3f4cfe804 Minor changes to readme 2009-07-13 23:48:55 +00:00
Luke Taylor 40fa884860 Updated release plugin version 2009-07-13 23:47:53 +00:00
Luke Taylor 3e393c9df6 Tidying test class 2009-07-13 23:47:33 +00:00
Luke Taylor a61aca1abf Update to bundlor M5 2009-07-13 13:07:44 +00:00
Luke Taylor 52d2c904f9 Disable adapters build 2009-07-09 12:38:59 +00:00
Luke Taylor 149fd5d8de Add bundlor templates 2009-07-09 12:26:11 +00:00
Luke Taylor f3f02d8aed Update sec-2.0.x branch to use bundlor 2009-07-09 11:51:26 +00:00
Luke Taylor 781c99f257 SEC-1145: Updated LDAP code to make sure pooling flag is removed when binding as a specific user (for real this time) 2009-06-03 16:57:33 +00:00
Luke Taylor b77f780993 SEC-1145: Updated LDAP code to make sure pooling flag is removed when binding as a specific user 2009-06-03 16:12:54 +00:00
Scott Battaglia 22964837e9 SEC-1066
upgraded to CAS Client for Java 3.1.5
2008-12-22 19:37:50 +00:00
Scott Battaglia 7566802a08 SEC-1046
upgrade to CAS Client for Java 3.1.4
2008-12-16 14:50:04 +00:00
Luke Taylor 4c3867718e SEC-1031: Ported change from trunk. 2008-11-11 23:36:47 +00:00
Luke Taylor ad4b5c487f Temporarily store webflow test sample in sandbox 2008-10-02 23:24:58 +00:00
Luke Taylor 48013b2c93 typo 2008-10-02 15:26:20 +00:00
Luke Taylor 03b21494bc Corrected typo 2008-10-02 14:53:24 +00:00
Luke Taylor ac54976f9e Added appendices to end of doc 2008-10-02 14:50:58 +00:00
Scott Battaglia 7594e1ae2f SEC-984
added template method to allow to override the default of retrieving user by username.
2008-10-01 18:49:52 +00:00
Luke Taylor 97381fb448 SEC-974: Made getExceptionMappings() protected. 2008-10-01 16:25:20 +00:00
Carlos Sanchez af3c77f56f [SEC-997] Remove unnecessary repository 2008-10-01 00:52:52 +00:00
Luke Taylor 4542f00b14 SEC-975: Namespace security syntax does not interpret properties
http://jira.springframework.org/browse/SEC-975. Changed creation of AccessDeniedHandler to use a BeanDefinition to make sure placeholders work OK.
2008-09-12 19:06:53 +00:00
Luke Taylor 5e4634d216 Minor Javadoc improvement. 2008-09-12 14:57:21 +00:00
Luke Taylor d291def963 Removed invalid comment. 2008-09-12 10:18:40 +00:00
Luke Taylor df59cb9dcd Import cleaning. 2008-09-11 14:41:00 +00:00
Luke Taylor ef0389ae79 SEC-976: Removed checks for presence of core-tiger classes. 2008-09-11 14:37:55 +00:00
Luke Taylor 5b9bb8ba54 [maven-release-plugin] prepare for next development iteration 2008-09-05 19:04:22 +00:00
Luke Taylor 73eed2656d [maven-release-plugin] prepare release spring-security-parent-2.0.4 2008-09-05 18:57:43 +00:00
Luke Taylor f935830cdf Class index generation files 2008-09-05 14:26:26 +00:00
Luke Taylor ee04b189b7 Updated schema verisions to 2.0.4 2008-09-05 14:23:42 +00:00
Luke Taylor 8661e17df9 OPEN - issue SEC-960: DN Encoding in LDAPUserDetailsManager.changePassword() causes bind errors
http://jira.springframework.org/browse/SEC-960. Replaced call to toUrl() with toString() to prevent URL encoding when setting up principal name for reconnect() in changePassword() method.
2008-09-05 13:49:38 +00:00
Ben Alex c45b4e0989 SEC-951: Overcome serialization error caused by BasicLookupStrategy failing to modify AccessControlEntryImpl.acl field to the replacement AclImpl (previously old references to StubAclParent were retained). 2008-09-05 05:33:41 +00:00
Ben Alex 0f8ea229c2 SEC-908: Correct issue with BasePermission static initialization failure. 2008-09-05 04:33:52 +00:00
Luke Taylor 5102be3a59 SEC-971: getter for cookieName in AbstractRememberMeServices
http://jira.springframework.org/browse/SEC-971. Added getCookieName() method.
2008-09-04 16:05:34 +00:00
Luke Taylor de379dc2ac Converted literals to classname/interfacename docbook tags for easier indexing 2008-09-02 01:05:57 +00:00
Luke Taylor 09c70bb28e SEC-970: Corrected link in docbook html banner 2008-09-01 16:56:50 +00:00
Luke Taylor 4e2d6f8b2e SEC-967: TextUtils.java does not escape ampersand character
http://jira.springframework.org/browse/SEC-967. Added escaping of '&' character
2008-08-29 12:01:45 +00:00
Luke Taylor d781deffe7 OPEN - issue SEC-966: Consider adding escapeXml attribute to security:authentication
http://jira.springframework.org/browse/SEC-966.  Added escaping of rendered text as default.
2008-08-26 16:21:29 +00:00
Luke Taylor a4e4120443 SEC-963: LDAP Group Search Root
http://jira.springframework.org/browse/SEC-963. Changed namespace instances of DefaultAuthoritiesPopulator to use the root as the default search location.
2008-08-26 13:51:01 +00:00
Luke Taylor 83868a7334 SEC-955: ability to externalize port mapping for secured channel to a property file
http://jira.springframework.org/browse/SEC-955. Changed schema to make port-mapping type xsd:string to allow placeholders.
2008-08-26 13:20:01 +00:00
Luke Taylor 150f3d97d0 SEC-832: NamingEnumeration.hasMore fails on MS AD with PartialResultException
http://jira.springframework.org/browse/SEC-832. Changed searchForSingleEntry method to ignore PartialResultException, similar to Spring LDAP's approach.
2008-08-26 12:49:37 +00:00
Luke Taylor 7f28a8bc5d Refactored DefaultLdapAuthoritiesPopulator to remove contextSource field and setter method. 2008-08-26 12:38:02 +00:00
Luke Taylor 1cfd886517 SEC-922: Spring Security should respect Spring XML boolean operators for AJ pointcut
http://jira.springframework.org/browse/SEC-922. Added method to substitute boolean operators "and, not, or" with aspectj versions "&&, !, ||".
2008-08-18 23:31:14 +00:00
Luke Taylor bb457e1d07 SEC-957: logger.debug without guard causing massive performance hit
http://jira.springframework.org/browse/SEC-957. Added debug logging guard as requested.
2008-08-18 18:20:48 +00:00
Luke Taylor 09cf90258f SEC-758: Both AspectJSecurityInterceptor and AspectJAnnotationSecurityInterceptor not usable with @AspectJ notation
http://jira.springframework.org/browse/SEC-758. Added "throws Throwable" to AspectJAnnotationCallback signature.
2008-08-18 14:47:28 +00:00
Luke Taylor e15d7a78cd SEC-956: Remove MapBasedMethodDefinitionSource.lookupAttributes
http://jira.springframework.org/browse/SEC-956. Done.
2008-08-18 13:13:18 +00:00
Luke Taylor 3bf5e406b7 SEC-936: NPE in AbstractFallbackMethodDefinitionSource
http://jira.springframework.org/browse/SEC-936. Changed to check if the value of MethodInvocation.getThis() is null to prevent NPE. MapBasedMethodDefinitionSource now ignores calls to findAttributes() with a null target class (all its entries require a class) and the fallback option in AbstractFallbackMethodDefinitionSource is used if the targetClass is null (i.e. Method.getDeclaringClass() will be used as the Class)
2008-08-16 02:31:36 +00:00
Luke Taylor 6a68a2531c SEC-904: Moved test module out of sandbox 2008-08-16 02:24:32 +00:00
Luke Taylor 959cdd8335 SEC-936: Tests 2008-08-16 01:58:45 +00:00
Luke Taylor 8e0a6b9d1a SEC-904: Test module updates 2008-08-15 23:54:16 +00:00
Luke Taylor 827d0e1ebf OPEN - issue SEC-865: Re-Challenge NTLM Clients after Authentication Failure
http://jira.springframework.org/browse/SEC-865. Changed NTLM filter to re-challenge if retryOnAuthFailure is set and the Smb logon call fails. Updated JCIFS version in pom.
2008-08-15 22:44:22 +00:00
Luke Taylor 55d357f42d OPEN - issue SEC-905: <protect-pointcut /> pointcuts do not respect method arguments
http://jira.springframework.org/browse/SEC-905. Added extra registration method to MapBasedMethodDefinitionSource which takes a Method instance rather than the method name.
2008-08-12 17:11:38 +00:00
Luke Taylor d9ab0758ee SEC-954: Removed test dependency on AbstractMethodDefinitionSource. 2008-08-12 17:08:55 +00:00
Luke Taylor 36b35e3b1f CLOSED - issue SEC-953: Query string isn't ignored while url - filterchain pattern matching
http://jira.springframework.org/browse/SEC-953. Fixed autoboxing issue.
2008-08-11 21:15:09 +00:00
Luke Taylor 39a656eb78 OPEN - issue SEC-953: Query string isn't ignored while url - filterchain pattern matching
http://jira.springframework.org/browse/SEC-953. Added stripQueryStringFromUrls parameter to FilterChainProxy which works the same as the one on DefaultFilterInvocationDefinitionSource. This defaults to true when used with ant path matching.
2008-08-11 19:15:33 +00:00
Luke Taylor b6dec19e90 SEC-932: Added supplied class and test class. 2008-08-11 16:36:01 +00:00
Luke Taylor 69e776f581 Fixed invalid tags in faq.fml 2008-08-11 16:18:26 +00:00
Luke Taylor 3ab9fcdcaf Tidying. 2008-08-11 15:05:16 +00:00
Luke Taylor 5e3204a5cb Typo 2008-08-09 11:22:35 +00:00
Luke Taylor 6409f140e0 SEC-902: Changed Ntlm entry point to send 403 if no failure URL set 2008-08-08 16:44:13 +00:00
Luke Taylor 130e70373f SEC-936: Initial test which fails to reproduce the problem 2008-08-08 16:41:23 +00:00
Luke Taylor 3a9eb018ba SEC-950: Added test to attempt to reproduce problem. 2008-08-08 15:41:14 +00:00
Luke Taylor 8b376ccdeb SEC-910: Finished LDAP ns reference 2008-08-08 14:59:44 +00:00
Luke Taylor b3a23b4377 Some minor improvements to schema comments 2008-08-07 19:15:13 +00:00
Luke Taylor 7461d0e5f1 Added authentication, method security and start of LDAP ns info 2008-08-07 19:12:56 +00:00
Luke Taylor 566f656eba Added ldap-server xml:id 2008-08-07 19:11:43 +00:00
Luke Taylor e5d2578aec Added example of @Secured use and some extra explanation 2008-08-07 19:10:53 +00:00
Luke Taylor fb3d0b7f25 Fixed link 2008-08-07 19:09:49 +00:00
Luke Taylor 2d0b594a97 Fixed missing section closing tag 2008-08-07 15:21:25 +00:00
Luke Taylor 42af39a59e Some corrections to explicit FilterChainProxy information 2008-08-07 13:33:36 +00:00
Luke Taylor 930be9338b Added info on default target options when using form-login 2008-08-07 12:41:12 +00:00
Luke Taylor c1a6ae0832 Added faq on required dependencies 2008-08-07 12:40:25 +00:00
Luke Taylor c49bc7ffbb SEC-910: Finishing off http part of namespace appendix 2008-08-07 10:47:59 +00:00
Luke Taylor 25814d341d Tidying. 2008-08-06 16:18:05 +00:00
Luke Taylor 21eb70c576 Corrected context file name in petclinic tutorial 2008-08-06 15:40:01 +00:00
Luke Taylor e951c42c2b Improved javadoc. Some tidying up. 2008-08-06 15:28:04 +00:00
Luke Taylor 7258d30e13 Reinstated missing author tag and some minor tidying (de-jalopying). Removed unused logger. 2008-08-06 13:41:01 +00:00
Luke Taylor 22a64c1555 Added faq on missing session listener 2008-08-06 11:03:53 +00:00
Luke Taylor ff13df03ac SEC-910: More updates to namespace appendix 2008-08-06 00:21:46 +00:00
Luke Taylor ecd63cabda Added use of ANY_CHANNEL attribute to channel-security docbook 2008-08-06 00:20:58 +00:00
Luke Taylor f31bcbee07 Minor formatting 2008-08-06 00:19:46 +00:00
Luke Taylor 3ee3591feb SEC-947: Added check on "before" and "after" values to make sure they don't overflow when decremented/incremented respectfully. 2008-08-05 23:26:01 +00:00
Luke Taylor fbeb47d559 SEC-947: Added clarification to docs that FIRST and LAST should be used with position attribute 2008-08-05 23:24:49 +00:00
Luke Taylor 1c9c8f0883 SEC-910: Updates to ns appendix 2008-08-05 12:03:50 +00:00
Luke Taylor f821b0f0f8 Fix issues with move of TestingAuthenticationToken 2008-08-04 20:42:48 +00:00
Luke Taylor 4165e15861 Fix issues with move of TestingAuthenticationToken 2008-08-04 20:14:20 +00:00
Luke Taylor aa75b2fa6d Fixes to match TestingAuthenticationToken changes 2008-08-04 13:50:27 +00:00
Luke Taylor d6918c88a7 Fixes to match TestingAuthenticationToken changes 2008-08-04 13:48:44 +00:00
Luke Taylor b6d088e40d SEC-944: Minor updates to schema appendix 2008-08-04 13:29:42 +00:00
Luke Taylor 069a75b8fc minor change to wording 2008-08-04 13:29:06 +00:00
Luke Taylor 1af7eed433 SEC-883: RoleHierarchyVoter
http://jira.springframework.org/browse/SEC-883. Added RoleHierarchyVoter and deprecated existing approach. Also moved TestingAuthenticationToken to test package structure.
2008-08-04 13:08:03 +00:00
Luke Taylor e982e91846 SEC-944: Added db schema reference (and start of namespace appendix) 2008-08-01 13:57:42 +00:00
Luke Taylor 54ac7b3e46 SEC-935: Updated schema to include OpenID filter name. Also updated some doc comments and added default schema name (spring-security.xsd) to schemas. 2008-08-01 12:51:31 +00:00
Luke Taylor 3049b933d9 Moved XML test snippet to ConfigTestUtils class and removed context files from core-tiger tests in favour of in-memory XML 2008-07-31 21:35:29 +00:00
Luke Taylor c8b22d8e36 SEC-923: Fixed broken build due to missing test class. 2008-07-31 21:22:19 +00:00
Luke Taylor 1d96283876 Removed commented out line. 2008-07-31 20:45:25 +00:00
Luke Taylor ef44bd91f2 SEC-933: Added test for security pointcut applied to a UserDetailsService. 2008-07-31 20:32:43 +00:00
Luke Taylor d7926f3557 SEC-943: Forgot to commit tests. 2008-07-31 20:30:56 +00:00
Luke Taylor e5d86b13b7 SEC-941: Embedded ldap-server uses hard-coded ldap url for importing ldif files
http://jira.springframework.org/browse/SEC-941. Changed LdapUtils.parseRootDnFromUrl to use URI.getRawPath() so the returned root value still contains the escaping. I think this should be Ok.
2008-07-31 19:50:08 +00:00
Ray Krueger 3393ea7aaa SEC-923: Realm support for discovering relying parties.
A new "realmMapping" property can be configured on the OpenIDAuthenticationProcessingFilter to map the "return_to" url to a realm. If there is no mapping present the "return_to" url will be parsed and the protocol, hostname and port will be used with a trailing "/"
2008-07-31 19:23:12 +00:00
Luke Taylor 67e5afbb79 OPEN - issue SEC-881: PreAuthenticatedFilter continues filter chain after unsuccessfulAuthentication(...)
http://jira.springframework.org/browse/SEC-881. Updated Javadoc.
2008-07-31 15:56:37 +00:00
Luke Taylor 000bb1cbed OPEN - issue SEC-881: PreAuthenticatedFilter continues filter chain after unsuccessfulAuthentication(...)
http://jira.springframework.org/browse/SEC-881. Added test class.
2008-07-31 15:42:04 +00:00
Luke Taylor 243c4f22d4 OPEN - issue SEC-899: GrantedAuthorityImpl.compareTo should handle null roles
http://jira.springframework.org/browse/SEC-899. Changed to return -1 when compared to custom auhority which returns null from getAuthority()
2008-07-31 13:01:22 +00:00
Luke Taylor d4c105d8ba OPEN - issue SEC-934: security:intercept-url throws NPE if defined twice with the same url
http://jira.springframework.org/browse/SEC-934. Added log warning when the same url is used multiple times.
2008-07-30 15:03:47 +00:00
Luke Taylor f6ff958411 Renamed rnc file. 2008-07-30 11:05:44 +00:00
Luke Taylor 4bb3eb12c3 SEC-933: global-method-security and aop:aspectj-autoproxy throws NullPointerException in some situations
http://jira.springframework.org/browse/SEC-933. Removed the setting of the attributeSource field from the interceptor in MethodDefinitionSourceAdvisor as this was overwriting the version supplied with the constructor with null (causing the NPE).
Also implemented lazy initialization of the authentication provider list from the bean factory in a custom NamespaceAuthenticationManager (extends ProviderManager and introspects the BeanFactory when getProviders() is first called). This should prevent the perennial problem of the eager initialization of UserDetailsService and other beans when the interceptor is eagerly initialized by something like aspectj-autoproxy.
2008-07-30 11:01:23 +00:00
Luke Taylor f538a36cd3 SEC-939: Changed XML header to include schema locations for clarification. 2008-07-29 10:40:50 +00:00
Luke Taylor 6e06789a28 SEC-937: Added CAS logout filter to sample application 2008-07-28 10:53:55 +00:00
Luke Taylor 6b45eda37c SEC-877, SEC-553: Added code to sandbox/other 2008-07-17 17:46:11 +00:00
Luke Taylor f453264bde SEC-909: custom remember me services doesn't get registered as logout handler
http://jira.springframework.org/browse/SEC-909. HttpSecurityBeanDefinitionParser now passes the resolved RememberMeServices bean name to the LogoutBeanDefinitionparser so that it an use it explicitly.
2008-07-15 18:22:53 +00:00
Luke Taylor 1ddc033fe5 SEC-903: Wrong attribute mapping when using jdbc-user-service bean
http://jira.springframework.org/browse/SEC-903. Corrected property name set by JdbcUserServiceBeanDefinitionParser (was setting authorities query rather than groups one).
2008-07-15 16:43:57 +00:00
Luke Taylor e303e8b71a SEC-924: Implement automatic injection of namespace created RememberMeServices into custom AbstractProcessingFilter based beans.
http://jira.springframework.org/browse/SEC-924. Delayed setting of NullRememberMeServices in AbstractProcessingFilter until afterPropertiesSet method is called, allowing the null value to be read by the namespace and the confgiured RememberMeServices bean injected.
2008-07-15 14:52:13 +00:00
Luke Taylor bf5896600e OPEN - issue SEC-913: SwitchUserProcessingFilter modifies the switchFailureUrl member variable on failure
http://jira.springframework.org/browse/SEC-913. Applied patch as suggested (use sendRedirect method for failure URL).
2008-07-15 13:42:30 +00:00
Luke Taylor b4c63db680 SEC-921: Improved messages_zh_CN.properties for Chinese
http://jira.springframework.org/browse/SEC-921. Added contributed file.
2008-07-15 11:11:21 +00:00
Luke Taylor a56c13fb22 SEC-912: Added callback methods to BasicProcessingFilter for successful and unsuccessful authentication. 2008-07-12 17:40:39 +00:00
Luke Taylor 697c7c5f48 SEC-918: Added more info on DB schema to javadoc 2008-07-12 15:21:24 +00:00
Luke Taylor b32a418175 Added mmore info on 'springSecurityFilter' chain and warning not to use this bean name explicitly 2008-07-12 15:14:43 +00:00
Luke Taylor 4cebc67088 Added example config for JDBCDaoImpl and user-service-ref in namespace 2008-07-11 19:33:15 +00:00
Luke Taylor fbc7c31b5e SEC-918: Added DDL or user and authorities tables to section on JDBC UserDetailsService 2008-07-11 19:21:00 +00:00
Luke Taylor 7dc998196a Added faq on JDK and Spring version requirements 2008-07-11 14:43:36 +00:00
Luke Taylor 768219af81 Added exta sub-headings to facilitate searching for particular topics from content page 2008-07-11 13:27:19 +00:00
Luke Taylor 7039bfdfbe Minor text spacing correction 2008-07-11 13:11:35 +00:00
Luke Taylor d13b32c77f Clarified that paths are relative to the checked out source tree 2008-07-11 12:19:19 +00:00
Luke Taylor dce709a669 Minor code formatting in docbookk 2008-07-11 12:14:00 +00:00
Luke Taylor d9634bcb39 SEC-920: Update preauth sample to make use of internal authentication manager
http://jira.springframework.org/browse/SEC-920. Updated context file to use <custom-authentication-provider>.
2008-07-11 10:56:57 +00:00
Luke Taylor 8fe1b4b402 SEC-914: Slight modification of tld description text for readability. 2008-07-11 08:14:28 +00:00
Luke Taylor 30f1e5729a SEC-914: Corrected tagllib descriptor documentation for var attribute in authentication tag. 2008-07-11 07:52:52 +00:00
Luke Taylor 6d179122d3 SEC-916: Added Spanish messages contribution. 2008-07-10 15:32:01 +00:00
Luke Taylor bd4ed794ea SEC-904: Renamed SessionRegistryImplMultithreadedTests 2008-07-02 19:25:28 +00:00
Luke Taylor 2cda6242c8 SEC-904: Moved multi-threaded tests into sandbox 2008-07-02 19:19:21 +00:00
Luke Taylor 479693ced7 SEC-900: Added extra checks on expiry time 2008-07-02 18:40:55 +00:00
Luke Taylor d5df35f739 Update sandbox poms post-release 2008-07-02 16:27:02 +00:00
Luke Taylor b99a5dec29 Various mods to heavyduty app 2008-07-02 16:25:18 +00:00
Luke Taylor e1fcacbca5 Added general question on other security concerns 2008-07-01 21:00:30 +00:00
Luke Taylor bf45ff94e7 SEC-901: Improve docs on custom-filter and avoiding conflicts with namespace filters 2008-07-01 14:20:18 +00:00
Luke Taylor c372c2df87 SEC-896: Changed result.toString() to String.valueOf(result) in tag class to prevent NPE when value of property is null 2008-06-30 21:02:23 +00:00
Luke Taylor dd5edbcce9 Added labels to faqs 2008-06-30 20:59:27 +00:00
Luke Taylor 3a25766da1 Adding sub-headings etc to 'secure objects' section 2008-06-27 13:12:27 +00:00
Luke Taylor 6ff0b969d5 Corrected ldap sample config (traditional bean version was wrong) 2008-06-23 23:43:48 +00:00
Luke Taylor 775a6c3939 [maven-release-plugin] prepare for next development iteration 2008-06-23 14:10:35 +00:00
Luke Taylor 87d50aecce [maven-release-plugin] prepare release spring-security-parent-2.0.3 2008-06-23 14:05:36 +00:00
Luke Taylor 125f5911c0 Heavyduty sample additions to check multiple-parameter values 2008-06-23 13:27:08 +00:00
Luke Taylor 57558de3ec Added error page URL to openid login sample 2008-06-23 13:18:35 +00:00
Luke Taylor 456e737d31 Corrections to readme 2008-06-23 13:16:50 +00:00
Luke Taylor 66008817c4 Changed OSGi version prior to 2.0.3 release 2008-06-23 13:14:42 +00:00
Luke Taylor 5ec06778f5 removed optional scope from jaxen dependecy in preauth sample as it breaks war file 2008-06-23 13:00:03 +00:00
302 changed files with 13822 additions and 3860 deletions
+14
View File
@@ -0,0 +1,14 @@
target
.gradle
build/
.idea
out/
*.ipr
*.iml
*.iws
intellij/
.settings
.classpath
.project
.DS_Store
atlassian-ide-plugin.xml
+19 -28
View File
@@ -3,14 +3,13 @@
<parent>
<artifactId>spring-security-parent</artifactId>
<groupId>org.springframework.security</groupId>
<version>2.0.3</version>
<version>2.0.6.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-acl</artifactId>
<name>Spring Security - ACL module</name>
<version>2.0.3</version>
<packaging>bundle</packaging>
<packaging>jar</packaging>
<dependencies>
<dependency>
@@ -25,6 +24,13 @@
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${project.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
@@ -45,29 +51,14 @@
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<spring.osgi.export>
org.springframework.security.*;version=${pom.version.osgi}
</spring.osgi.export>
<spring.osgi.import>
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
org.springframework.security.*;version="[${pom.version.osgi},${pom.version.osgi}]",
org.springframework.context.*;version="${spring.version.osgi}",
org.springframework.dao.*;version="${spring.version.osgi}";resolution:=optional,
org.springframework.jdbc.*;version="${spring.version.osgi}";resolution:=optional,
org.springframework.transaction.support.*;version="${spring.version.osgi}";resolution:=optional,
org.springframework.util.*;version="${spring.version.osgi}",
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
javax.sql.*
</spring.osgi.import>
<spring.osgi.private.pkg>
!org.springframework.security.*
</spring.osgi.private.pkg>
<spring.osgi.symbolic.name>org.springframework.security.acls</spring.osgi.symbolic.name>
</properties>
<!--
<build>
<plugins>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>
</plugins>
</build>
-->
</project>
@@ -1,39 +0,0 @@
package org.springframework.security.acls.domain;
import org.springframework.security.acls.Permission;
/**
* Provides an abstract base for standard {@link Permission} instances that wish to offer static convenience
* methods to callers via delegation to {@link DefaultPermissionFactory}.
*
* @author Ben Alex
* @since 2.0.3
*
*/
public abstract class AbstractRegisteredPermission extends AbstractPermission {
protected static DefaultPermissionFactory defaultPermissionFactory = new DefaultPermissionFactory();
protected AbstractRegisteredPermission(int mask, char code) {
super(mask, code);
}
protected final static void registerPermissionsFor(Class subClass) {
defaultPermissionFactory.registerPublicPermissions(subClass);
}
public final static Permission buildFromMask(int mask) {
return defaultPermissionFactory.buildFromMask(mask);
}
public final static Permission[] buildFromMask(int[] masks) {
return defaultPermissionFactory.buildFromMask(masks);
}
public final static Permission buildFromName(String name) {
return defaultPermissionFactory.buildFromName(name);
}
public final static Permission[] buildFromName(String[] names) {
return defaultPermissionFactory.buildFromName(names);
}
}
@@ -28,14 +28,16 @@ import org.springframework.security.acls.Permission;
* @author Ben Alex
* @version $Id$
*/
public class BasePermission extends AbstractRegisteredPermission {
public class BasePermission extends AbstractPermission {
public static final Permission READ = new BasePermission(1 << 0, 'R'); // 1
public static final Permission WRITE = new BasePermission(1 << 1, 'W'); // 2
public static final Permission CREATE = new BasePermission(1 << 2, 'C'); // 4
public static final Permission DELETE = new BasePermission(1 << 3, 'D'); // 8
public static final Permission ADMINISTRATION = new BasePermission(1 << 4, 'A'); // 16
/**
protected static DefaultPermissionFactory defaultPermissionFactory = new DefaultPermissionFactory();
/**
* Registers the public static permissions defined on this class. This is mandatory so
* that the static methods will operate correctly.
*/
@@ -46,4 +48,25 @@ public class BasePermission extends AbstractRegisteredPermission {
protected BasePermission(int mask, char code) {
super(mask, code);
}
}
protected final static void registerPermissionsFor(Class subClass) {
defaultPermissionFactory.registerPublicPermissions(subClass);
}
public final static Permission buildFromMask(int mask) {
return defaultPermissionFactory.buildFromMask(mask);
}
public final static Permission[] buildFromMask(int[] masks) {
return defaultPermissionFactory.buildFromMask(masks);
}
public final static Permission buildFromName(String name) {
return defaultPermissionFactory.buildFromName(name);
}
public final static Permission[] buildFromName(String[] names) {
return defaultPermissionFactory.buildFromName(names);
}
}
@@ -18,12 +18,14 @@ import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import javax.sql.DataSource;
@@ -173,14 +175,33 @@ public final class BasicLookupStrategy implements LookupStrategy {
auditLogger, parent, null, inputAcl.isEntriesInheriting(), inputAcl.getOwner());
// Copy the "aces" from the input to the destination
Field field = FieldUtils.getField(AclImpl.class, "aces");
Field fieldAces = FieldUtils.getField(AclImpl.class, "aces");
Field fieldAcl = FieldUtils.getField(AccessControlEntryImpl.class, "acl");
try {
field.setAccessible(true);
field.set(result, field.get(inputAcl));
fieldAces.setAccessible(true);
fieldAcl.setAccessible(true);
// Obtain the "aces" from the input ACL
Iterator i = ((List) fieldAces.get(inputAcl)).iterator();
// Create a list in which to store the "aces" for the "result" AclImpl instance
List acesNew = new ArrayList();
// Iterate over the "aces" input and replace each nested AccessControlEntryImpl.getAcl() with the new "result" AclImpl instance
// This ensures StubAclParent instances are removed, as per SEC-951
while(i.hasNext()) {
AccessControlEntryImpl ace = (AccessControlEntryImpl) i.next();
fieldAcl.set(ace, result);
acesNew.add(ace);
}
// Finally, now that the "aces" have been converted to have the "result" AclImpl instance, modify the "result" AclImpl instance
fieldAces.set(result, acesNew);
} catch (IllegalAccessException ex) {
throw new IllegalStateException("Could not obtain or set AclImpl.ace field");
throw new IllegalStateException("Could not obtain or set AclImpl or AccessControlEntryImpl fields");
}
return result;
}
@@ -32,6 +32,12 @@ public class PermissionTests {
//~ Methods ========================================================================================================
@Test
public void basePermissionTest() {
Permission p = BasePermission.buildFromName("WRITE");
assertNotNull(p);
}
@Test
public void expectedIntegerValues() {
assertEquals(1, BasePermission.READ.getMask());
@@ -53,7 +53,7 @@ public class SidTests extends TestCase {
}
try {
Authentication authentication = new TestingAuthenticationToken(null, "password", null);
Authentication authentication = new TestingAuthenticationToken(null, "password");
Sid principalSid = new PrincipalSid(authentication);
Assert.fail("It should have thrown IllegalArgumentException");
}
@@ -62,7 +62,7 @@ public class SidTests extends TestCase {
}
try {
Authentication authentication = new TestingAuthenticationToken("johndoe", "password", null);
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
Sid principalSid = new PrincipalSid(authentication);
Assert.assertTrue(true);
}
@@ -128,15 +128,15 @@ public class SidTests extends TestCase {
}
public void testPrincipalSidEquals() throws Exception {
Authentication authentication = new TestingAuthenticationToken("johndoe", "password", null);
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
Sid principalSid = new PrincipalSid(authentication);
Assert.assertFalse(principalSid.equals(null));
Assert.assertFalse(principalSid.equals("DIFFERENT_TYPE_OBJECT"));
Assert.assertTrue(principalSid.equals(principalSid));
Assert.assertTrue(principalSid.equals(new PrincipalSid(authentication)));
Assert.assertTrue(principalSid.equals(new PrincipalSid(new TestingAuthenticationToken("johndoe", null, null))));
Assert.assertFalse(principalSid.equals(new PrincipalSid(new TestingAuthenticationToken("scott", null, null))));
Assert.assertTrue(principalSid.equals(new PrincipalSid(new TestingAuthenticationToken("johndoe", null))));
Assert.assertFalse(principalSid.equals(new PrincipalSid(new TestingAuthenticationToken("scott", null))));
Assert.assertTrue(principalSid.equals(new PrincipalSid("johndoe")));
Assert.assertFalse(principalSid.equals(new PrincipalSid("scott")));
}
@@ -156,14 +156,13 @@ public class SidTests extends TestCase {
}
public void testPrincipalSidHashCode() throws Exception {
Authentication authentication = new TestingAuthenticationToken("johndoe", "password", null);
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
Sid principalSid = new PrincipalSid(authentication);
Assert.assertTrue(principalSid.hashCode() == new String("johndoe").hashCode());
Assert.assertTrue(principalSid.hashCode() == new PrincipalSid("johndoe").hashCode());
Assert.assertTrue(principalSid.hashCode() != new PrincipalSid("scott").hashCode());
Assert.assertTrue(principalSid.hashCode() != new PrincipalSid(new TestingAuthenticationToken("scott", "password",
null)).hashCode());
Assert.assertTrue(principalSid.hashCode() != new PrincipalSid(new TestingAuthenticationToken("scott", "password")).hashCode());
}
public void testGrantedAuthoritySidHashCode() throws Exception {
@@ -177,7 +176,7 @@ public class SidTests extends TestCase {
}
public void testGetters() throws Exception {
Authentication authentication = new TestingAuthenticationToken("johndoe", "password", null);
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
PrincipalSid principalSid = new PrincipalSid(authentication);
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
GrantedAuthoritySid gaSid = new GrantedAuthoritySid(ga);
+19
View File
@@ -0,0 +1,19 @@
Bundle-SymbolicName: org.springframework.security.acls
Bundle-Name: Spring Security Acls
Bundle-Vendor: SpringSource
Bundle-Version: ${version}
Bundle-ManifestVersion: 2
Ignored-Existing-Headers:
Import-Package,
Export-Package
Import-Template:
org.apache.commons.logging.*;version="[1.0.4, 2.0.0)",
org.springframework.security.*;version="[${version}, ${version}]",
org.springframework.context.*;version="[2.0.8, 3.1.0)";resolution:=optional,
org.springframework.dao.*;version="[2.0.8, 3.1.0)";resolution:=optional,
org.springframework.jdbc.core.*;version="[2.0.8, 3.1.0)";resolution:=optional,
org.springframework.transaction.support.*;version="[2.0.8, 3.1.0)";resolution:=optional,
org.springframework.util.*;version="[2.0.8, 3.1.0)";resolution:=optional,
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
javax.sql.*;version="0";resolution:=optional
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-adapters</artifactId>
<version>2.0.3</version>
<version>2.0.5.CI-SNAPSHOT</version>
</parent>
<artifactId>spring-security-catalina</artifactId>
<name>Spring Security - Catalina adapter</name>
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-adapters</artifactId>
<version>2.0.3</version>
<version>2.0.5.CI-SNAPSHOT</version>
</parent>
<artifactId>spring-security-jboss</artifactId>
<name>Spring Security - JBoss adapter</name>
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-adapters</artifactId>
<version>2.0.3</version>
<version>2.0.5.CI-SNAPSHOT</version>
</parent>
<artifactId>spring-security-jetty</artifactId>
<name>Spring Security - Jetty adapter</name>
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-parent</artifactId>
<version>2.0.3</version>
<version>2.0.5.CI-SNAPSHOT</version>
</parent>
<artifactId>spring-security-adapters</artifactId>
<name>Spring Security - Adapters</name>
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-adapters</artifactId>
<version>2.0.3</version>
<version>2.0.5.CI-SNAPSHOT</version>
</parent>
<artifactId>spring-security-resin</artifactId>
<name>Spring Security - Resin adapter</name>
+18 -27
View File
@@ -3,11 +3,11 @@
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-parent</artifactId>
<version>2.0.3</version>
<version>2.0.6.RELEASE</version>
</parent>
<artifactId>spring-security-cas-client</artifactId>
<name>Spring Security - CAS support</name>
<packaging>bundle</packaging>
<packaging>jar</packaging>
<dependencies>
<dependency>
@@ -15,6 +15,13 @@
<artifactId>spring-security-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${project.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-dao</artifactId>
@@ -31,7 +38,7 @@
<dependency>
<groupId>org.jasig.cas</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.1.3</version>
<version>3.1.5</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
@@ -40,28 +47,12 @@
</dependency>
</dependencies>
<properties>
<spring.osgi.export>
org.springframework.security.*;version=${pom.version.osgi}
</spring.osgi.export>
<spring.osgi.import>
org.springframework.security.*;version="[${pom.version.osgi},${pom.version.osgi}]",
org.springframework.beans.*;version="${spring.version.osgi}",
org.springframework.context.*;version="${spring.version.osgi}",
org.springframework.dao.*;version="${spring.version.osgi}";resolution:=optional,
org.springframework.util.*;version="${spring.version.osgi}",
javax.servlet.*;version="[2.4.0, 3.0.0)";resolution:=optional,
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
org.jasig.cas.client.*;version="[3.1.3, 4.0.0)"
</spring.osgi.import>
<spring.osgi.private.pkg>
!org.springframework.security.*
</spring.osgi.private.pkg>
<spring.osgi.symbolic.name>org.springframework.security.cas</spring.osgi.symbolic.name>
</properties>
<build>
<plugins>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -76,7 +76,7 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.userDetailsService, "A userDetailsService must be set");
Assert.notNull(this.ticketValidator, "A ticketValidator must be set");
Assert.notNull(this.statelessTicketCache, "A statelessTicketCache must be set");
@@ -140,29 +140,38 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
return result;
}
private CasAuthenticationToken authenticateNow(Authentication authentication) throws AuthenticationException {
try {
final Assertion assertion = this.ticketValidator.validate(authentication.getCredentials().toString(), serviceProperties.getService());
final UserDetails userDetails = userDetailsService.loadUserByUsername(assertion.getPrincipal().getName());
private final CasAuthenticationToken authenticateNow(final Authentication authentication) throws AuthenticationException {
try {
final Assertion assertion = this.ticketValidator.validate(authentication.getCredentials().toString(), serviceProperties.getService());
final UserDetails userDetails = loadUserByAssertion(assertion);
userDetailsChecker.check(userDetails);
return new CasAuthenticationToken(this.key, userDetails, authentication.getCredentials(),
userDetails.getAuthorities(), userDetails, assertion);
} catch (final TicketValidationException e) {
// TODO get error message
throw new BadCredentialsException("", e);
}
return new CasAuthenticationToken(this.key, userDetails, authentication.getCredentials(), userDetails.getAuthorities(), userDetails, assertion);
} catch (final TicketValidationException e) {
throw new BadCredentialsException(e.getMessage(), e);
}
}
/**
* Template method for retrieving the UserDetails based on the assertion. Default is to call configured userDetailsService and pass the username. Deployers
* can override this method and retrieve the user based on any criteria they desire.
*
* @param assertion The CAS Assertion.
* @returns the UserDetails.
*/
protected UserDetails loadUserByAssertion(final Assertion assertion) {
return this.userDetailsService.loadUserByUsername(assertion.getPrincipal().getName());
}
protected UserDetailsService getUserDetailsService() {
return userDetailsService;
}
public void setUserDetailsService(UserDetailsService userDetailsService) {
public void setUserDetailsService(final UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
public void setServiceProperties(final ServiceProperties serviceProperties) {
this.serviceProperties = serviceProperties;
this.serviceProperties = serviceProperties;
}
protected String getKey() {
@@ -181,15 +190,15 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
return ticketValidator;
}
public void setMessageSource(MessageSource messageSource) {
public void setMessageSource(final MessageSource messageSource) {
this.messages = new MessageSourceAccessor(messageSource);
}
public void setStatelessTicketCache(StatelessTicketCache statelessTicketCache) {
public void setStatelessTicketCache(final StatelessTicketCache statelessTicketCache) {
this.statelessTicketCache = statelessTicketCache;
}
public void setTicketValidator(TicketValidator ticketValidator) {
public void setTicketValidator(final TicketValidator ticketValidator) {
this.ticketValidator = ticketValidator;
}
+19
View File
@@ -0,0 +1,19 @@
Bundle-SymbolicName: org.springframework.security.cas
Bundle-Name: Spring Security CAS
Bundle-Vendor: SpringSource
Bundle-Version: ${version}
Bundle-ManifestVersion: 2
Ignored-Existing-Headers:
Import-Package,
Export-Package
Import-Template:
org.apache.commons.logging.*;version="[1.0.4, 2.0.0)",
org.jasig.cas.client.*;version="[3.1.1,3.2)",
org.springframework.security.*;version="[${version}, ${version}]",
org.springframework.beans.factory;version="[2.0.8, 3.1.0)",
org.springframework.context.*;version="[2.0.8, 3.1.0)",
org.springframework.dao;version="[2.0.8, 3.1.0)",
org.springframework.util;version="[2.0.8, 3.1.0)",
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
javax.servlet.*;version="0"
+12 -36
View File
@@ -3,9 +3,9 @@
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-parent</artifactId>
<version>2.0.3</version>
<version>2.0.6.RELEASE</version>
</parent>
<packaging>bundle</packaging>
<packaging>jar</packaging>
<artifactId>spring-security-core-tiger</artifactId>
<name>Spring Security - Java 5 (Tiger)</name>
@@ -21,7 +21,12 @@
<version>${project.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-remoting</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
@@ -54,39 +59,10 @@
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<configuration>
<targetJdk>1.5</targetJdk>
</configuration>
</plugin>
</plugins>
</reporting>
<properties>
<spring.osgi.export>
org.springframework.security.*;version=${pom.version}
</spring.osgi.export>
<spring.osgi.import>
javax.annotation.*;version="[1.0.0, 2.0.0)",
org.springframework.security.*;version="[${pom.version.osgi},${pom.version.osgi}]",
org.springframework.core.*;version="${spring.version.osgi}"
</spring.osgi.import>
<spring.osgi.private.pkg>
!org.springframework.security.*
</spring.osgi.private.pkg>
<spring.osgi.include.res>
src/main/resources
</spring.osgi.include.res>
<spring.osgi.symbolic.name>org.springframework.security.annotation</spring.osgi.symbolic.name>
</properties>
</project>
@@ -39,8 +39,10 @@ public interface BusinessService {
public void someUserMethod1();
@Secured({"ROLE_USER"})
@RolesAllowed({"ROLE_USER"})
@RolesAllowed({"ROLE_USER"})
public void someUserMethod2();
public int someOther(String s);
public int someOther(int input);
}
@@ -26,7 +26,11 @@ public class BusinessServiceImpl<E extends Entity> implements BusinessService {
return entity;
}
public int someOther(int input) {
return input;
}
public int someOther(String s) {
return 0;
}
public int someOther(int input) {
return input;
}
}
@@ -27,7 +27,11 @@ public class Jsr250BusinessServiceImpl implements BusinessService {
public void someAdminMethod() {
}
public int someOther(String input) {
return 0;
}
public int someOther(int input) {
return input;
}
}
return input;
}
}
@@ -1,13 +1,12 @@
package org.springframework.security.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*;
import static org.springframework.security.config.ConfigTestUtils.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.context.support.AbstractXmlApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.AuthenticationCredentialsNotFoundException;
import org.springframework.security.GrantedAuthority;
@@ -15,10 +14,12 @@ import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.annotation.BusinessService;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.security.util.InMemoryXmlApplicationContext;
/**
* @author Ben Alex
* @author Luke Taylor
* @version $Id$
*/
public class GlobalMethodSecurityBeanDefinitionParserTests {
@@ -27,29 +28,36 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
private BusinessService target;
public void loadContext() {
appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/global-method-security.xml");
setContext(
"<b:bean id='target' class='org.springframework.security.annotation.BusinessServiceImpl'/>" +
"<global-method-security>" +
" <protect-pointcut expression='execution(* *.someUser*(..))' access='ROLE_USER'/>" +
" <protect-pointcut expression='execution(* *.someAdmin*(..))' access='ROLE_ADMIN'/>" +
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
);
target = (BusinessService) appContext.getBean("target");
}
}
@After
public void closeAppContext() {
if (appContext != null) {
appContext.close();
appContext = null;
}
SecurityContextHolder.clearContext();
target = null;
}
@Test(expected=AuthenticationCredentialsNotFoundException.class)
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
loadContext();
loadContext();
target.someUserMethod1();
}
@Test
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
loadContext();
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_USER")});
loadContext();
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "password");
SecurityContextHolder.getContext().setAuthentication(token);
target.someUserMethod1();
@@ -57,20 +65,19 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
@Test(expected=AccessDeniedException.class)
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
loadContext();
loadContext();
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_SOMEOTHERROLE")});
SecurityContextHolder.getContext().setAuthentication(token);
target.someAdminMethod();
}
@Test
public void doesntInterfereWithBeanPostProcessing() {
setContext(
"<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>" +
"<global-method-security />" +
// "<http auto-config='true'/>" +
"<authentication-provider user-service-ref='myUserService'/>" +
"<b:bean id='beanPostProcessor' class='org.springframework.security.config.MockUserServiceBeanPostProcessor'/>"
);
@@ -79,7 +86,75 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
assertEquals("Hello from the post processor!", service.getPostProcessorWasHere());
}
@Test(expected=AccessDeniedException.class)
public void worksWithAspectJAutoproxy() {
setContext(
"<global-method-security>" +
" <protect-pointcut expression='execution(* org.springframework.security.config.*Service.*(..))'" +
" access='ROLE_SOMETHING' />" +
"</global-method-security>" +
"<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>" +
"<aop:aspectj-autoproxy />" +
"<authentication-provider user-service-ref='myUserService'/>"
);
UserDetailsService service = (UserDetailsService) appContext.getBean("myUserService");
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_SOMEOTHERROLE")});
SecurityContextHolder.getContext().setAuthentication(token);
service.loadUserByUsername("notused");
}
@Test
public void supportsMethodArgumentsInPointcut() {
setContext(
"<b:bean id='target' class='org.springframework.security.annotation.BusinessServiceImpl'/>" +
"<global-method-security>" +
" <protect-pointcut expression='execution(* org.springframework.security.annotation.BusinessService.someOther(String))' access='ROLE_ADMIN'/>" +
" <protect-pointcut expression='execution(* org.springframework.security.annotation.BusinessService.*(..))' access='ROLE_USER'/>" +
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
);
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("user", "password"));
target = (BusinessService) appContext.getBean("target");
// someOther(int) should not be matched by someOther(String), but should require ROLE_USER
target.someOther(0);
try {
// String version should required admin role
target.someOther("somestring");
fail("Expected AccessDeniedException");
} catch (AccessDeniedException expected) {
}
}
@Test
public void supportsBooleanPointcutExpressions() {
setContext(
"<b:bean id='target' class='org.springframework.security.annotation.BusinessServiceImpl'/>" +
"<global-method-security>" +
" <protect-pointcut expression=" +
" 'execution(* org.springframework.security.annotation.BusinessService.*(..)) " +
" and not execution(* org.springframework.security.annotation.BusinessService.someOther(String)))' " +
" access='ROLE_USER'/>" +
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
);
target = (BusinessService) appContext.getBean("target");
// String method should not be protected
target.someOther("somestring");
// All others should require ROLE_USER
try {
target.someOther(0);
fail("Expected AuthenticationCredentialsNotFoundException");
} catch (AuthenticationCredentialsNotFoundException expected) {
}
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("user", "password"));
target.someOther(0);
}
@Test(expected=BeanDefinitionParsingException.class)
public void duplicateElementCausesError() {
setContext(
@@ -87,8 +162,27 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
"<global-method-security />"
);
}
@Test(expected=AccessDeniedException.class)
public void worksWithoutTargetOrClass() {
setContext(
"<global-method-security secured-annotations='enabled'/>" +
"<b:bean id='businessService' class='org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean'>" +
" <b:property name='serviceUrl' value='http://localhost:8080/SomeService'/>" +
" <b:property name='serviceInterface' value='org.springframework.security.annotation.BusinessService'/>" +
"</b:bean>" + AUTH_PROVIDER_XML
);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_SOMEOTHERROLE")});
SecurityContextHolder.getContext().setAuthentication(token);
target = (BusinessService) appContext.getBean("businessService");
target.someUserMethod1();
}
private void setContext(String context) {
appContext = new InMemoryXmlApplicationContext(context);
}
}
@@ -3,7 +3,6 @@ package org.springframework.security.config;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.AuthenticationCredentialsNotFoundException;
import org.springframework.security.GrantedAuthority;
@@ -11,19 +10,23 @@ import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.annotation.BusinessService;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.util.InMemoryXmlApplicationContext;
/**
* @author Luke Taylor
* @version $Id$
*/
public class Jsr250AnnotationDrivenBeanDefinitionParserTests {
private ClassPathXmlApplicationContext appContext;
private InMemoryXmlApplicationContext appContext;
private BusinessService target;
@Before
public void loadContext() {
appContext = new ClassPathXmlApplicationContext("/org/springframework/security/config/jsr250-annotated-method-security.xml");
appContext = new InMemoryXmlApplicationContext(
"<b:bean id='target' class='org.springframework.security.annotation.Jsr250BusinessServiceImpl'/>" +
"<global-method-security jsr250-annotations='enabled'/>" + ConfigTestUtils.AUTH_PROVIDER_XML
);
target = (BusinessService) appContext.getBean("target");
}
@@ -48,7 +51,7 @@ public class Jsr250AnnotationDrivenBeanDefinitionParserTests {
target.someOther(0);
}
@Test
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
@@ -66,4 +69,4 @@ public class Jsr250AnnotationDrivenBeanDefinitionParserTests {
target.someAdminMethod();
}
}
}
@@ -3,7 +3,6 @@ package org.springframework.security.config;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.AuthenticationCredentialsNotFoundException;
import org.springframework.security.GrantedAuthority;
@@ -11,19 +10,23 @@ import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.annotation.BusinessService;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.util.InMemoryXmlApplicationContext;
/**
* @author Ben Alex
* @version $Id$
*/
public class SecuredAnnotationDrivenBeanDefinitionParserTests {
private ClassPathXmlApplicationContext appContext;
private InMemoryXmlApplicationContext appContext;
private BusinessService target;
@Before
public void loadContext() {
appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/secured-annotated-method-security.xml");
appContext = new InMemoryXmlApplicationContext(
"<b:bean id='target' class='org.springframework.security.annotation.Jsr250BusinessServiceImpl'/>" +
"<global-method-security secured-annotations='enabled'/>" + ConfigTestUtils.AUTH_PROVIDER_XML
);
target = (BusinessService) appContext.getBean("target");
}
@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<b:beans xmlns="http://www.springframework.org/schema/security"
xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
<b:bean id="target" class="org.springframework.security.annotation.BusinessServiceImpl"/>
<global-method-security>
<protect-pointcut expression="execution(* *.someUser*(..))" access="ROLE_USER"/>
<protect-pointcut expression="execution(* *.someAdmin*(..))" access="ROLE_ADMIN"/>
</global-method-security>
<authentication-provider>
<user-service>
<user name="bob" password="bobspassword" authorities="ROLE_A,ROLE_B" />
<user name="bill" password="billspassword" authorities="ROLE_A,ROLE_B,AUTH_OTHER" />
</user-service>
</authentication-provider>
</b:beans>
@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<b:beans xmlns="http://www.springframework.org/schema/security"
xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
<b:bean id="target" class="org.springframework.security.annotation.Jsr250BusinessServiceImpl"/>
<global-method-security jsr250-annotations="enabled"/>
<authentication-provider>
<user-service>
<user name="bob" password="bobspassword" authorities="ROLE_A,ROLE_B" />
<user name="bill" password="billspassword" authorities="ROLE_A,ROLE_B,AUTH_OTHER" />
</user-service>
</authentication-provider>
</b:beans>
@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<b:beans xmlns="http://www.springframework.org/schema/security"
xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
<b:bean id="target" class="org.springframework.security.annotation.Jsr250BusinessServiceImpl"/>
<global-method-security secured-annotations="enabled"/>
<authentication-provider>
<user-service>
<user name="bob" password="bobspassword" authorities="ROLE_A,ROLE_B" />
<user name="bill" password="billspassword" authorities="ROLE_A,ROLE_B,AUTH_OTHER" />
</user-service>
</authentication-provider>
</b:beans>
+12
View File
@@ -0,0 +1,12 @@
Bundle-SymbolicName: org.springframework.security.annotation
Bundle-Name: Spring Security Annotations
Bundle-Vendor: SpringSource
Bundle-Version: ${version}
Bundle-ManifestVersion: 2
Ignored-Existing-Headers:
Import-Package,
Export-Package
Import-Template:
javax.annotation.security.*;version="0";resolution:=optional,
org.springframework.security.*;version="[${version},${version}]",
org.springframework.core.*;version="[2.0.8, 3.1.0)"
+11
View File
@@ -0,0 +1,11 @@
#! /bin/sh
pushd src/main/resources/org/springframework/security/config/
echo "Converting rnc file to xsd ..."
java -jar ~/bin/trang.jar spring-security-2.0.6.rnc spring-security-2.0.6.xsd
echo "Applying XSL transformation to xsd ..."
xsltproc --output spring-security-2.0.6.xsd spring-security.xsl spring-security-2.0.6.xsd
popd
+33 -72
View File
@@ -3,9 +3,9 @@
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-parent</artifactId>
<version>2.0.3</version>
<version>2.0.6.RELEASE</version>
</parent>
<packaging>bundle</packaging>
<packaging>jar</packaging>
<artifactId>spring-security-core</artifactId>
<name>Spring Security - Core</name>
@@ -47,27 +47,27 @@
<artifactId>spring-mock</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<scope>test</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<scope>test</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
@@ -95,7 +95,7 @@
<artifactId>jaxen</artifactId>
<version>1.1.1</version>
<optional>true</optional>
</dependency>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
@@ -135,64 +135,25 @@
<version>1.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.8.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<properties>
<spring.osgi.export>
org.springframework.security.*;version=${pom.version}
</spring.osgi.export>
<spring.osgi.import>
!com.ibm.websphere.security,
javax.servlet.*;version="[2.4.0, 3.0.0)";resolution:=optional,
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
org.aopalliance.*;version="[1.0.0, 2.0.0)",
org.apache.commons.codec.*;version="[1.3.0, 2.0.0)",
org.apache.commons.collections.*;version="[3.2.0, 4.0.0)",
org.apache.commons.lang.*;version="[2.1.0, 3.0.0)",
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
org.apache.directory.server.configuration.*;version="[1.0.2, 2.0.0)";resolution:=optional,
org.apache.directory.server.core.*;version="[1.0.2, 2.0.0)";resolution:=optional,
org.apache.directory.server.protocol.*;version="[1.0.2, 2.0.0)";resolution:=optional,
org.aspectj.*;version="[1.5.4, 2.0.0)";resolution:=optional,
org.jaxen.*;version="[1.1.1, 2.0.0)";resolution:=optional,
org.springframework.aop.*;version="${spring.version.osgi}",
org.springframework.beans.*;version="${spring.version.osgi}",
org.springframework.context.*;version="${spring.version.osgi}",
org.springframework.core.*;version="${spring.version.osgi}",
org.springframework.dao.*;version="${spring.version.osgi}";resolution:=optional,
org.springframework.jdbc.*;version="${spring.version.osgi}";resolution:=optional,
org.springframework.ldap.*;version="[1.2.1.A, 2.0.0)";resolution:=optional,
org.springframework.metadata.*;version="${spring.version.osgi}",
org.springframework.mock.*;version="${spring.version.osgi}";resolution:=optional,
org.springframework.remoting.*;version="${spring.version.osgi}";resolution:=optional,
org.springframework.util.*;version="${spring.version.osgi}",
org.springframework.web.*;version="${spring.version.osgi}";resolution:=optional,
javax.crypto.*,
javax.naming.*,
javax.rmi.*,
javax.security.*,
javax.sql.*,
javax.xml.parsers.*,
org.w3c.dom.*,
org.xml.sax.*,
*;resolution:=optional
</spring.osgi.import>
<spring.osgi.private.pkg>
!org.springframework.security.*
</spring.osgi.private.pkg>
<!--
<spring.osgi.include.res>
src/main/resources
</spring.osgi.include.res>
-->
<spring.osgi.symbolic.name>org.springframework.security.core</spring.osgi.symbolic.name>
</properties>
<build>
<plugins>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -21,8 +21,13 @@ import org.springframework.util.Assert;
/**
* Basic concrete implementation of a {@link GrantedAuthority}.<p>Stores a <code>String</code> representation of an
* authority granted to the {@link Authentication} object.</p>
* Basic concrete implementation of a {@link GrantedAuthority}.
*
* <p>
* Stores a <code>String</code> representation of an authority granted to the {@link Authentication} object.
* <p>
* If compared to a custom authority which returns null from {@link #getAuthority}, the <tt>compareTo</tt>
* method will return -1, so the custom authority will take precedence.
*
* @author Ben Alex
* @version $Id$
@@ -36,7 +41,6 @@ public class GrantedAuthorityImpl implements GrantedAuthority, Serializable {
//~ Constructors ===================================================================================================
public GrantedAuthorityImpl(String role) {
super();
Assert.hasText(role, "A granted authority textual representation is required");
this.role = role;
}
@@ -71,8 +75,13 @@ public class GrantedAuthorityImpl implements GrantedAuthority, Serializable {
public int compareTo(Object o) {
if (o != null && o instanceof GrantedAuthority) {
GrantedAuthority rhs = (GrantedAuthority) o;
return this.role.compareTo(rhs.getAuthority());
String rhsRole = ((GrantedAuthority) o).getAuthority();
if (rhsRole == null) {
return -1;
}
return role.compareTo(rhsRole);
}
return -1;
}
@@ -0,0 +1,167 @@
package org.springframework.security.authoritymapping;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* <p>
* This class implements the Attributes2GrantedAuthoritiesMapper and
* MappableAttributesRetriever interfaces based on the supplied Map.
* It supports both one-to-one and one-to-many mappings. The granted
* authorities to map to can be supplied either as a String or as a
* GrantedAuthority object.
* </p>
* @author Ruud Senden
*/
public class MapBasedAttributes2GrantedAuthoritiesMapper implements Attributes2GrantedAuthoritiesMapper, MappableAttributesRetriever, InitializingBean {
private Map attributes2grantedAuthoritiesMap = null;
private String stringSeparator = ",";
private String[] mappableAttributes = null;
/**
* Check whether all properties have been set to correct values, and do some preprocessing.
*/
public void afterPropertiesSet() {
Assert.notEmpty(attributes2grantedAuthoritiesMap,"A non-empty attributes2grantedAuthoritiesMap must be supplied");
attributes2grantedAuthoritiesMap = preProcessMap(attributes2grantedAuthoritiesMap);
try {
mappableAttributes = (String[])attributes2grantedAuthoritiesMap.keySet().toArray(new String[]{});
} catch ( ArrayStoreException ase ) {
throw new IllegalArgumentException("attributes2grantedAuthoritiesMap contains non-String objects as keys");
}
}
/**
* Preprocess the given map
* @param orgMap The map to process
* @return the processed Map
*/
private Map preProcessMap(Map orgMap) {
Map result = new HashMap(orgMap.size());
Iterator it = orgMap.entrySet().iterator();
while ( it.hasNext() ) {
Map.Entry entry = (Map.Entry)it.next();
result.put(entry.getKey(),getGrantedAuthorityCollection(entry.getValue()));
}
return result;
}
/**
* Convert the given value to a collection of Granted Authorities
*
* @param value
* The value to convert to a GrantedAuthority Collection
* @return Collection containing the GrantedAuthority Collection
*/
private Collection getGrantedAuthorityCollection(Object value) {
Collection result = new ArrayList();
addGrantedAuthorityCollection(result,value);
return result;
}
/**
* Convert the given value to a collection of Granted Authorities,
* adding the result to the given result collection.
*
* @param value
* The value to convert to a GrantedAuthority Collection
* @return Collection containing the GrantedAuthority Collection
*/
private void addGrantedAuthorityCollection(Collection result, Object value) {
if ( value != null ) {
if ( value instanceof Collection ) {
addGrantedAuthorityCollection(result,(Collection)value);
} else if ( value instanceof Object[] ) {
addGrantedAuthorityCollection(result,(Object[])value);
} else if ( value instanceof String ) {
addGrantedAuthorityCollection(result,(String)value);
} else if ( value instanceof GrantedAuthority ) {
result.add(value);
} else {
throw new IllegalArgumentException("Invalid object type: "+value.getClass().getName());
}
}
}
private void addGrantedAuthorityCollection(Collection result, Collection value) {
Iterator it = value.iterator();
while ( it.hasNext() ) {
addGrantedAuthorityCollection(result,it.next());
}
}
private void addGrantedAuthorityCollection(Collection result, Object[] value) {
for ( int i = 0 ; i < value.length ; i++ ) {
addGrantedAuthorityCollection(result,value[i]);
}
}
private void addGrantedAuthorityCollection(Collection result, String value) {
StringTokenizer st = new StringTokenizer(value,stringSeparator,false);
while ( st.hasMoreTokens() ) {
String nextToken = st.nextToken();
if ( StringUtils.hasText(nextToken) ) {
result.add(new GrantedAuthorityImpl(nextToken));
}
}
}
/**
* Map the given array of attributes to Spring Security GrantedAuthorities.
*/
public GrantedAuthority[] getGrantedAuthorities(String[] attributes) {
List gaList = new ArrayList();
for (int i = 0; i < attributes.length; i++) {
Collection c = (Collection)attributes2grantedAuthoritiesMap.get(attributes[i]);
if ( c != null ) { gaList.addAll(c); }
}
GrantedAuthority[] result = new GrantedAuthority[gaList.size()];
result = (GrantedAuthority[])gaList.toArray(result);
return result;
}
/**
* @return Returns the attributes2grantedAuthoritiesMap.
*/
public Map getAttributes2grantedAuthoritiesMap() {
return attributes2grantedAuthoritiesMap;
}
/**
* @param attributes2grantedAuthoritiesMap The attributes2grantedAuthoritiesMap to set.
*/
public void setAttributes2grantedAuthoritiesMap(Map attributes2grantedAuthoritiesMap) {
this.attributes2grantedAuthoritiesMap = attributes2grantedAuthoritiesMap;
}
/**
*
* @see org.springframework.security.authoritymapping.MappableAttributesRetriever#getMappableAttributes()
*/
public String[] getMappableAttributes() {
return mappableAttributes;
}
/**
* @return Returns the stringSeparator.
*/
public String getStringSeparator() {
return stringSeparator;
}
/**
* @param stringSeparator The stringSeparator to set.
*/
public void setStringSeparator(String stringSeparator) {
this.stringSeparator = stringSeparator;
}
}
@@ -61,14 +61,13 @@ public class AnonymousBeanDefinitionParser implements BeanDefinitionParser {
filter.getPropertyValues().addPropertyValue("userAttribute", username + "," + grantedAuthority);
filter.getPropertyValues().addPropertyValue(ATT_KEY, key);
BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);
RootBeanDefinition provider = new RootBeanDefinition(AnonymousAuthenticationProvider.class);
provider.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
provider.setSource(source);
provider.getPropertyValues().addPropertyValue(ATT_KEY, key);
ManagedList authMgrProviderList = (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
authMgrProviderList.add(provider);
parserContext.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_AUTHENTICATION_PROVIDER, provider);
ConfigUtils.addAuthenticationProvider(parserContext, BeanIds.ANONYMOUS_AUTHENTICATION_PROVIDER);
parserContext.getRegistry().registerBeanDefinition(BeanIds.ANONYMOUS_PROCESSING_FILTER, filter);
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.ANONYMOUS_PROCESSING_FILTER));
@@ -22,7 +22,7 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
private static final String ATT_ALIAS = "alias";
public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);
ConfigUtils.registerProviderManagerIfNecessary(parserContext);
String alias = element.getAttribute(ATT_ALIAS);
@@ -33,6 +33,7 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
String sessionControllerRef = element.getAttribute(ATT_SESSION_CONTROLLER_REF);
if (StringUtils.hasText(sessionControllerRef)) {
BeanDefinition authManager = parserContext.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
ConfigUtils.setSessionControllerOnAuthenticationManager(parserContext,
BeanIds.CONCURRENT_SESSION_CONTROLLER, element);
authManager.getPropertyValues().addPropertyValue("sessionController",
@@ -94,7 +94,7 @@ class AuthenticationProviderBeanDefinitionParser implements BeanDefinitionParser
parserContext.getRegistry().registerBeanDefinition(name , cacheResolver);
parserContext.registerComponent(new BeanComponentDefinition(cacheResolver, name));
ConfigUtils.getRegisteredProviders(parserContext).add(new RuntimeBeanReference(id));
ConfigUtils.addAuthenticationProvider(parserContext, id);
return null;
}
@@ -42,6 +42,7 @@ public abstract class BeanIds {
public static final String MAIN_ENTRY_POINT = "_mainEntryPoint";
public static final String FILTER_CHAIN_PROXY = "_filterChainProxy";
public static final String HTTP_SESSION_CONTEXT_INTEGRATION_FILTER = "_httpSessionContextIntegrationFilter";
public static final String LDAP_AUTHENTICATION_PROVIDER = "_ldapAuthenticationProvider";
public static final String LOGOUT_FILTER = "_logoutFilter";
public static final String EXCEPTION_TRANSLATION_FILTER = "_exceptionTranslationFilter";
public static final String FILTER_SECURITY_INTERCEPTOR = "_filterSecurityInterceptor";
@@ -49,6 +50,7 @@ public abstract class BeanIds {
public static final String CHANNEL_DECISION_MANAGER = "_channelDecisionManager";
public static final String REMEMBER_ME_FILTER = "_rememberMeFilter";
public static final String REMEMBER_ME_SERVICES = "_rememberMeServices";
public static final String REMEMBER_ME_AUTHENTICATION_PROVIDER = "_rememberMeAuthenticationProvider";
public static final String DEFAULT_LOGIN_PAGE_GENERATING_FILTER = "_defaultLoginPageFilter";
public static final String SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER = "_securityContextHolderAwareRequestFilter";
public static final String SESSION_FIXATION_PROTECTION_FILTER = "_sessionFixationProtectionFilter";
@@ -66,5 +68,4 @@ public abstract class BeanIds {
public static final String X509_AUTH_PROVIDER = "_x509AuthenticationProvider";
public static final String PRE_AUTH_ENTRY_POINT = "_preAuthenticatedProcessingFilterEntryPoint";
public static final String REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR = "_rememberMeServicesInjectionBeanPostProcessor";
}
@@ -1,7 +1,7 @@
package org.springframework.security.config;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -9,15 +9,12 @@ import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.afterinvocation.AfterInvocationProviderManager;
import org.springframework.security.providers.ProviderManager;
import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.security.util.UrlUtils;
import org.springframework.security.vote.AffirmativeBased;
import org.springframework.security.vote.AuthenticatedVoter;
@@ -80,21 +77,20 @@ public abstract class ConfigUtils {
* using the &lt;security:provider /> tag or by other beans which have a dependency on the
* authentication manager.
*/
static BeanDefinition registerProviderManagerIfNecessary(ParserContext parserContext) {
static void registerProviderManagerIfNecessary(ParserContext parserContext) {
if(parserContext.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER)) {
return parserContext.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
return;
}
BeanDefinition authManager = new RootBeanDefinition(ProviderManager.class);
authManager.getPropertyValues().addPropertyValue("providers", new ManagedList());
BeanDefinition authManager = new RootBeanDefinition(NamespaceAuthenticationManager.class);
authManager.getPropertyValues().addPropertyValue("providerBeanNames", new ArrayList());
parserContext.getRegistry().registerBeanDefinition(BeanIds.AUTHENTICATION_MANAGER, authManager);
return authManager;
}
static ManagedList getRegisteredProviders(ParserContext parserContext) {
BeanDefinition authManager = registerProviderManagerIfNecessary(parserContext);
return (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
static void addAuthenticationProvider(ParserContext parserContext, String beanName) {
registerProviderManagerIfNecessary(parserContext);
BeanDefinition authManager = parserContext.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
((ArrayList) authManager.getPropertyValues().getPropertyValue("providerBeanNames").getValue()).add(beanName);
}
static ManagedList getRegisteredAfterInvocationProviders(ParserContext parserContext) {
@@ -172,7 +168,8 @@ public abstract class ConfigUtils {
}
static void setSessionControllerOnAuthenticationManager(ParserContext pc, String beanName, Element sourceElt) {
BeanDefinition authManager = registerProviderManagerIfNecessary(pc);
registerProviderManagerIfNecessary(pc);
BeanDefinition authManager = pc.getRegistry().getBeanDefinition(BeanIds.AUTHENTICATION_MANAGER);
PropertyValue pv = authManager.getPropertyValues().getPropertyValue("sessionController");
if (pv != null && pv.getValue() != null) {
@@ -17,7 +17,7 @@ import org.w3c.dom.Node;
*/
public class CustomAuthenticationProviderBeanDefinitionDecorator implements BeanDefinitionDecorator {
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext parserContext) {
ConfigUtils.getRegisteredProviders(parserContext).add(new RuntimeBeanReference(holder.getBeanName()));
ConfigUtils.addAuthenticationProvider(parserContext, holder.getBeanName());
return holder;
}
@@ -10,34 +10,35 @@ abstract class Elements {
public static final String AUTHENTICATION_MANAGER = "authentication-manager";
public static final String USER_SERVICE = "user-service";
public static final String JDBC_USER_SERVICE = "jdbc-user-service";
public static final String FILTER_CHAIN_MAP = "filter-chain-map";
public static final String INTERCEPT_METHODS = "intercept-methods";
public static final String INTERCEPT_URL = "intercept-url";
public static final String AUTHENTICATION_PROVIDER = "authentication-provider";
public static final String HTTP = "http";
public static final String LDAP_PROVIDER = "ldap-authentication-provider";
public static final String LDAP_SERVER = "ldap-server";
public static final String JDBC_USER_SERVICE = "jdbc-user-service";
public static final String FILTER_CHAIN_MAP = "filter-chain-map";
public static final String INTERCEPT_METHODS = "intercept-methods";
public static final String INTERCEPT_URL = "intercept-url";
public static final String AUTHENTICATION_PROVIDER = "authentication-provider";
public static final String HTTP = "http";
public static final String LDAP_PROVIDER = "ldap-authentication-provider";
public static final String LDAP_SERVER = "ldap-server";
public static final String LDAP_USER_SERVICE = "ldap-user-service";
public static final String PROTECT_POINTCUT = "protect-pointcut";
public static final String PROTECT = "protect";
public static final String CONCURRENT_SESSIONS = "concurrent-session-control";
public static final String LOGOUT = "logout";
public static final String FORM_LOGIN = "form-login";
public static final String OPENID_LOGIN = "openid-login";
public static final String BASIC_AUTH = "http-basic";
public static final String REMEMBER_ME = "remember-me";
public static final String ANONYMOUS = "anonymous";
public static final String FILTER_CHAIN = "filter-chain";
public static final String GLOBAL_METHOD_SECURITY = "global-method-security";
public static final String PASSWORD_ENCODER = "password-encoder";
public static final String SALT_SOURCE = "salt-source";
public static final String PORT_MAPPINGS = "port-mappings";
public static final String CONCURRENT_SESSIONS = "concurrent-session-control";
public static final String LOGOUT = "logout";
public static final String FORM_LOGIN = "form-login";
public static final String OPENID_LOGIN = "openid-login";
public static final String BASIC_AUTH = "http-basic";
public static final String REMEMBER_ME = "remember-me";
public static final String ANONYMOUS = "anonymous";
public static final String FILTER_CHAIN = "filter-chain";
public static final String GLOBAL_METHOD_SECURITY = "global-method-security";
public static final String PASSWORD_ENCODER = "password-encoder";
public static final String SALT_SOURCE = "salt-source";
public static final String PORT_MAPPINGS = "port-mappings";
public static final String PORT_MAPPING = "port-mapping";
public static final String CUSTOM_FILTER = "custom-filter";
public static final String CUSTOM_AUTH_PROVIDER = "custom-authentication-provider";
public static final String CUSTOM_AFTER_INVOCATION_PROVIDER = "custom-after-invocation-provider";
public static final String CUSTOM_AFTER_INVOCATION_PROVIDER = "custom-after-invocation-provider";
public static final String X509 = "x509";
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
public static final String HTTP_FIREWALL = "http-firewall";
}
@@ -20,14 +20,13 @@ import org.springframework.security.intercept.method.MapBasedMethodDefinitionSou
import org.springframework.security.intercept.method.ProtectPointcutPostProcessor;
import org.springframework.security.intercept.method.aopalliance.MethodDefinitionSourceAdvisor;
import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
* Processes the top-level "global-method-security" element.
*
*
* @author Ben Alex
* @version $Id$
*/
@@ -42,32 +41,26 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
private static final String ATT_USE_JSR250 = "jsr250-annotations";
private static final String ATT_USE_SECURED = "secured-annotations";
private void validatePresent(String className, Element element, ParserContext parserContext) {
if (!ClassUtils.isPresent(className, parserContext.getReaderContext().getBeanClassLoader())) {
parserContext.getReaderContext().error("Cannot locate '" + className + "'", element);
}
}
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
// The list of method metadata delegates
ManagedList delegates = new ManagedList();
boolean jsr250Enabled = registerAnnotationBasedMethodDefinitionSources(element, parserContext, delegates);
MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource = new MapBasedMethodDefinitionSource();
delegates.add(mapBasedMethodDefinitionSource);
// Now create a Map<String, ConfigAttribute> for each <protect-pointcut> sub-element
Map pointcutMap = parseProtectPointcuts(parserContext,
// Now create a Map<String, ConfigAttribute> for each <protect-pointcut> sub-element
Map pointcutMap = parseProtectPointcuts(parserContext,
DomUtils.getChildElementsByTagName(element, Elements.PROTECT_POINTCUT));
if (pointcutMap.size() > 0) {
registerProtectPointcutPostProcessor(parserContext, pointcutMap, mapBasedMethodDefinitionSource, source);
}
registerDelegatingMethodDefinitionSource(parserContext, delegates, source);
// Register the applicable AccessDecisionManager, handling the special JSR 250 voter if being used
String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
@@ -75,45 +68,40 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
ConfigUtils.registerDefaultAccessManagerIfNecessary(parserContext);
if (jsr250Enabled) {
ConfigUtils.addVoter(new RootBeanDefinition(JSR_250_VOTER_CLASS, null, null), parserContext);
ConfigUtils.addVoter(new RootBeanDefinition(JSR_250_VOTER_CLASS, null, null), parserContext);
}
accessManagerId = BeanIds.ACCESS_MANAGER;
}
registerMethodSecurityInterceptor(parserContext, accessManagerId, source);
registerAdvisor(parserContext, source);
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
return null;
}
/**
* Checks whether JSR-250 and/or Secured annotations are enabled and adds the appropriate
* MethodDefinitionSource delegates if required.
* Checks whether JSR-250 and/or Secured annotations are enabled and adds the appropriate
* MethodDefinitionSource delegates if required.
*/
private boolean registerAnnotationBasedMethodDefinitionSources(Element element, ParserContext pc, ManagedList delegates) {
boolean useJsr250 = "enabled".equals(element.getAttribute(ATT_USE_JSR250));
boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED));
// Check the required classes are present
if (useSecured) {
validatePresent(SECURED_METHOD_DEFINITION_SOURCE_CLASS, element, pc);
validatePresent(SECURED_DEPENDENCY_CLASS, element, pc);
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(SECURED_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
}
if (useJsr250) {
validatePresent(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS, element, pc);
validatePresent(JSR_250_VOTER_CLASS, element, pc);
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
}
return useJsr250;
}
private void registerDelegatingMethodDefinitionSource(ParserContext parserContext, ManagedList delegates, Object source) {
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE)) {
parserContext.getReaderContext().error("Duplicate <global-method-security> detected.", source);
@@ -122,9 +110,9 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
delegatingMethodDefinitionSource.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
delegatingMethodDefinitionSource.setSource(source);
delegatingMethodDefinitionSource.getPropertyValues().addPropertyValue("methodDefinitionSources", delegates);
parserContext.getRegistry().registerBeanDefinition(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE, delegatingMethodDefinitionSource);
parserContext.getRegistry().registerBeanDefinition(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE, delegatingMethodDefinitionSource);
}
private void registerProtectPointcutPostProcessor(ParserContext parserContext, Map pointcutMap,
MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource, Object source) {
RootBeanDefinition ppbp = new RootBeanDefinition(ProtectPointcutPostProcessor.class);
@@ -162,13 +150,13 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
RootBeanDefinition interceptor = new RootBeanDefinition(MethodSecurityInterceptor.class);
interceptor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
interceptor.setSource(source);
interceptor.getPropertyValues().addPropertyValue("accessDecisionManager", new RuntimeBeanReference(accessManagerId));
interceptor.getPropertyValues().addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
interceptor.getPropertyValues().addPropertyValue("objectDefinitionSource", new RuntimeBeanReference(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE));
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_INTERCEPTOR, interceptor);
parserContext.registerComponent(new BeanComponentDefinition(interceptor, BeanIds.METHOD_SECURITY_INTERCEPTOR));
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_INTERCEPTOR_POST_PROCESSOR,
new RootBeanDefinition(MethodSecurityInterceptorPostProcessor.class));
}
@@ -180,6 +168,6 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
advisor.getConstructorArgumentValues().addGenericArgumentValue(BeanIds.METHOD_SECURITY_INTERCEPTOR);
advisor.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE));
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_DEFINITION_SOURCE_ADVISOR, advisor);
}
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_DEFINITION_SOURCE_ADVISOR, advisor);
}
}
@@ -0,0 +1,31 @@
package org.springframework.security.config;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Injects the supplied {@code HttpFirewall} bean reference into the {@code FilterChainProxy}.
*
* @author Luke Taylor
*/
public class HttpFirewallBeanDefinitionParser implements BeanDefinitionParser {
public BeanDefinition parse(Element element, ParserContext pc) {
String ref = element.getAttribute("ref");
if (!StringUtils.hasText(ref)) {
pc.getReaderContext().error("ref attribute is required", pc.extractSource(element));
}
BeanDefinitionBuilder injector = BeanDefinitionBuilder.rootBeanDefinition(HttpFirewallInjectionBeanPostProcessor.class);
injector.addConstructorArg(ref);
pc.getReaderContext().registerWithGeneratedName(injector.getBeanDefinition());
return null;
}
}
@@ -0,0 +1,40 @@
package org.springframework.security.config;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.security.config.BeanIds;
import org.springframework.security.util.FilterChainProxy;
import org.springframework.security.firewall.HttpFirewall;
/**
* @author Luke Taylor
*/
public class HttpFirewallInjectionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
private ConfigurableListableBeanFactory beanFactory;
private String ref;
public HttpFirewallInjectionBeanPostProcessor(String ref) {
this.ref = ref;
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (BeanIds.FILTER_CHAIN_PROXY.equals(beanName)) {
HttpFirewall fw = (HttpFirewall) beanFactory.getBean(ref);
((FilterChainProxy)bean).setFirewall(fw);
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
}
@@ -50,16 +50,16 @@ import org.w3c.dom.Element;
* @version $Id$
*/
public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
protected final Log logger = LogFactory.getLog(getClass());
static final Log logger = LogFactory.getLog(HttpSecurityBeanDefinitionParser.class);
static final String ATT_REALM = "realm";
static final String DEF_REALM = "Spring Security Application";
static final String ATT_PATH_PATTERN = "pattern";
static final String ATT_SESSION_FIXATION_PROTECTION = "session-fixation-protection";
static final String OPT_SESSION_FIXATION_NO_PROTECTION = "none";
static final String OPT_SESSION_FIXATION_CLEAN_SESSION = "newSession";
static final String OPT_SESSION_FIXATION_CLEAN_SESSION = "newSession";
static final String OPT_SESSION_FIXATION_MIGRATE_SESSION = "migrateSession";
static final String ATT_PATH_TYPE = "path-type";
@@ -91,9 +91,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
static final String ATT_SERVLET_API_PROVISION = "servlet-api-provision";
static final String DEF_SERVLET_API_PROVISION = "true";
static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
static final String ATT_USER_SERVICE_REF = "user-service-ref";
static final String ATT_ENTRY_POINT_REF = "entry-point-ref";
static final String ATT_ONCE_PER_REQUEST = "once-per-request";
static final String ATT_ACCESS_DENIED_PAGE = "access-denied-page";
@@ -106,20 +106,20 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
// SEC-501 - should paths stored in request maps be converted to lower case
// true if Ant path and using lower case
final boolean convertPathsToLowerCase = (matcher instanceof AntUrlPathMatcher) && matcher.requiresLowerCaseUrl();
final List interceptUrlElts = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL);
final Map filterChainMap = new LinkedHashMap();
final LinkedHashMap channelRequestMap = new LinkedHashMap();
registerFilterChainProxy(parserContext, filterChainMap, matcher, source);
parseInterceptUrlsForChannelSecurityAndFilterChain(interceptUrlElts, filterChainMap, channelRequestMap,
parseInterceptUrlsForChannelSecurityAndFilterChain(interceptUrlElts, filterChainMap, channelRequestMap,
convertPathsToLowerCase, parserContext);
boolean allowSessionCreation = registerHttpSessionIntegrationFilter(element, parserContext);
registerServletApiFilter(element, parserContext);
// Set up the access manager reference for http
String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
@@ -127,7 +127,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
ConfigUtils.registerDefaultAccessManagerIfNecessary(parserContext);
accessManagerId = BeanIds.ACCESS_MANAGER;
}
// Register the portMapper. A default will always be created, even if no element exists.
BeanDefinition portMapper = new PortMappingsBeanDefinitionParser().parse(
DomUtils.getChildElementByTagName(element, Elements.PORT_MAPPINGS), parserContext);
@@ -139,19 +139,19 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
if (channelRequestMap.size() > 0) {
// At least one channel requirement has been specified
registerChannelProcessingBeans(parserContext, matcher, channelRequestMap);
}
registerFilterSecurityInterceptor(element, parserContext, matcher, accessManagerId,
}
registerFilterSecurityInterceptor(element, parserContext, matcher, accessManagerId,
parseInterceptUrlsForFilterInvocationRequestMap(interceptUrlElts, convertPathsToLowerCase, parserContext));
boolean sessionControlEnabled = registerConcurrentSessionControlBeansIfRequired(element, parserContext);
registerSessionFixationProtectionFilter(parserContext, element.getAttribute(ATT_SESSION_FIXATION_PROTECTION),
registerSessionFixationProtectionFilter(parserContext, element.getAttribute(ATT_SESSION_FIXATION_PROTECTION),
sessionControlEnabled);
boolean autoConfig = false;
if ("true".equals(element.getAttribute(ATT_AUTO_CONFIG))) {
autoConfig = true;
autoConfig = true;
}
Element anonymousElt = DomUtils.getChildElementByTagName(element, Elements.ANONYMOUS);
@@ -159,21 +159,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
new AnonymousBeanDefinitionParser().parse(anonymousElt, parserContext);
}
// Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation.
Element rememberMeElt = DomUtils.getChildElementByTagName(element, Elements.REMEMBER_ME);
if (rememberMeElt != null || autoConfig) {
new RememberMeBeanDefinitionParser().parse(rememberMeElt, parserContext);
// Post processor to inject RememberMeServices into filters which need it
RootBeanDefinition rememberMeInjectionPostProcessor = new RootBeanDefinition(RememberMeServicesInjectionBeanPostProcessor.class);
rememberMeInjectionPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR, rememberMeInjectionPostProcessor);
}
Element logoutElt = DomUtils.getChildElementByTagName(element, Elements.LOGOUT);
if (logoutElt != null || autoConfig) {
new LogoutBeanDefinitionParser().parse(logoutElt, parserContext);
}
parseRememberMeAndLogout(element, autoConfig, parserContext);
parseBasicFormLoginAndOpenID(element, parserContext, autoConfig, allowSessionCreation);
Element x509Elt = DomUtils.getChildElementByTagName(element, Elements.X509);
@@ -188,27 +175,49 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
RootBeanDefinition postProcessor2 = new RootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
postProcessor2.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BeanIds.USER_DETAILS_SERVICE_INJECTION_POST_PROCESSOR, postProcessor2);
return null;
}
private void parseRememberMeAndLogout(Element elt, boolean autoConfig, ParserContext pc) {
// Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation.
Element rememberMeElt = DomUtils.getChildElementByTagName(elt, Elements.REMEMBER_ME);
String rememberMeServices = null;
if (rememberMeElt != null || autoConfig) {
RememberMeBeanDefinitionParser rmbdp = new RememberMeBeanDefinitionParser();
rmbdp.parse(rememberMeElt, pc);
rememberMeServices = rmbdp.getServicesName();
// Post processor to inject RememberMeServices into filters which need it
RootBeanDefinition rememberMeInjectionPostProcessor = new RootBeanDefinition(RememberMeServicesInjectionBeanPostProcessor.class);
rememberMeInjectionPostProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES_INJECTION_POST_PROCESSOR, rememberMeInjectionPostProcessor);
}
Element logoutElt = DomUtils.getChildElementByTagName(elt, Elements.LOGOUT);
if (logoutElt != null || autoConfig) {
new LogoutBeanDefinitionParser(rememberMeServices).parse(logoutElt, pc);
}
}
private void registerFilterChainProxy(ParserContext pc, Map filterChainMap, UrlMatcher matcher, Object source) {
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
pc.getReaderContext().error("Duplicate <http> element detected", source);
}
RootBeanDefinition filterChainProxy = new RootBeanDefinition(FilterChainProxy.class);
filterChainProxy.setSource(source);
filterChainProxy.getPropertyValues().addPropertyValue("matcher", matcher);
filterChainProxy.getPropertyValues().addPropertyValue("stripQueryStringFromUrls", Boolean.valueOf(matcher instanceof AntUrlPathMatcher));
filterChainProxy.getPropertyValues().addPropertyValue("filterChainMap", filterChainMap);
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_CHAIN_PROXY, filterChainProxy);
pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
}
private boolean registerHttpSessionIntegrationFilter(Element element, ParserContext pc) {
RootBeanDefinition httpScif = new RootBeanDefinition(HttpSessionContextIntegrationFilter.class);
boolean sessionCreationAllowed = true;
String createSession = element.getAttribute(ATT_CREATE_SESSION);
if (OPT_CREATE_SESSION_ALWAYS.equals(createSession)) {
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.TRUE);
@@ -225,11 +234,11 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
pc.getRegistry().registerBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER, httpScif);
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER));
return sessionCreationAllowed;
}
// Adds the servlet-api integration filter if required
// Adds the servlet-api integration filter if required
private void registerServletApiFilter(Element element, ParserContext pc) {
String provideServletApi = element.getAttribute(ATT_SERVLET_API_PROVISION);
if (!StringUtils.hasText(provideServletApi)) {
@@ -242,57 +251,57 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER));
}
}
private boolean registerConcurrentSessionControlBeansIfRequired(Element element, ParserContext parserContext) {
Element sessionControlElt = DomUtils.getChildElementByTagName(element, Elements.CONCURRENT_SESSIONS);
if (sessionControlElt == null) {
return false;
}
new ConcurrentSessionsBeanDefinitionParser().parse(sessionControlElt, parserContext);
logger.info("Concurrent session filter in use, setting 'forceEagerSessionCreation' to true");
BeanDefinition sessionIntegrationFilter = parserContext.getRegistry().getBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER);
BeanDefinition sessionIntegrationFilter = parserContext.getRegistry().getBeanDefinition(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER);
sessionIntegrationFilter.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
return true;
}
private void registerExceptionTranslationFilter(Element element, ParserContext pc, boolean allowSessionCreation) {
String accessDeniedPage = element.getAttribute(ATT_ACCESS_DENIED_PAGE);
ConfigUtils.validateHttpRedirect(accessDeniedPage, pc, pc.extractSource(element));
String accessDeniedPage = element.getAttribute(ATT_ACCESS_DENIED_PAGE);
ConfigUtils.validateHttpRedirect(accessDeniedPage, pc, pc.extractSource(element));
BeanDefinitionBuilder exceptionTranslationFilterBuilder
= BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
exceptionTranslationFilterBuilder.addPropertyValue("createSessionAllowed", new Boolean(allowSessionCreation));
if (StringUtils.hasText(accessDeniedPage)) {
AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl();
accessDeniedHandler.setErrorPage(accessDeniedPage);
BeanDefinition accessDeniedHandler = new RootBeanDefinition(AccessDeniedHandlerImpl.class);
accessDeniedHandler.getPropertyValues().addPropertyValue("errorPage", accessDeniedPage);
exceptionTranslationFilterBuilder.addPropertyValue("accessDeniedHandler", accessDeniedHandler);
}
pc.getRegistry().registerBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER, exceptionTranslationFilterBuilder.getBeanDefinition());
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.EXCEPTION_TRANSLATION_FILTER));
}
private void registerFilterSecurityInterceptor(Element element, ParserContext pc, UrlMatcher matcher,
String accessManagerId, LinkedHashMap filterInvocationDefinitionMap) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class);
builder.addPropertyReference("accessDecisionManager", accessManagerId);
builder.addPropertyReference("authenticationManager", BeanIds.AUTHENTICATION_MANAGER);
if ("false".equals(element.getAttribute(ATT_ONCE_PER_REQUEST))) {
builder.addPropertyValue("observeOncePerRequest", Boolean.FALSE);
}
DefaultFilterInvocationDefinitionSource fids =
DefaultFilterInvocationDefinitionSource fids =
new DefaultFilterInvocationDefinitionSource(matcher, filterInvocationDefinitionMap);
fids.setStripQueryStringFromUrls(matcher instanceof AntUrlPathMatcher);
builder.addPropertyValue("objectDefinitionSource", fids);
pc.getRegistry().registerBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR, builder.getBeanDefinition());
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FILTER_SECURITY_INTERCEPTOR));
}
private void registerChannelProcessingBeans(ParserContext pc, UrlMatcher matcher, LinkedHashMap channelRequestMap) {
RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class);
channelFilter.getPropertyValues().addPropertyValue("channelDecisionManager",
@@ -300,7 +309,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
DefaultFilterInvocationDefinitionSource channelFilterInvDefSource =
new DefaultFilterInvocationDefinitionSource(matcher, channelRequestMap);
channelFilterInvDefSource.setStripQueryStringFromUrls(matcher instanceof AntUrlPathMatcher);
channelFilter.getPropertyValues().addPropertyValue("filterInvocationDefinitionSource",
channelFilterInvDefSource);
RootBeanDefinition channelDecisionManager = new RootBeanDefinition(ChannelDecisionManagerImpl.class);
@@ -321,161 +330,161 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_PROCESSING_FILTER, channelFilter);
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.CHANNEL_PROCESSING_FILTER));
pc.getRegistry().registerBeanDefinition(BeanIds.CHANNEL_DECISION_MANAGER, channelDecisionManager);
}
private void registerSessionFixationProtectionFilter(ParserContext pc, String sessionFixationAttribute, boolean sessionControlEnabled) {
if(!StringUtils.hasText(sessionFixationAttribute)) {
sessionFixationAttribute = OPT_SESSION_FIXATION_MIGRATE_SESSION;
}
if (!sessionFixationAttribute.equals(OPT_SESSION_FIXATION_NO_PROTECTION)) {
BeanDefinitionBuilder sessionFixationFilter =
BeanDefinitionBuilder sessionFixationFilter =
BeanDefinitionBuilder.rootBeanDefinition(SessionFixationProtectionFilter.class);
sessionFixationFilter.addPropertyValue("migrateSessionAttributes",
sessionFixationFilter.addPropertyValue("migrateSessionAttributes",
Boolean.valueOf(sessionFixationAttribute.equals(OPT_SESSION_FIXATION_MIGRATE_SESSION)));
if (sessionControlEnabled) {
sessionFixationFilter.addPropertyReference("sessionRegistry", BeanIds.SESSION_REGISTRY);
}
pc.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER,
pc.getRegistry().registerBeanDefinition(BeanIds.SESSION_FIXATION_PROTECTION_FILTER,
sessionFixationFilter.getBeanDefinition());
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.SESSION_FIXATION_PROTECTION_FILTER));
}
}
private void parseBasicFormLoginAndOpenID(Element element, ParserContext pc, boolean autoConfig, boolean allowSessionCreation) {
RootBeanDefinition formLoginFilter = null;
RootBeanDefinition formLoginEntryPoint = null;
String formLoginPage = null;
String formLoginPage = null;
RootBeanDefinition openIDFilter = null;
RootBeanDefinition openIDEntryPoint = null;
String openIDLoginPage = null;
String realm = element.getAttribute(ATT_REALM);
if (!StringUtils.hasText(realm)) {
realm = DEF_REALM;
realm = DEF_REALM;
}
Element basicAuthElt = DomUtils.getChildElementByTagName(element, Elements.BASIC_AUTH);
if (basicAuthElt != null || autoConfig) {
new BasicAuthenticationBeanDefinitionParser(realm).parse(basicAuthElt, pc);
}
Element formLoginElt = DomUtils.getChildElementByTagName(element, Elements.FORM_LOGIN);
Element formLoginElt = DomUtils.getChildElementByTagName(element, Elements.FORM_LOGIN);
if (formLoginElt != null || autoConfig) {
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
"org.springframework.security.ui.webapp.AuthenticationProcessingFilter");
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
"org.springframework.security.ui.webapp.AuthenticationProcessingFilter");
parser.parse(formLoginElt, pc);
formLoginFilter = parser.getFilterBean();
formLoginEntryPoint = parser.getEntryPointBean();
formLoginPage = parser.getLoginPage();
}
Element openIDLoginElt = DomUtils.getChildElementByTagName(element, Elements.OPENID_LOGIN);
if (openIDLoginElt != null) {
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
"org.springframework.security.ui.openid.OpenIDAuthenticationProcessingFilter");
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
"org.springframework.security.ui.openid.OpenIDAuthenticationProcessingFilter");
parser.parse(openIDLoginElt, pc);
openIDFilter = parser.getFilterBean();
openIDEntryPoint = parser.getEntryPointBean();
openIDLoginPage = parser.getLoginPage();
BeanDefinitionBuilder openIDProviderBuilder =
BeanDefinitionBuilder openIDProviderBuilder =
BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.providers.openid.OpenIDAuthenticationProvider");
String userService = openIDLoginElt.getAttribute(ATT_USER_SERVICE_REF);
if (StringUtils.hasText(userService)) {
openIDProviderBuilder.addPropertyReference("userDetailsService", userService);
}
BeanDefinition openIDProvider = openIDProviderBuilder.getBeanDefinition();
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_PROVIDER, openIDProvider);
ConfigUtils.getRegisteredProviders(pc).add(new RuntimeBeanReference(BeanIds.OPEN_ID_PROVIDER));
ConfigUtils.addAuthenticationProvider(pc, BeanIds.OPEN_ID_PROVIDER);
}
boolean needLoginPage = false;
if (formLoginFilter != null) {
needLoginPage = true;
formLoginFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, formLoginFilter);
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, formLoginEntryPoint);
}
needLoginPage = true;
formLoginFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_FILTER, formLoginFilter);
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
pc.getRegistry().registerBeanDefinition(BeanIds.FORM_LOGIN_ENTRY_POINT, formLoginEntryPoint);
}
if (openIDFilter != null) {
needLoginPage = true;
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openIDFilter);
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openIDEntryPoint);
needLoginPage = true;
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_FILTER, openIDFilter);
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_ENTRY_POINT, openIDEntryPoint);
}
// If no login page has been defined, add in the default page generator.
if (needLoginPage && formLoginPage == null && openIDLoginPage == null) {
logger.info("No login page configured. The default internal one will be used. Use the '"
+ FormLoginBeanDefinitionParser.ATT_LOGIN_PAGE + "' attribute to set the URL of the login page.");
BeanDefinitionBuilder loginPageFilter =
BeanDefinitionBuilder.rootBeanDefinition(DefaultLoginPageGeneratingFilter.class);
BeanDefinitionBuilder loginPageFilter =
BeanDefinitionBuilder.rootBeanDefinition(DefaultLoginPageGeneratingFilter.class);
if (formLoginFilter != null) {
loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
}
if (openIDFilter != null) {
loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.FORM_LOGIN_FILTER));
}
pc.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER,
loginPageFilter.getBeanDefinition());
if (openIDFilter != null) {
loginPageFilter.addConstructorArg(new RuntimeBeanReference(BeanIds.OPEN_ID_FILTER));
}
pc.getRegistry().registerBeanDefinition(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER,
loginPageFilter.getBeanDefinition());
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.DEFAULT_LOGIN_PAGE_GENERATING_FILTER));
}
// We need to establish the main entry point.
// First check if a custom entry point bean is set
String customEntryPoint = element.getAttribute(ATT_ENTRY_POINT_REF);
if (StringUtils.hasText(customEntryPoint)) {
pc.getRegistry().registerAlias(customEntryPoint, BeanIds.MAIN_ENTRY_POINT);
return;
}
// Basic takes precedence if explicit element is used and no others are configured
if (basicAuthElt != null && formLoginElt == null && openIDLoginElt == null) {
pc.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
return;
pc.getRegistry().registerAlias(BeanIds.BASIC_AUTHENTICATION_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
return;
}
// If formLogin has been enabled either through an element or auto-config, then it is used if no openID login page
// has been set
if (formLoginFilter != null && openIDLoginPage == null) {
pc.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
return;
pc.getRegistry().registerAlias(BeanIds.FORM_LOGIN_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
return;
}
// Otherwise use OpenID if enabled
if (openIDFilter != null && formLoginFilter == null) {
pc.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
return;
pc.getRegistry().registerAlias(BeanIds.OPEN_ID_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
return;
}
// If X.509 has been enabled, use the preauth entry point.
if (DomUtils.getChildElementByTagName(element, Elements.X509) != null) {
pc.getRegistry().registerAlias(BeanIds.PRE_AUTH_ENTRY_POINT, BeanIds.MAIN_ENTRY_POINT);
return;
}
pc.getReaderContext().error("No AuthenticationEntryPoint could be established. Please " +
"make sure you have a login mechanism configured through the namespace (such as form-login) or " +
"specify a custom AuthenticationEntryPoint with the custom-entry-point-ref attribute ",
"make sure you have a login mechanism configured through the namespace (such as form-login) or " +
"specify a custom AuthenticationEntryPoint with the custom-entry-point-ref attribute ",
pc.extractSource(element));
}
static UrlMatcher createUrlMatcher(Element element) {
String patternType = element.getAttribute(ATT_PATH_TYPE);
if (!StringUtils.hasText(patternType)) {
@@ -509,8 +518,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
}
// Default for regex is no change
}
return matcher;
return matcher;
}
/**
@@ -554,7 +563,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
editor.setAsText(channelConfigAttribute);
channelRequestMap.put(new RequestKey(path), (ConfigAttributeDefinition) editor.getValue());
}
String filters = urlElt.getAttribute(ATT_FILTERS);
if (StringUtils.hasText(filters)) {
@@ -567,10 +576,10 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
}
}
}
static LinkedHashMap parseInterceptUrlsForFilterInvocationRequestMap(List urlElts, boolean useLowerCasePaths, ParserContext parserContext) {
LinkedHashMap filterInvocationDefinitionMap = new LinkedHashMap();
Iterator urlEltsIterator = urlElts.iterator();
ConfigAttributeEditor editor = new ConfigAttributeEditor();
@@ -597,11 +606,17 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
// Convert the comma-separated list of access attributes to a ConfigAttributeDefinition
if (StringUtils.hasText(access)) {
editor.setAsText(access);
filterInvocationDefinitionMap.put(new RequestKey(path, method), editor.getValue());
Object key = new RequestKey(path, method);
if (filterInvocationDefinitionMap.containsKey(key)) {
logger.warn("Duplicate URL defined: " + key + ". The original attribute values will be overwritten");
}
filterInvocationDefinitionMap.put(key, editor.getValue());
}
}
return filterInvocationDefinitionMap;
}
}
@@ -50,7 +50,7 @@ public class JdbcUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
if (StringUtils.hasText(groupAuthoritiesQuery)) {
builder.addPropertyValue("enableGroups", Boolean.TRUE);
builder.addPropertyValue("authoritiesByUsernameQuery", groupAuthoritiesQuery);
builder.addPropertyValue("groupAuthoritiesByUsernameQuery", groupAuthoritiesQuery);
}
}
}
@@ -100,8 +100,9 @@ public class LdapProviderBeanDefinitionParser implements BeanDefinitionParser {
ldapProvider.addConstructorArg(LdapUserServiceBeanDefinitionParser.parseAuthoritiesPopulator(elt, parserContext));
ldapProvider.addPropertyValue("userDetailsContextMapper",
LdapUserServiceBeanDefinitionParser.parseUserDetailsClass(elt, parserContext));
parserContext.getRegistry().registerBeanDefinition(BeanIds.LDAP_AUTHENTICATION_PROVIDER, ldapProvider.getBeanDefinition());
ConfigUtils.getRegisteredProviders(parserContext).add(ldapProvider.getBeanDefinition());
ConfigUtils.addAuthenticationProvider(parserContext, BeanIds.LDAP_AUTHENTICATION_PROVIDER);
return null;
}
@@ -14,22 +14,22 @@ import org.w3c.dom.Element;
* @since 2.0
*/
public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser {
public static final String ATT_SERVER = "server-ref";
public static final String ATT_SERVER = "server-ref";
public static final String ATT_USER_SEARCH_FILTER = "user-search-filter";
public static final String ATT_USER_SEARCH_BASE = "user-search-base";
public static final String DEF_USER_SEARCH_BASE = "";
public static final String ATT_GROUP_SEARCH_FILTER = "group-search-filter";
public static final String ATT_GROUP_SEARCH_BASE = "group-search-base";
public static final String ATT_GROUP_ROLE_ATTRIBUTE = "group-role-attribute";
public static final String ATT_GROUP_ROLE_ATTRIBUTE = "group-role-attribute";
public static final String DEF_GROUP_SEARCH_FILTER = "(uniqueMember={0})";
public static final String DEF_GROUP_SEARCH_BASE = "ou=groups";
public static final String DEF_GROUP_SEARCH_BASE = "";
static final String ATT_ROLE_PREFIX = "role-prefix";
static final String ATT_USER_CLASS = "user-details-class";
static final String OPT_PERSON = "person";
static final String OPT_INETORGPERSON = "inetOrgPerson";
public static final String LDAP_SEARCH_CLASS = "org.springframework.security.ldap.search.FilterBasedLdapUserSearch";
public static final String PERSON_MAPPER_CLASS = "org.springframework.security.userdetails.ldap.PersonContextMapper";
public static final String INET_ORG_PERSON_MAPPER_CLASS = "org.springframework.security.userdetails.ldap.InetOrgPersonContextMapper";
@@ -45,42 +45,42 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
if (!StringUtils.hasText(elt.getAttribute(ATT_USER_SEARCH_FILTER))) {
parserContext.getReaderContext().error("User search filter must be supplied", elt);
}
builder.addConstructorArg(parseSearchBean(elt, parserContext));
builder.addConstructorArg(parseAuthoritiesPopulator(elt, parserContext));
builder.addPropertyValue("userDetailsMapper", parseUserDetailsClass(elt, parserContext));
}
static RootBeanDefinition parseSearchBean(Element elt, ParserContext parserContext) {
String userSearchFilter = elt.getAttribute(ATT_USER_SEARCH_FILTER);
String userSearchBase = elt.getAttribute(ATT_USER_SEARCH_BASE);
Object source = parserContext.extractSource(elt);
if (StringUtils.hasText(userSearchBase)) {
if(!StringUtils.hasText(userSearchFilter)) {
parserContext.getReaderContext().error(ATT_USER_SEARCH_BASE + " cannot be used without a " + ATT_USER_SEARCH_FILTER, source);
}
} else {
userSearchBase = DEF_USER_SEARCH_BASE;
}
}
if (!StringUtils.hasText(userSearchFilter)) {
return null;
}
BeanDefinitionBuilder searchBuilder = BeanDefinitionBuilder.rootBeanDefinition(LDAP_SEARCH_CLASS);
searchBuilder.setSource(source);
searchBuilder.addConstructorArg(userSearchBase);
searchBuilder.addConstructorArg(userSearchFilter);
searchBuilder.addConstructorArg(parseServerReference(elt, parserContext));
return (RootBeanDefinition) searchBuilder.getBeanDefinition();
}
static RuntimeBeanReference parseServerReference(Element elt, ParserContext parserContext) {
String server = elt.getAttribute(ATT_SERVER);
boolean requiresDefaultName = false;
if (!StringUtils.hasText(server)) {
server = BeanIds.CONTEXT_SOURCE;
requiresDefaultName = true;
@@ -89,27 +89,27 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
RuntimeBeanReference contextSource = new RuntimeBeanReference(server);
contextSource.setSource(parserContext.extractSource(elt));
LdapConfigUtils.registerPostProcessorIfNecessary(parserContext.getRegistry(), requiresDefaultName);
return contextSource;
}
static RootBeanDefinition parseUserDetailsClass(Element elt, ParserContext parserContext) {
String userDetailsClass = elt.getAttribute(ATT_USER_CLASS);
if (OPT_PERSON.equals(userDetailsClass)) {
return new RootBeanDefinition(PERSON_MAPPER_CLASS, null, null);
} else if (OPT_INETORGPERSON.equals(userDetailsClass)) {
return new RootBeanDefinition(INET_ORG_PERSON_MAPPER_CLASS, null, null);
}
return new RootBeanDefinition(LDAP_USER_MAPPER_CLASS, null, null);
String userDetailsClass = elt.getAttribute(ATT_USER_CLASS);
if (OPT_PERSON.equals(userDetailsClass)) {
return new RootBeanDefinition(PERSON_MAPPER_CLASS, null, null);
} else if (OPT_INETORGPERSON.equals(userDetailsClass)) {
return new RootBeanDefinition(INET_ORG_PERSON_MAPPER_CLASS, null, null);
}
return new RootBeanDefinition(LDAP_USER_MAPPER_CLASS, null, null);
}
static RootBeanDefinition parseAuthoritiesPopulator(Element elt, ParserContext parserContext) {
String groupSearchFilter = elt.getAttribute(ATT_GROUP_SEARCH_FILTER);
String groupSearchBase = elt.getAttribute(ATT_GROUP_SEARCH_BASE);
String groupRoleAttribute = elt.getAttribute(ATT_GROUP_ROLE_ATTRIBUTE);
String rolePrefix = elt.getAttribute(ATT_ROLE_PREFIX);
if (!StringUtils.hasText(groupSearchFilter)) {
groupSearchFilter = DEF_GROUP_SEARCH_FILTER;
}
@@ -117,25 +117,25 @@ public class LdapUserServiceBeanDefinitionParser extends AbstractUserDetailsServ
if (!StringUtils.hasText(groupSearchBase)) {
groupSearchBase = DEF_GROUP_SEARCH_BASE;
}
BeanDefinitionBuilder populator = BeanDefinitionBuilder.rootBeanDefinition(LDAP_AUTHORITIES_POPULATOR_CLASS);
populator.setSource(parserContext.extractSource(elt));
populator.addConstructorArg(parseServerReference(elt, parserContext));
populator.addConstructorArg(groupSearchBase);
populator.addPropertyValue("groupSearchFilter", groupSearchFilter);
populator.addPropertyValue("searchSubtree", Boolean.TRUE);
if (StringUtils.hasText(rolePrefix)) {
if ("none".equals(rolePrefix)) {
rolePrefix = "";
}
populator.addPropertyValue("rolePrefix", rolePrefix);
}
if (StringUtils.hasLength(groupRoleAttribute)) {
populator.addPropertyValue("groupRoleAttribute", groupRoleAttribute);
}
return (RootBeanDefinition) populator.getBeanDefinition();
}
}
@@ -25,6 +25,12 @@ public class LogoutBeanDefinitionParser implements BeanDefinitionParser {
static final String ATT_LOGOUT_URL = "logout-url";
static final String DEF_LOGOUT_URL = "/j_spring_security_logout";
String rememberMeServices;
public LogoutBeanDefinitionParser(String rememberMeServices) {
this.rememberMeServices = rememberMeServices;
}
public BeanDefinition parse(Element element, ParserContext parserContext) {
String logoutUrl = null;
@@ -66,8 +72,8 @@ public class LogoutBeanDefinitionParser implements BeanDefinitionParser {
}
handlers.add(sclh);
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.REMEMBER_ME_SERVICES)) {
handlers.add(new RuntimeBeanReference(BeanIds.REMEMBER_ME_SERVICES));
if (rememberMeServices != null) {
handlers.add(new RuntimeBeanReference(rememberMeServices));
}
builder.addConstructorArg(handlers);
@@ -0,0 +1,59 @@
package org.springframework.security.config;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.security.providers.ProviderManager;
import org.springframework.util.Assert;
/**
* Extended version of {@link ProviderManager the default authentication manager} which lazily initializes
* the list of {@link AuthenticationProvider}s. This prevents some of the issues that have occurred with
* namespace configuration where early instantiation of a security interceptor has caused the AuthenticationManager
* and thus dependent beans (typically UserDetailsService implementations or DAOs) to be initialized too early.
*
* @author Luke Taylor
* @since 2.0.4
*/
public class NamespaceAuthenticationManager extends ProviderManager implements BeanFactoryAware {
BeanFactory beanFactory;
List providerBeanNames;
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(providerBeanNames, "provideBeanNames has not been set");
Assert.notEmpty(providerBeanNames, "No authentication providers were found in the application context");
super.afterPropertiesSet();
}
/**
* Overridden to lazily-initialize the list of providers on first use.
*/
public List getProviders() {
// We use the names array to determine whether the list has been set yet.
if (providerBeanNames != null) {
List providers = new ArrayList();
Iterator beanNames = providerBeanNames.iterator();
while (beanNames.hasNext()) {
providers.add(beanFactory.getBean((String) beanNames.next()));
}
providerBeanNames = null;
setProviders(providers);
}
return super.getProviders();
}
public void setProviderBeanNames(List provideBeanNames) {
this.providerBeanNames = provideBeanNames;
}
}
@@ -22,7 +22,7 @@ import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* Adds the decorated "Filter" bean into the standard filter chain maintained by the FilterChainProxy.
* Adds the decorated "Filter" bean into the standard filter chain maintained by the FilterChainProxy.
* This allows user to add their own custom filters to the security chain. If the user's filter
* already implements Ordered, and no "order" attribute is specified, the filter's default order will be used.
*
@@ -33,7 +33,7 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
public static final String ATT_AFTER = "after";
public static final String ATT_BEFORE = "before";
public static final String ATT_POSITION = "position";
public static final String ATT_POSITION = "position";
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext parserContext) {
Element elt = (Element)node;
@@ -48,7 +48,7 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
}
ConfigUtils.addHttpFilter(parserContext, wrapper.getBeanDefinition());
return holder;
}
@@ -59,22 +59,26 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
String after = elt.getAttribute(ATT_AFTER);
String before = elt.getAttribute(ATT_BEFORE);
String position = elt.getAttribute(ATT_POSITION);
if(ConfigUtils.countNonEmpty(new String[] {after, before, position}) != 1) {
pc.getReaderContext().error("A single '" + ATT_AFTER + "', '" + ATT_BEFORE + "', or '" +
ATT_POSITION + "' attribute must be supplied", pc.extractSource(elt));
pc.getReaderContext().error("A single '" + ATT_AFTER + "', '" + ATT_BEFORE + "', or '" +
ATT_POSITION + "' attribute must be supplied", pc.extractSource(elt));
}
if (StringUtils.hasText(position)) {
return Integer.toString(FilterChainOrder.getOrder(position));
return Integer.toString(FilterChainOrder.getOrder(position));
}
if (StringUtils.hasText(after)) {
return Integer.toString(FilterChainOrder.getOrder(after) + 1);
int order = FilterChainOrder.getOrder(after);
return Integer.toString(order == Integer.MAX_VALUE ? order : order + 1);
}
if (StringUtils.hasText(before)) {
return Integer.toString(FilterChainOrder.getOrder(before) - 1);
int order = FilterChainOrder.getOrder(before);
return Integer.toString(order == Integer.MIN_VALUE ? order : order - 1);
}
return null;
@@ -121,12 +125,12 @@ public class OrderedFilterBeanDefinitionDecorator implements BeanDefinitionDecor
return beanName;
}
public String toString() {
return "OrderedFilterDecorator[ delegate=" + delegate + "; order=" + getOrder() + "]";
}
Filter getDelegate() {
return delegate;
}
public String toString() {
return "OrderedFilterDecorator[ delegate=" + delegate + "; order=" + getOrder() + "]";
}
Filter getDelegate() {
return delegate;
}
}
}
@@ -32,6 +32,7 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
static final String ATT_TOKEN_VALIDITY = "token-validity-seconds";
protected final Log logger = LogFactory.getLog(getClass());
private String servicesName;
public BeanDefinition parse(Element element, ParserContext parserContext) {
String tokenRepository = null;
@@ -102,8 +103,10 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
}
services.setSource(source);
services.getPropertyValues().addPropertyValue(ATT_KEY, key);
parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services);
parserContext.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_SERVICES, services);
servicesName = BeanIds.REMEMBER_ME_SERVICES;
} else {
servicesName = rememberMeServicesRef;
parserContext.getRegistry().registerAlias(rememberMeServicesRef, BeanIds.REMEMBER_ME_SERVICES);
}
@@ -114,13 +117,17 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
return null;
}
private void registerProvider(ParserContext pc, Object source, String key) {
BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(pc);
String getServicesName() {
return servicesName;
}
private void registerProvider(ParserContext pc, Object source, String key) {
//BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(pc);
RootBeanDefinition provider = new RootBeanDefinition(RememberMeAuthenticationProvider.class);
provider.setSource(source);
provider.getPropertyValues().addPropertyValue(ATT_KEY, key);
ManagedList providers = (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
providers.add(provider);
pc.getRegistry().registerBeanDefinition(BeanIds.REMEMBER_ME_AUTHENTICATION_PROVIDER, provider);
ConfigUtils.addAuthenticationProvider(pc, BeanIds.REMEMBER_ME_AUTHENTICATION_PROVIDER);
}
private void registerFilter(ParserContext pc, Object source) {
@@ -51,7 +51,8 @@ public class RememberMeServicesInjectionBeanPostProcessor implements BeanPostPro
Map beans = beanFactory.getBeansOfType(RememberMeServices.class);
Assert.isTrue(beans.size() > 0, "No RememberMeServices configured");
Assert.isTrue(beans.size() == 1, "More than one RememberMeServices bean found.");
Assert.isTrue(beans.size() == 1, "Use of '<remember-me />' requires a single instance of RememberMeServices " +
"in the application context, but more than one was found.");
return (RememberMeServices) beans.values().toArray()[0];
}
@@ -24,6 +24,7 @@ public class SecurityNamespaceHandler extends NamespaceHandlerSupport {
registerBeanDefinitionParser(Elements.GLOBAL_METHOD_SECURITY, new GlobalMethodSecurityBeanDefinitionParser());
registerBeanDefinitionParser(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser());
registerBeanDefinitionParser(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationDefinitionSourceBeanDefinitionParser());
registerBeanDefinitionParser(Elements.HTTP_FIREWALL, new HttpFirewallBeanDefinitionParser());
// Decorators
registerBeanDefinitionDecorator(Elements.INTERCEPT_METHODS, new InterceptMethodsBeanDefinitionDecorator());
@@ -2,8 +2,6 @@ package org.springframework.security.config;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValue;
@@ -21,91 +19,91 @@ import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.util.Assert;
/**
*
* Registered by {@link HttpSecurityBeanDefinitionParser} to inject a UserDetailsService into
* the X509Provider, RememberMeServices and OpenIDAuthenticationProvider instances created by
* the namespace.
*
* @author Luke Taylor
* @since 2.0.2
*/
public class UserDetailsServiceInjectionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
private final Log logger = LogFactory.getLog(getClass());
private ConfigurableListableBeanFactory beanFactory;
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (BeanIds.X509_AUTH_PROVIDER.equals(beanName)) {
injectUserDetailsServiceIntoX509Provider((PreAuthenticatedAuthenticationProvider) bean);
} else if (BeanIds.REMEMBER_ME_SERVICES.equals(beanName)) {
injectUserDetailsServiceIntoRememberMeServices((AbstractRememberMeServices)bean);
} else if (BeanIds.OPEN_ID_PROVIDER.equals(beanName)) {
injectUserDetailsServiceIntoOpenIDProvider(bean);
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
private ConfigurableListableBeanFactory beanFactory;
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (BeanIds.X509_AUTH_PROVIDER.equals(beanName)) {
injectUserDetailsServiceIntoX509Provider((PreAuthenticatedAuthenticationProvider) bean);
} else if (BeanIds.REMEMBER_ME_SERVICES.equals(beanName)) {
injectUserDetailsServiceIntoRememberMeServices((AbstractRememberMeServices)bean);
} else if (BeanIds.OPEN_ID_PROVIDER.equals(beanName)) {
injectUserDetailsServiceIntoOpenIDProvider(bean);
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
private void injectUserDetailsServiceIntoRememberMeServices(AbstractRememberMeServices services) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(BeanIds.REMEMBER_ME_SERVICES);
PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("userDetailsService");
if (pv == null) {
services.setUserDetailsService(getUserDetailsService());
services.setUserDetailsService(getUserDetailsService());
} else {
UserDetailsService cachingUserService = getCachingUserService(pv.getValue());
if (cachingUserService != null) {
services.setUserDetailsService(cachingUserService);
}
UserDetailsService cachingUserService = getCachingUserService(pv.getValue());
if (cachingUserService != null) {
services.setUserDetailsService(cachingUserService);
}
}
}
private void injectUserDetailsServiceIntoX509Provider(PreAuthenticatedAuthenticationProvider provider) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(BeanIds.X509_AUTH_PROVIDER);
PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("preAuthenticatedUserDetailsService");
UserDetailsByNameServiceWrapper wrapper = new UserDetailsByNameServiceWrapper();
if (pv == null) {
wrapper.setUserDetailsService(getUserDetailsService());
provider.setPreAuthenticatedUserDetailsService(wrapper);
wrapper.setUserDetailsService(getUserDetailsService());
provider.setPreAuthenticatedUserDetailsService(wrapper);
} else {
RootBeanDefinition preAuthUserService = (RootBeanDefinition) pv.getValue();
Object userService =
preAuthUserService.getPropertyValues().getPropertyValue("userDetailsService").getValue();
UserDetailsService cachingUserService = getCachingUserService(userService);
if (cachingUserService != null) {
wrapper.setUserDetailsService(cachingUserService);
provider.setPreAuthenticatedUserDetailsService(wrapper);
}
RootBeanDefinition preAuthUserService = (RootBeanDefinition) pv.getValue();
Object userService =
preAuthUserService.getPropertyValues().getPropertyValue("userDetailsService").getValue();
UserDetailsService cachingUserService = getCachingUserService(userService);
if (cachingUserService != null) {
wrapper.setUserDetailsService(cachingUserService);
provider.setPreAuthenticatedUserDetailsService(wrapper);
}
}
}
private void injectUserDetailsServiceIntoOpenIDProvider(Object bean) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(BeanIds.OPEN_ID_PROVIDER);
PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("userDetailsService");
if (pv == null) {
BeanWrapperImpl beanWrapper = new BeanWrapperImpl(bean);
BeanWrapperImpl beanWrapper = new BeanWrapperImpl(bean);
beanWrapper.setPropertyValue("userDetailsService", getUserDetailsService());
}
}
/**
* Obtains a user details service for use in RememberMeServices etc. Will return a caching version
* if available so should not be used for beans which need to separate the two.
* if available so should not be used for beans which need to separate the two.
*/
UserDetailsService getUserDetailsService() {
Map beans = beanFactory.getBeansOfType(CachingUserDetailsService.class);
if (beans.size() == 0) {
beans = beanFactory.getBeansOfType(UserDetailsService.class);
}
Map beans = beanFactory.getBeansOfType(CachingUserDetailsService.class);
if (beans.size() == 0) {
beans = beanFactory.getBeansOfType(UserDetailsService.class);
}
if (beans.size() == 0) {
throw new SecurityConfigurationException("No UserDetailsService registered.");
@@ -116,24 +114,24 @@ public class UserDetailsServiceInjectionBeanPostProcessor implements BeanPostPro
return (UserDetailsService) beans.values().toArray()[0];
}
private UserDetailsService getCachingUserService(Object userServiceRef) {
Assert.isInstanceOf(RuntimeBeanReference.class, userServiceRef,
"userDetailsService property value must be a RuntimeBeanReference");
String id = ((RuntimeBeanReference)userServiceRef).getBeanName();
// Overwrite with the caching version if available
String cachingId = id + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX;
if (beanFactory.containsBeanDefinition(cachingId)) {
return (UserDetailsService) beanFactory.getBean(cachingId);
}
return null;
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
private UserDetailsService getCachingUserService(Object userServiceRef) {
Assert.isInstanceOf(RuntimeBeanReference.class, userServiceRef,
"userDetailsService property value must be a RuntimeBeanReference");
String id = ((RuntimeBeanReference)userServiceRef).getBeanName();
// Overwrite with the caching version if available
String cachingId = id + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX;
if (beanFactory.containsBeanDefinition(cachingId)) {
return (UserDetailsService) beanFactory.getBean(cachingId);
}
return null;
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
}
@@ -46,7 +46,7 @@ public class X509BeanDefinitionParser implements BeanDefinitionParser {
BeanDefinition provider = new RootBeanDefinition(PreAuthenticatedAuthenticationProvider.class);
parserContext.getRegistry().registerBeanDefinition(BeanIds.X509_AUTH_PROVIDER, provider);
ConfigUtils.getRegisteredProviders(parserContext).add(new RuntimeBeanReference(BeanIds.X509_AUTH_PROVIDER));
ConfigUtils.addAuthenticationProvider(parserContext, BeanIds.X509_AUTH_PROVIDER);
String userServiceRef = element.getAttribute(ATT_USER_SERVICE_REF);
@@ -0,0 +1,67 @@
package org.springframework.security.firewall;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Default implementation which wraps requests in order to provide consistent values of the {@code servletPath} and
* {@code pathInfo}, which do not contain path parameters (as defined in
* <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>). Different servlet containers
* interpret the servlet spec differently as to how path parameters are treated and it is possible they might be added
* in order to bypass particular security constraints. When using this implementation, they will be removed for all
* requests as the request passes through the security filter chain. Note that this means that any segments in the
* decoded path which contain a semi-colon, will have the part following the semi-colon removed for
* request matching. Your application should not contain any valid paths which contain semi-colons.
* <p>
* If any un-normalized paths are found (containing directory-traversal character sequences), the request will be
* rejected immediately. Most containers normalize the paths before performing the servlet-mapping, but again this is
* not guaranteed by the servlet spec.
*
* @author Luke Taylor
*/
public class DefaultHttpFirewall implements HttpFirewall {
public FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException {
FirewalledRequest fwr = new RequestWrapper(request);
if (!isNormalized(fwr.getServletPath()) || !isNormalized(fwr.getPathInfo())) {
throw new RequestRejectedException("Un-normalized paths are not supported: " + fwr.getServletPath() +
(fwr.getPathInfo() != null ? fwr.getPathInfo() : ""));
}
return fwr;
}
public HttpServletResponse getFirewalledResponse(HttpServletResponse response) {
return response;
}
/**
* Checks whether a path is normalized (doesn't contain path traversal sequences like "./", "/../" or "/.")
*
* @param path the path to test
* @return true if the path doesn't contain any path-traversal character sequences.
*/
private boolean isNormalized(String path) {
if (path == null) {
return true;
}
for (int j = path.length(); j > 0;) {
int i = path.lastIndexOf('/', j - 1);
int gap = j - i;
if (gap == 2 && path.charAt(i+1) == '.') {
// ".", "/./" or "/."
return false;
} else if (gap == 3 && path.charAt(i+1) == '.'&& path.charAt(i+2) == '.') {
return false;
}
j = i;
}
return true;
}
}
@@ -0,0 +1,34 @@
package org.springframework.security.firewall;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/**
* Request wrapper which is returned by the {@code HttpFirewall} interface.
* <p>
* The only difference is the {@code reset} method which allows some
* or all of the state to be reset by the {@code FilterChainProxy} when the
* request leaves the security filter chain.
*
* @author Luke Taylor
*/
public abstract class FirewalledRequest extends HttpServletRequestWrapper {
/**
* Constructs a request object wrapping the given request.
*
* @throws IllegalArgumentException if the request is null
*/
public FirewalledRequest(HttpServletRequest request) {
super(request);
}
/**
* This method will be called once the request has passed through the
* security filter chain, when it is about to proceed to the application
* proper.
* <p>
* An implementation can thus choose to modify the state of the request
* for the security infrastructure, while still maintaining the
*/
public abstract void reset();
}
@@ -0,0 +1,32 @@
package org.springframework.security.firewall;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Interface which can be used to reject potentially dangerous requests and/or wrap them to
* control their behaviour.
* <p>
* The implementation is injected into the {@code FilterChainProxy} and will be invoked before
* sending any request through the filter chain. It can also provide a response wrapper if the response
* behaviour should also be restricted.
*
* @author Luke Taylor
*/
public interface HttpFirewall {
/**
* Provides the request object which will be passed through the filter chain.
*
* @throws RequestRejectedException if the request should be rejected immediately
*/
FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException;
/**
* Provides the response which will be passed through the filter chain.
*
* @param response the original response
* @return either the original response or a replacement/wrapper.
*/
HttpServletResponse getFirewalledResponse(HttpServletResponse response);
}
@@ -0,0 +1,10 @@
package org.springframework.security.firewall;
/**
* @author Luke Taylor
*/
public class RequestRejectedException extends RuntimeException {
public RequestRejectedException(String message) {
super(message);
}
}
@@ -0,0 +1,98 @@
package org.springframework.security.firewall;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
/**
* Request wrapper which ensures values of {@code servletPath} and {@code pathInfo} are returned which are suitable for
* pattern matching against. It strips out path parameters and extra consecutive '/' characters.
*
* <h3>Path Parameters</h3>
* Parameters (as defined in <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>) are stripped from the path
* segments of the {@code servletPath} and {@code pathInfo} values of the request.
* <p>
* The parameter sequence is demarcated by a semi-colon, so each segment is checked for the occurrence of a ";"
* character and truncated at that point if it is present.
* <p>
* The behaviour differs between servlet containers in how they interpret the servlet spec, which
* does not clearly state what the behaviour should be. For consistency, we make sure they are always removed, to
* avoid the risk of URL matching rules being bypassed by the malicious addition of parameters to the path component.
*
* @author Luke Taylor
*/
final class RequestWrapper extends FirewalledRequest {
private final String strippedServletPath;
private final String strippedPathInfo;
private boolean stripPaths = true;
public RequestWrapper(HttpServletRequest request) {
super(request);
strippedServletPath = strip(request.getServletPath());
String pathInfo = strip(request.getPathInfo());
if (pathInfo != null && pathInfo.length() == 0) {
pathInfo = null;
}
strippedPathInfo = pathInfo;
}
/**
* Removes path parameters from each path segment in the supplied path and truncates sequences of multiple '/'
* characters to a single '/'.
*
* @param path either the {@code servletPath} and {@code pathInfo} from the original request
*
* @return the supplied value, with path parameters removed and sequences of multiple '/' characters truncated,
* or null if the supplied path was null.
*/
private String strip(String path) {
if (path == null) {
return null;
}
int scIndex = path.indexOf(';');
if (scIndex < 0) {
int doubleSlashIndex = path.indexOf("//");
if (doubleSlashIndex < 0) {
// Most likely case, no parameters in any segment and no '//', so no stripping required
return path;
}
}
StringTokenizer st = new StringTokenizer(path, "/");
StringBuilder stripped = new StringBuilder(path.length());
if (path.charAt(0) == '/') {
stripped.append('/');
}
while(st.hasMoreTokens()) {
String segment = st.nextToken();
scIndex = segment.indexOf(';');
if (scIndex >= 0) {
segment = segment.substring(0, scIndex);
}
stripped.append(segment).append('/');
}
// Remove the trailing slash if the original path didn't have one
if (path.charAt(path.length() - 1) != '/') {
stripped.deleteCharAt(stripped.length() - 1);
}
return stripped.toString();
}
public String getPathInfo() {
return stripPaths ? strippedPathInfo : super.getPathInfo();
}
public String getServletPath() {
return stripPaths ? strippedServletPath : super.getServletPath();
}
public void reset() {
this.stripPaths = false;
}
}
@@ -18,11 +18,11 @@ import org.springframework.util.ObjectUtils;
* Abstract implementation of {@link MethodDefinitionSource} that supports both Spring AOP and AspectJ and
* caches configuration attribute resolution from: 1. specific target method; 2. target class; 3. declaring method;
* 4. declaring class/interface.
*
*
* <p>
* This class mimics the behaviour of Spring's AbstractFallbackTransactionAttributeSource class.
* </p>
*
*
* <p>
* Note that this class cannot extract security metadata where that metadata is expressed by way of
* a target method/class (ie #1 and #2 above) AND the target method/class is encapsulated in another
@@ -31,7 +31,7 @@ import org.springframework.util.ObjectUtils;
* another proxy), move the metadata to declared methods or interfaces the proxy implements, or provide
* your own replacement <tt>MethodDefinitionSource</tt>.
* </p>
*
*
* @author Ben Alex
* @version $Id$
* @since 2.0
@@ -39,15 +39,16 @@ import org.springframework.util.ObjectUtils;
public abstract class AbstractFallbackMethodDefinitionSource implements MethodDefinitionSource {
private static final Log logger = LogFactory.getLog(AbstractFallbackMethodDefinitionSource.class);
private final static Object NULL_CONFIG_ATTRIBUTE = new Object();
private final static Object NULL_CONFIG_ATTRIBUTE = new Object();
private final Map attributeCache = new HashMap();
public ConfigAttributeDefinition getAttributes(Object object) throws IllegalArgumentException {
Assert.notNull(object, "Object cannot be null");
if (object instanceof MethodInvocation) {
MethodInvocation mi = (MethodInvocation) object;
return getAttributes(mi.getMethod(), mi.getThis().getClass());
MethodInvocation mi = (MethodInvocation) object;
Object target = mi.getThis();
return getAttributes(mi.getMethod(), target == null ? null : target.getClass());
}
if (object instanceof JoinPoint) {
@@ -59,143 +60,143 @@ public abstract class AbstractFallbackMethodDefinitionSource implements MethodDe
Method method = ClassUtils.getMethodIfAvailable(declaringType, targetMethodName, types);
Assert.notNull(method, "Could not obtain target method from JoinPoint: '"+ jp + "'");
return getAttributes(method, targetClass);
}
throw new IllegalArgumentException("Object must be a MethodInvocation or JoinPoint");
}
public final boolean supports(Class clazz) {
return (MethodInvocation.class.isAssignableFrom(clazz) || JoinPoint.class.isAssignableFrom(clazz));
}
public ConfigAttributeDefinition getAttributes(Method method, Class targetClass) {
// First, see if we have a cached value.
Object cacheKey = new DefaultCacheKey(method, targetClass);
synchronized (this.attributeCache) {
Object cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// Value will either be canonical value indicating there is no config attribute,
// or an actual config attribute.
if (cached == NULL_CONFIG_ATTRIBUTE) {
return null;
}
else {
return (ConfigAttributeDefinition) cached;
}
}
else {
// We need to work it out.
ConfigAttributeDefinition cfgAtt = computeAttributes(method, targetClass);
// Put it in the cache.
if (cfgAtt == null) {
this.attributeCache.put(cacheKey, NULL_CONFIG_ATTRIBUTE);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Adding security method [" + cacheKey + "] with attribute [" + cfgAtt + "]");
}
this.attributeCache.put(cacheKey, cfgAtt);
}
return cfgAtt;
}
}
// First, see if we have a cached value.
Object cacheKey = new DefaultCacheKey(method, targetClass);
synchronized (this.attributeCache) {
Object cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// Value will either be canonical value indicating there is no config attribute,
// or an actual config attribute.
if (cached == NULL_CONFIG_ATTRIBUTE) {
return null;
}
else {
return (ConfigAttributeDefinition) cached;
}
}
else {
// We need to work it out.
ConfigAttributeDefinition cfgAtt = computeAttributes(method, targetClass);
// Put it in the cache.
if (cfgAtt == null) {
this.attributeCache.put(cacheKey, NULL_CONFIG_ATTRIBUTE);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Adding security method [" + cacheKey + "] with attribute [" + cfgAtt + "]");
}
this.attributeCache.put(cacheKey, cfgAtt);
}
return cfgAtt;
}
}
}
/**
*
* @param method the method for the current invocation (never <code>null</code>)
* @param targetClass the target class for this invocation (may be <code>null</code>)
*
* @param method the method for the current invocation (never <code>null</code>)
* @param targetClass the target class for this invocation (may be <code>null</code>)
* @return
*/
private ConfigAttributeDefinition computeAttributes(Method method, Class targetClass) {
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
// First try is the method in the target class.
ConfigAttributeDefinition attr = findAttributes(specificMethod, targetClass);
if (attr != null) {
return attr;
}
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
// First try is the method in the target class.
ConfigAttributeDefinition attr = findAttributes(specificMethod, targetClass);
if (attr != null) {
return attr;
}
// Second try is the config attribute on the target class.
attr = findAttributes(specificMethod.getDeclaringClass());
if (attr != null) {
return attr;
}
// Second try is the config attribute on the target class.
attr = findAttributes(specificMethod.getDeclaringClass());
if (attr != null) {
return attr;
}
if (specificMethod != method) {
// Fallback is to look at the original method.
attr = findAttributes(method, method.getDeclaringClass());
if (attr != null) {
return attr;
}
// Last fallback is the class of the original method.
return findAttributes(method.getDeclaringClass());
}
return null;
if (specificMethod != method || targetClass == null) {
// Fallback is to look at the original method.
attr = findAttributes(method, method.getDeclaringClass());
if (attr != null) {
return attr;
}
// Last fallback is the class of the original method.
return findAttributes(method.getDeclaringClass());
}
return null;
}
/**
* Obtains the security metadata applicable to the specified method invocation.
*
*
* <p>
* Note that the {@link Method#getDeclaringClass()} may not equal the <code>targetClass</code>.
* Both parameters are provided to assist subclasses which may wish to provide advanced
* capabilities related to method metadata being "registered" against a method even if the
* target class does not declare the method (i.e. the subclass may only inherit the method).
*
*
* @param method the method for the current invocation (never <code>null</code>)
* @param targetClass the target class for the invocation (may be <code>null</code>)
* @return the security metadata (or null if no metadata applies)
*/
protected abstract ConfigAttributeDefinition findAttributes(Method method, Class targetClass);
/**
* Obtains the security metadata registered against the specified class.
*
*
* <p>
* Subclasses should only return metadata expressed at a class level. Subclasses should NOT
* aggregate metadata for each method registered against a class, as the abstract superclass
* will separate invoke {@link #findAttributes(Method, Class)} for individual methods as
* appropriate.
*
* appropriate.
*
* @param clazz the target class for the invocation (never <code>null</code>)
* @return the security metadata (or null if no metadata applies)
*/
protected abstract ConfigAttributeDefinition findAttributes(Class clazz);
private static class DefaultCacheKey {
private final Method method;
private final Class targetClass;
private static class DefaultCacheKey {
public DefaultCacheKey(Method method, Class targetClass) {
this.method = method;
this.targetClass = targetClass;
}
private final Method method;
private final Class targetClass;
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof DefaultCacheKey)) {
return false;
}
DefaultCacheKey otherKey = (DefaultCacheKey) other;
return (this.method.equals(otherKey.method) &&
ObjectUtils.nullSafeEquals(this.targetClass, otherKey.targetClass));
}
public DefaultCacheKey(Method method, Class targetClass) {
this.method = method;
this.targetClass = targetClass;
}
public int hashCode() {
return this.method.hashCode() * 21 + (this.targetClass != null ? this.targetClass.hashCode() : 0);
}
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof DefaultCacheKey)) {
return false;
}
DefaultCacheKey otherKey = (DefaultCacheKey) other;
return (this.method.equals(otherKey.method) &&
ObjectUtils.nullSafeEquals(this.targetClass, otherKey.targetClass));
}
public int hashCode() {
return this.method.hashCode() * 21 + (this.targetClass != null ? this.targetClass.hashCode() : 0);
}
public String toString() {
return "CacheKey[" + (targetClass == null ? "-" : targetClass.getName()) + "; " + method + "]";
}
}
public String toString() {
return "CacheKey[" + (targetClass == null ? "-" : targetClass.getName()) + "; " + method + "]";
}
}
}
@@ -34,13 +34,13 @@ import org.springframework.util.ClassUtils;
/**
* Stores a {@link ConfigAttributeDefinition} for a method or class signature.
*
*
* <p>
* This class is the preferred implementation of {@link MethodDefinitionSource} for XML-based
* definition of method security metadata. To assist in XML-based definition, wildcard support
* is provided.
* </p>
*
*
* @author Ben Alex
* @version $Id$
* @since 2.0
@@ -51,9 +51,9 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
private static final Log logger = LogFactory.getLog(MapBasedMethodDefinitionSource.class);
//~ Instance fields ================================================================================================
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
/** Map from RegisteredMethod to ConfigAttributeDefinition */
/** Map from RegisteredMethod to ConfigAttributeDefinition */
protected Map methodMap = new HashMap();
/** Map from RegisteredMethod to name pattern used for registration */
@@ -74,48 +74,37 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
addSecureMethod((String)entry.getKey(), (ConfigAttributeDefinition)entry.getValue());
}
}
}
/**
* Implementation does not support class-level attributes.
*/
protected ConfigAttributeDefinition findAttributes(Class clazz) {
return null;
}
/**
* Will walk the method inheritance tree to find the most specific declaration applicable.
*/
protected ConfigAttributeDefinition findAttributes(Method method, Class targetClass) {
return findAttributesSpecifiedAgainst(method, targetClass);
}
private ConfigAttributeDefinition findAttributesSpecifiedAgainst(Method method, Class clazz) {
RegisteredMethod registeredMethod = new RegisteredMethod(method, clazz);
if (methodMap.containsKey(registeredMethod)) {
return (ConfigAttributeDefinition) methodMap.get(registeredMethod);
}
// Search superclass
if (clazz.getSuperclass() != null) {
return findAttributesSpecifiedAgainst(method, clazz.getSuperclass());
}
return null;
}
/**
* Implementation does not support class-level attributes.
*/
protected ConfigAttributeDefinition findAttributes(Class clazz) {
return null;
}
/**
* Add configuration attributes for a secure method.
*
* @param method the method to be secured
* @param attr required authorities associated with the method
* Will walk the method inheritance tree to find the most specific declaration applicable.
*/
private void addSecureMethod(RegisteredMethod method, ConfigAttributeDefinition attr) {
Assert.notNull(method, "RegisteredMethod required");
Assert.notNull(attr, "Configuration attribute required");
if (logger.isInfoEnabled()) {
logger.info("Adding secure method [" + method + "] with attributes [" + attr + "]");
}
this.methodMap.put(method, attr);
protected ConfigAttributeDefinition findAttributes(Method method, Class targetClass) {
if (targetClass == null) {
return null;
}
return findAttributesSpecifiedAgainst(method, targetClass);
}
private ConfigAttributeDefinition findAttributesSpecifiedAgainst(Method method, Class clazz) {
RegisteredMethod registeredMethod = new RegisteredMethod(method, clazz);
if (methodMap.containsKey(registeredMethod)) {
return (ConfigAttributeDefinition) methodMap.get(registeredMethod);
}
// Search superclass
if (clazz.getSuperclass() != null) {
return findAttributesSpecifiedAgainst(method, clazz.getSuperclass());
}
return null;
}
/**
@@ -126,7 +115,7 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
* @param attr required authorities associated with the method
*/
public void addSecureMethod(String name, ConfigAttributeDefinition attr) {
int lastDotIndex = name.lastIndexOf(".");
int lastDotIndex = name.lastIndexOf(".");
if (lastDotIndex == -1) {
throw new IllegalArgumentException("'" + name + "' is not a valid method name: format is FQN.methodName");
@@ -134,17 +123,17 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
String methodName = name.substring(lastDotIndex + 1);
Assert.hasText(methodName, "Method not found for '" + name + "'");
String typeName = name.substring(0, lastDotIndex);
Class type = ClassUtils.resolveClassName(typeName, this.beanClassLoader);
addSecureMethod(type, methodName, attr);
}
/**
* Add configuration attributes for a secure method. Mapped method names can end or start with <code>&#42</code>
* for matching multiple methods.
*
*
* @param javaType target interface or class the security configuration attribute applies to
* @param mappedName mapped method name, which the javaType has declared or inherited
* @param attr required authorities associated with the method
@@ -192,6 +181,38 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
}
}
/**
* Adds configuration attributes for a specific method, for example where the method has been
* matched using a pointcut expression. If a match already exists in the map for the method, then
* the existing match will be retained, so that if this method is called for a more general pointcut
* it will not override a more specific one which has already been added. This
*/
public void addSecureMethod(Class javaType, Method method, ConfigAttributeDefinition attr) {
RegisteredMethod key = new RegisteredMethod(method, javaType);
if (methodMap.containsKey(key)) {
logger.debug("Method [" + method + "] is already registered with attributes [" + methodMap.get(key) + "]");
return;
}
methodMap.put(key, attr);
}
/**
* Add configuration attributes for a secure method.
*
* @param method the method to be secured
* @param attr required authorities associated with the method
*/
private void addSecureMethod(RegisteredMethod method, ConfigAttributeDefinition attr) {
Assert.notNull(method, "RegisteredMethod required");
Assert.notNull(attr, "Configuration attribute required");
if (logger.isInfoEnabled()) {
logger.info("Adding secure method [" + method + "] with attributes [" + attr + "]");
}
this.methodMap.put(method, attr);
}
/**
* Obtains the configuration attributes explicitly defined against this bean.
*
@@ -215,93 +236,54 @@ public class MapBasedMethodDefinitionSource extends AbstractFallbackMethodDefini
|| (mappedName.startsWith("*") && methodName.endsWith(mappedName.substring(1, mappedName.length())));
}
protected ConfigAttributeDefinition lookupAttributes(Method method) {
List attributesToReturn = new ArrayList();
public void setBeanClassLoader(ClassLoader beanClassLoader) {
Assert.notNull(beanClassLoader, "Bean class loader required");
this.beanClassLoader = beanClassLoader;
}
// Add attributes explicitly defined for this method invocation
merge(attributesToReturn, (ConfigAttributeDefinition) this.methodMap.get(method));
/**
* @return map size (for unit tests and diagnostics)
*/
public int getMethodMapSize() {
return methodMap.size();
}
// Add attributes explicitly defined for this method invocation's interfaces
Class[] interfaces = method.getDeclaringClass().getInterfaces();
/**
* Stores both the Java Method as well as the Class we obtained the Method from. This is necessary because Method only
* provides us access to the declaring class. It doesn't provide a way for us to introspect which Class the Method
* was registered against. If a given Class inherits and redeclares a method (i.e. calls super();) the registered Class
* and declaring Class are the same. If a given class merely inherits but does not redeclare a method, the registered
* Class will be the Class we're invoking against and the Method will provide details of the declared class.
*/
private class RegisteredMethod {
private Method method;
private Class registeredJavaType;
for (int i = 0; i < interfaces.length; i++) {
Class clazz = interfaces[i];
public RegisteredMethod(Method method, Class registeredJavaType) {
Assert.notNull(method, "Method required");
Assert.notNull(registeredJavaType, "Registered Java Type required");
this.method = method;
this.registeredJavaType = registeredJavaType;
}
try {
// Look for the method on the current interface
Method interfaceMethod = clazz.getDeclaredMethod(method.getName(), (Class[]) method.getParameterTypes());
ConfigAttributeDefinition interfaceAssigned =
(ConfigAttributeDefinition) this.methodMap.get(interfaceMethod);
merge(attributesToReturn, interfaceAssigned);
} catch (Exception e) {
// skip this interface
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj != null && obj instanceof RegisteredMethod) {
RegisteredMethod rhs = (RegisteredMethod) obj;
return method.equals(rhs.method) && registeredJavaType.equals(rhs.registeredJavaType);
}
return false;
}
// Return null if empty, as per abstract superclass contract
if (attributesToReturn.size() == 0) {
return null;
public int hashCode() {
return method.hashCode() * registeredJavaType.hashCode();
}
return new ConfigAttributeDefinition(attributesToReturn);
public String toString() {
return "RegisteredMethod[" + registeredJavaType.getName() + "; " + method + "]";
}
}
private void merge(List attributes, ConfigAttributeDefinition toMerge) {
if (toMerge == null) {
return;
}
attributes.addAll(toMerge.getConfigAttributes());
}
public void setBeanClassLoader(ClassLoader beanClassLoader) {
Assert.notNull(beanClassLoader, "Bean class loader required");
this.beanClassLoader = beanClassLoader;
}
/**
* @return map size (for unit tests and diagnostics)
*/
public int getMethodMapSize() {
return methodMap.size();
}
/**
* Stores both the Java Method as well as the Class we obtained the Method from. This is necessary because Method only
* provides us access to the declaring class. It doesn't provide a way for us to introspect which Class the Method
* was registered against. If a given Class inherits and redeclares a method (i.e. calls super();) the registered Class
* and declaring Class are the same. If a given class merely inherits but does not redeclare a method, the registered
* Class will be the Class we're invoking against and the Method will provide details of the declared class.
*/
private class RegisteredMethod {
private Method method;
private Class registeredJavaType;
public RegisteredMethod(Method method, Class registeredJavaType) {
Assert.notNull(method, "Method required");
Assert.notNull(registeredJavaType, "Registered Java Type required");
this.method = method;
this.registeredJavaType = registeredJavaType;
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj != null && obj instanceof RegisteredMethod) {
RegisteredMethod rhs = (RegisteredMethod) obj;
return method.equals(rhs.method) && registeredJavaType.equals(rhs.registeredJavaType);
}
return false;
}
public int hashCode() {
return method.hashCode() * registeredJavaType.hashCode();
}
public String toString() {
return "RegisteredMethod[" + registeredJavaType.getName() + "; " + method + "]";
}
}
}
@@ -17,29 +17,30 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.security.intercept.method.aopalliance.MethodDefinitionSourceAdvisor;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Parses AspectJ pointcut expressions, registering methods that match the pointcut with a
* traditional {@link MapBasedMethodDefinitionSource}.
*
*
* <p>
* This class provides a convenient way of declaring a list of pointcuts, and then
* having every method of every bean defined in the Spring application context compared with
* those pointcuts. Where a match is found, the matching method will be registered with the
* {@link MapBasedMethodDefinitionSource}.
* </p>
*
*
* <p>
* It is very important to understand that only the <b>first</b> pointcut that matches a given
* method will be taken as authoritative for that method. This is why pointcuts should be provided
* as a <tt>LinkedHashMap</tt>, because their order is very important.
* </p>
*
*
* <p>
* Note also that only beans defined in the Spring application context will be examined by this
* class.
* class.
* </p>
*
*
* <p>
* Because this class registers method security metadata with {@link MapBasedMethodDefinitionSource},
* normal Spring Security capabilities such as {@link MethodDefinitionSourceAdvisor} can be used.
@@ -57,18 +58,19 @@ public final class ProtectPointcutPostProcessor implements BeanPostProcessor {
private static final Log logger = LogFactory.getLog(ProtectPointcutPostProcessor.class);
private Map pointcutMap = new LinkedHashMap(); /** Key: string-based pointcut, value: ConfigAttributeDefinition */
private MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource;
private PointcutParser parser;
public ProtectPointcutPostProcessor(MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource) {
Assert.notNull(mapBasedMethodDefinitionSource, "MapBasedMethodDefinitionSource to populate is required");
this.mapBasedMethodDefinitionSource = mapBasedMethodDefinitionSource;
// Setup AspectJ pointcut expression parser
Set supportedPrimitives = new HashSet();
supportedPrimitives.add(PointcutPrimitive.EXECUTION);
supportedPrimitives.add(PointcutPrimitive.ARGS);
supportedPrimitives.add(PointcutPrimitive.REFERENCE);
private MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource;
private PointcutParser parser;
private final Set processedBeans = new HashSet();
public ProtectPointcutPostProcessor(MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource) {
Assert.notNull(mapBasedMethodDefinitionSource, "MapBasedMethodDefinitionSource to populate is required");
this.mapBasedMethodDefinitionSource = mapBasedMethodDefinitionSource;
// Setup AspectJ pointcut expression parser
Set supportedPrimitives = new HashSet();
supportedPrimitives.add(PointcutPrimitive.EXECUTION);
supportedPrimitives.add(PointcutPrimitive.ARGS);
supportedPrimitives.add(PointcutPrimitive.REFERENCE);
// supportedPrimitives.add(PointcutPrimitive.THIS);
// supportedPrimitives.add(PointcutPrimitive.TARGET);
// supportedPrimitives.add(PointcutPrimitive.WITHIN);
@@ -76,79 +78,97 @@ public final class ProtectPointcutPostProcessor implements BeanPostProcessor {
// supportedPrimitives.add(PointcutPrimitive.AT_WITHIN);
// supportedPrimitives.add(PointcutPrimitive.AT_ARGS);
// supportedPrimitives.add(PointcutPrimitive.AT_TARGET);
parser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(supportedPrimitives);
}
parser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(supportedPrimitives);
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// Obtain methods for the present bean
Method[] methods;
try {
methods = bean.getClass().getMethods();
} catch (Exception e) {
throw new IllegalStateException(e.getMessage());
}
// Check to see if any of those methods are compatible with our pointcut expressions
for (int i = 0; i < methods.length; i++) {
Iterator iter = pointcutMap.keySet().iterator();
while (iter.hasNext()) {
String ex = iter.next().toString();
// Parse the presented AspectJ pointcut expression
PointcutExpression expression = parser.parsePointcutExpression(ex);
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (processedBeans.contains(beanName)) {
// We already have the metadata for this bean
return bean;
}
// Try for the bean class directly
if (attemptMatch(bean.getClass(), methods[i], expression, beanName)) {
// We've found the first expression that matches this method, so move onto the next method now
break; // the "while" loop, not the "for" loop
}
}
}
return bean;
}
private boolean attemptMatch(Class targetClass, Method method, PointcutExpression expression, String beanName) {
// Determine if the presented AspectJ pointcut expression matches this method
boolean matches = expression.matchesMethodExecution(method).alwaysMatches();
// Handle accordingly
if (matches) {
ConfigAttributeDefinition attr = (ConfigAttributeDefinition) pointcutMap.get(expression.getPointcutExpression());
if (logger.isDebugEnabled()) {
logger.debug("AspectJ pointcut expression '" + expression.getPointcutExpression() + "' matches target class '" + targetClass.getName() + "' (bean ID '" + beanName + "') for method '" + method + "'; registering security configuration attribute '" + attr + "'");
}
mapBasedMethodDefinitionSource.addSecureMethod(targetClass, method.getName(), attr);
}
return matches;
}
public void setPointcutMap(Map map) {
Assert.notEmpty(map);
Iterator i = map.keySet().iterator();
while (i.hasNext()) {
String expression = i.next().toString();
Object value = map.get(expression);
Assert.isInstanceOf(ConfigAttributeDefinition.class, value, "Map keys must be instances of ConfigAttributeDefinition");
addPointcut(expression, (ConfigAttributeDefinition) value);
}
}
// Obtain methods for the present bean
Method[] methods;
try {
methods = bean.getClass().getMethods();
} catch (Exception e) {
throw new IllegalStateException(e.getMessage());
}
// Check to see if any of those methods are compatible with our pointcut expressions
for (int i = 0; i < methods.length; i++) {
Iterator iter = pointcutMap.keySet().iterator();
while (iter.hasNext()) {
String ex = iter.next().toString();
// Parse the presented AspectJ pointcut expression
PointcutExpression expression = parser.parsePointcutExpression(ex);
// Try for the bean class directly
if (attemptMatch(bean.getClass(), methods[i], expression, beanName)) {
// We've found the first expression that matches this method, so move onto the next method now
break; // the "while" loop, not the "for" loop
}
}
}
processedBeans.add(beanName);
return bean;
}
private boolean attemptMatch(Class targetClass, Method method, PointcutExpression expression, String beanName) {
// Determine if the presented AspectJ pointcut expression matches this method
boolean matches = expression.matchesMethodExecution(method).alwaysMatches();
// Handle accordingly
if (matches) {
ConfigAttributeDefinition attr = (ConfigAttributeDefinition) pointcutMap.get(expression.getPointcutExpression());
if (logger.isDebugEnabled()) {
logger.debug("AspectJ pointcut expression '" + expression.getPointcutExpression() + "' matches target class '" + targetClass.getName() + "' (bean ID '" + beanName + "') for method '" + method + "'; registering security configuration attribute '" + attr + "'");
}
mapBasedMethodDefinitionSource.addSecureMethod(targetClass, method, attr);
}
return matches;
}
public void setPointcutMap(Map map) {
Assert.notEmpty(map);
Iterator i = map.keySet().iterator();
while (i.hasNext()) {
String expression = i.next().toString();
Object value = map.get(expression);
Assert.isInstanceOf(ConfigAttributeDefinition.class, value, "Map keys must be instances of ConfigAttributeDefinition");
addPointcut(expression, (ConfigAttributeDefinition) value);
}
}
private void addPointcut(String pointcutExpression, ConfigAttributeDefinition definition) {
Assert.hasText(pointcutExpression, "An AspectJ pointcut expression is required");
Assert.notNull(definition, "ConfigAttributeDefinition required");
pointcutExpression = replaceBooleanOperators(pointcutExpression);
pointcutMap.put(pointcutExpression, definition);
if (logger.isDebugEnabled()) {
logger.debug("AspectJ pointcut expression '" + pointcutExpression + "' registered for security configuration attribute '" + definition + "'");
}
}
/**
* @see org.springframework.aop.aspectj.AspectJExpressionPointcut#replaceBooleanOperators
*/
private String replaceBooleanOperators(String pcExpr) {
pcExpr = StringUtils.replace(pcExpr," and "," && ");
pcExpr = StringUtils.replace(pcExpr, " or ", " || ");
pcExpr = StringUtils.replace(pcExpr, " not ", " ! ");
return pcExpr;
}
public void addPointcut(String pointcutExpression, ConfigAttributeDefinition definition) {
Assert.hasText(pointcutExpression, "An AspectJ pointcut expression is required");
Assert.notNull(definition, "ConfigAttributeDefinition required");
pointcutMap.put(pointcutExpression, definition);
if (logger.isDebugEnabled()) {
logger.debug("AspectJ pointcut expression '" + pointcutExpression + "' registered for security configuration attribute '" + definition + "'");
}
}
}
@@ -33,7 +33,7 @@ import org.springframework.util.Assert;
* Advisor driven by a {@link MethodDefinitionSource}, used to exclude a {@link MethodSecurityInterceptor} from
* public (ie non-secure) methods.
* <p>
* Because the AOP framework caches advice calculations, this is normally faster than just letting the
* Because the AOP framework caches advice calculations, this is normally faster than just letting the
* <code>MethodSecurityInterceptor</code> run and find out itself that it has no work to do.
* <p>
* This class also allows the use of Spring's
@@ -63,64 +63,63 @@ public class MethodDefinitionSourceAdvisor extends AbstractPointcutAdvisor imple
* @deprecated use the decoupled approach instead
*/
public MethodDefinitionSourceAdvisor(MethodSecurityInterceptor advice) {
Assert.notNull(advice.getObjectDefinitionSource(), "Cannot construct a MethodDefinitionSourceAdvisor using a " +
"MethodSecurityInterceptor that has no ObjectDefinitionSource configured");
Assert.notNull(advice.getObjectDefinitionSource(), "Cannot construct a MethodDefinitionSourceAdvisor using a " +
"MethodSecurityInterceptor that has no ObjectDefinitionSource configured");
this.interceptor = advice;
this.interceptor = advice;
this.attributeSource = advice.getObjectDefinitionSource();
}
/**
* Alternative constructor for situations where we want the advisor decoupled from the advice. Instead the advice
* bean name should be set. This prevents eager instantiation of the interceptor
* bean name should be set. This prevents eager instantiation of the interceptor
* (and hence the AuthenticationManager). See SEC-773, for example.
* <p>
* This is essentially the approach taken by subclasses of {@link AbstractBeanFactoryPointcutAdvisor}, which this
* class should extend in future. The original hierarchy and constructor have been retained for backwards
* compatibilty.
*
* class should extend in future. The original hierarchy and constructor have been retained for backwards
* compatibility.
*
* @param adviceBeanName name of the MethodSecurityInterceptor bean
* @param attributeSource the attribute source (should be the same as the one used on the interceptor)
*/
public MethodDefinitionSourceAdvisor(String adviceBeanName, MethodDefinitionSource attributeSource) {
Assert.notNull(adviceBeanName, "The adviceBeanName cannot be null");
Assert.notNull(attributeSource, "The attributeSource cannot be null");
this.adviceBeanName = adviceBeanName;
this.attributeSource = attributeSource;
Assert.notNull(adviceBeanName, "The adviceBeanName cannot be null");
Assert.notNull(attributeSource, "The attributeSource cannot be null");
this.adviceBeanName = adviceBeanName;
this.attributeSource = attributeSource;
}
//~ Methods ========================================================================================================
public Pointcut getPointcut() {
return pointcut;
}
public Pointcut getPointcut() {
return pointcut;
}
public Advice getAdvice() {
synchronized (this.adviceMonitor) {
if (interceptor == null) {
Assert.notNull(adviceBeanName, "'adviceBeanName' must be set for use with bean factory lookup.");
Assert.state(beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
interceptor = (MethodSecurityInterceptor)
beanFactory.getBean(this.adviceBeanName, MethodSecurityInterceptor.class);
attributeSource = interceptor.getObjectDefinitionSource();
}
return interceptor;
}
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
public Advice getAdvice() {
synchronized (this.adviceMonitor) {
if (interceptor == null) {
Assert.notNull(adviceBeanName, "'adviceBeanName' must be set for use with bean factory lookup.");
Assert.state(beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
interceptor = (MethodSecurityInterceptor)
beanFactory.getBean(this.adviceBeanName, MethodSecurityInterceptor.class);
}
return interceptor;
}
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
//~ Inner Classes ==================================================================================================
class MethodDefinitionSourcePointcut extends StaticMethodMatcherPointcut {
public boolean matches(Method m, Class targetClass) {
return attributeSource.getAttributes(m, targetClass) != null;
}
}
/**
* Represents a <code>MethodInvocation</code>.
* <p>
@@ -153,7 +152,7 @@ public class MethodDefinitionSourceAdvisor extends AbstractPointcutAdvisor imple
}
public Object getThis() {
return this.targetClass;
return this.targetClass;
}
public Object proceed() throws Throwable {
@@ -12,5 +12,5 @@ package org.springframework.security.intercept.method.aspectj;
public interface AspectJAnnotationCallback {
//~ Methods ========================================================================================================
Object proceedWithObject();
Object proceedWithObject() throws Throwable;
}
@@ -54,4 +54,16 @@ public class RequestKey {
return method.equals(key.method);
}
public String toString() {
StringBuffer sb = new StringBuffer(url.length() + 7);
sb.append("[");
if (method != null) {
sb.append(method).append(",");
}
sb.append(url);
sb.append("]");
return sb.toString();
}
}
@@ -71,6 +71,7 @@ public class DefaultSpringSecurityContextSource extends LdapContextSource implem
env.put(Context.SECURITY_PRINCIPAL, userDn);
env.put(Context.SECURITY_CREDENTIALS, credentials);
env.remove(SUN_LDAP_POOLING_FLAG);
if (logger.isDebugEnabled()) {
logger.debug("Creating context with principal: '" + userDn + "'");
@@ -158,7 +158,7 @@ public final class LdapUtils {
if (url.startsWith("ldap:") || url.startsWith("ldaps:")) {
URI uri = parseLdapUrl(url);
urlRootDn = uri.getPath();
urlRootDn = uri.getRawPath();
} else {
// Assume it's an embedded server
urlRootDn = url;
@@ -15,6 +15,21 @@
package org.springframework.security.ldap;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.PartialResultException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.ldap.core.ContextExecutor;
import org.springframework.ldap.core.ContextMapper;
@@ -23,33 +38,18 @@ import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapEncoder;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.util.Assert;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.Set;
import java.util.Arrays;
/**
* LDAP equivalent of the Spring JdbcTemplate class.
* <p>
* This is mainly intended to simplify Ldap access within Spring Security's LDAP-related services.
* </p>
* Extension of Spring LDAP's LdapTemplate class which adds extra functionality required by Spring Security.
*
* @author Ben Alex
* @author Luke Taylor
* @since 2.0
*/
public class SpringSecurityLdapTemplate extends org.springframework.ldap.core.LdapTemplate {
public class SpringSecurityLdapTemplate extends LdapTemplate {
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(SpringSecurityLdapTemplate.class);
@@ -136,14 +136,14 @@ public class SpringSecurityLdapTemplate extends org.springframework.ldap.core.Ld
* @return the set of String values for the attribute as a union of the values found in all the matching entries.
*/
public Set searchForSingleAttributeValues(final String base, final String filter, final Object[] params,
final String attributeName) {
// Escape the params acording to RFC2254
Object[] encodedParams = new String[params.length];
for (int i=0; i < params.length; i++) {
encodedParams[i] = LdapEncoder.filterEncode(params[i].toString());
}
final String attributeName) {
// Escape the params acording to RFC2254
Object[] encodedParams = new String[params.length];
for (int i=0; i < params.length; i++) {
encodedParams[i] = LdapEncoder.filterEncode(params[i].toString());
}
String formattedFilter = MessageFormat.format(filter, encodedParams);
logger.debug("Using filter: " + formattedFilter);
@@ -175,12 +175,15 @@ public class SpringSecurityLdapTemplate extends org.springframework.ldap.core.Ld
/**
* Performs a search, with the requirement that the search shall return a single directory entry, and uses
* the supplied mapper to create the object from that entry.
* <p>
* Ignores <tt>PartialResultException</tt> if thrown, for compatibility with Active Directory
* (see {@link LdapTemplate#setIgnorePartialResultException(boolean)}).
*
* @param base
* @param filter
* @param params
* @param base the search base, relative to the base context supplied by the context source.
* @param filter the LDAP search filter
* @param params parameters to be substituted in the search.
*
* @return the object created by the mapper from the matching entry
* @return a DirContextOperations instance created from the matching entry.
*
* @throws IncorrectResultSizeDataAccessException if no results are found or the search returns more than one
* result.
@@ -188,32 +191,43 @@ public class SpringSecurityLdapTemplate extends org.springframework.ldap.core.Ld
public DirContextOperations searchForSingleEntry(final String base, final String filter, final Object[] params) {
return (DirContextOperations) executeReadOnly(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
public Object executeWithContext(DirContext ctx) throws NamingException {
DistinguishedName ctxBaseDn = new DistinguishedName(ctx.getNameInNamespace());
if (logger.isDebugEnabled()) {
logger.debug("Searching for entry in under DN '" + ctxBaseDn
+ "', base = '" + base + "', filter = '" + filter + "'");
}
NamingEnumeration results = ctx.search(base, filter, params, searchControls);
NamingEnumeration resultsEnum = ctx.search(base, filter, params, searchControls);
Set results = new HashSet();
try {
while (resultsEnum.hasMore()) {
SearchResult searchResult = (SearchResult) resultsEnum.next();
// Work out the DN of the matched entry
DistinguishedName dn = new DistinguishedName(searchResult.getName());
if (!results.hasMore()) {
if (base.length() > 0) {
dn.prepend(new DistinguishedName(base));
}
if (logger.isDebugEnabled()) {
logger.debug("Found DN: " + dn);
}
results.add(new DirContextAdapter(searchResult.getAttributes(), dn, ctxBaseDn));
}
} catch (PartialResultException e) {
logger.info("Ignoring PartialResultException");
}
if (results.size() == 0) {
throw new IncorrectResultSizeDataAccessException(1, 0);
}
SearchResult searchResult = (SearchResult) results.next();
if (results.hasMore()) {
// We don't know how many results but set to 2 which is good enough
throw new IncorrectResultSizeDataAccessException(1, 2);
if (results.size() > 1) {
throw new IncorrectResultSizeDataAccessException(1, results.size());
}
// Work out the DN of the matched entry
StringBuffer dn = new StringBuffer(searchResult.getName());
if (base.length() > 0) {
dn.append(",");
dn.append(base);
}
return new DirContextAdapter(searchResult.getAttributes(),
new DistinguishedName(dn.toString()), new DistinguishedName(ctx.getNameInNamespace()));
return results.toArray()[0];
}
});
}
@@ -99,8 +99,6 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
*/
private GrantedAuthority defaultRole;
private ContextSource contextSource;
private SpringSecurityLdapTemplate ldapTemplate;
/**
@@ -143,8 +141,10 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
* context factory.
*/
public DefaultLdapAuthoritiesPopulator(ContextSource contextSource, String groupSearchBase) {
this.setContextSource(contextSource);
this.setGroupSearchBase(groupSearchBase);
Assert.notNull(contextSource, "contextSource must not be null");
ldapTemplate = new SpringSecurityLdapTemplate(contextSource);
ldapTemplate.setSearchControls(searchControls);
setGroupSearchBase(groupSearchBase);
}
//~ Methods ========================================================================================================
@@ -226,20 +226,7 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
}
protected ContextSource getContextSource() {
return contextSource;
}
/**
* Set the {@link ContextSource}
*
* @param contextSource supplies the contexts used to search for user roles.
*/
private void setContextSource(ContextSource contextSource) {
Assert.notNull(contextSource, "contextSource must not be null");
this.contextSource = contextSource;
ldapTemplate = new SpringSecurityLdapTemplate(contextSource);
ldapTemplate.setSearchControls(searchControls);
return ldapTemplate.getContextSource();
}
/**
@@ -144,17 +144,10 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
checkIfValidList(this.providers);
Assert.notNull(this.messages, "A message source must be set");
exceptionMappings.putAll(additionalExceptionMappings);
}
private void checkIfValidList(List listToCheck) {
if ((listToCheck == null) || (listToCheck.size() == 0)) {
throw new IllegalArgumentException("A list of AuthenticationProviders is required");
}
}
/**
* Attempts to authenticate the passed {@link Authentication} object.
* <p>
@@ -174,7 +167,7 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
* @throws AuthenticationException if authentication fails.
*/
public Authentication doAuthentication(Authentication authentication) throws AuthenticationException {
Iterator iter = providers.iterator();
Iterator iter = getProviders().iterator();
Class toTest = authentication.getClass();
@@ -273,7 +266,11 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
}
public List getProviders() {
return this.providers;
if (providers == null || providers.size() == 0) {
throw new IllegalArgumentException("A list of AuthenticationProviders is required");
}
return providers;
}
/**
@@ -303,8 +300,7 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
* AuthenticationProvider instance.
*/
public void setProviders(List providers) {
checkIfValidList(providers);
Assert.notEmpty(providers, "A list of AuthenticationProviders is required");
Iterator iter = providers.iterator();
while (iter.hasNext()) {
@@ -15,30 +15,28 @@
package org.springframework.security.providers.anonymous;
import org.springframework.security.SpringSecurityMessageSource;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationException;
import org.springframework.security.BadCredentialsException;
import org.springframework.security.providers.AuthenticationProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationException;
import org.springframework.security.BadCredentialsException;
import org.springframework.security.SpringSecurityMessageSource;
import org.springframework.security.providers.AuthenticationProvider;
import org.springframework.util.Assert;
/**
* An {@link AuthenticationProvider} implementation that validates {@link
* org.springframework.security.providers.anonymous.AnonymousAuthenticationToken}s.<p>To be successfully validated, the
* {@link org.springframework.security.providers.anonymous.AnonymousAuthenticationToken#getKeyHash()} must match this class'
* {@link #getKey()}.</p>
* An {@link AuthenticationProvider} implementation that validates {@link AnonymousAuthenticationToken}s.
* <p>
* To be successfully validated, the {@link AnonymousAuthenticationToken#getKeyHash()} must match this class'
* {@link #getKey()}.
*
* @author Ben Alex
* @version $Id$
*/
public class AnonymousAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(AnonymousAuthenticationProvider.class);
//~ Instance fields ================================================================================================
@@ -47,7 +45,7 @@ public class AnonymousAuthenticationProvider implements AuthenticationProvider,
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
public void afterPropertiesSet() throws Exception {
Assert.hasLength(key, "A Key is required");
Assert.notNull(this.messages, "A message source must be set");
}
@@ -15,22 +15,26 @@
package org.springframework.security.providers.ldap.authenticator;
import org.springframework.security.Authentication;
import org.springframework.security.BadCredentialsException;
import org.springframework.security.ldap.SpringSecurityContextSource;
import org.springframework.security.ldap.SpringSecurityLdapTemplate;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.dao.DataAccessException;
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.util.Assert;
import java.util.Iterator;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.naming.directory.DirContext;
import java.util.Iterator;
import org.springframework.dao.DataAccessException;
import org.springframework.ldap.NamingException;
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.ldap.support.LdapUtils;
import org.springframework.security.Authentication;
import org.springframework.security.BadCredentialsException;
import org.springframework.security.ldap.SpringSecurityContextSource;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.util.Assert;
/**
@@ -91,21 +95,42 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
return user;
}
private DirContextOperations bindWithDn(String userDn, String username, String password) {
SpringSecurityLdapTemplate template = new SpringSecurityLdapTemplate(
new BindWithSpecificDnContextSource((SpringSecurityContextSource) getContextSource(), userDn, password));
private DirContextOperations bindWithDn(String userDnStr, String username, String password) {
BaseLdapPathContextSource ctxSource = (BaseLdapPathContextSource) getContextSource();
DistinguishedName userDn = new DistinguishedName(userDnStr);
DistinguishedName fullDn = new DistinguishedName(userDn);
fullDn.prepend(ctxSource.getBaseLdapPath());
BindWithSpecificDnContextSource specificDnContextSource = new BindWithSpecificDnContextSource(
(SpringSecurityContextSource) getContextSource(), fullDn,
password);
logger.debug("Attemptimg to bind as " + fullDn);
DirContext ctx = null;
try {
ctx = specificDnContextSource.getReadOnlyContext();
try {
return template.retrieveEntry(userDn, getUserAttributes());
Attributes attrs = ctx.getAttributes(userDn, getUserAttributes());
} 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
// unless a subclass wishes to implement more specialized behaviour.
handleBindException(userDn, username, e.getCause());
}
DirContextAdapter result = new DirContextAdapter(attrs, userDn, ctxSource.getBaseLdapPath());
return result;
} catch (NamingException 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
// unless a subclass wishes to implement more specialized behaviour.
if ((e instanceof org.springframework.ldap.AuthenticationException)
|| (e instanceof org.springframework.ldap.OperationNotSupportedException)) {
handleBindException(userDnStr, username, e);
} else {
throw e;
}
} catch (javax.naming.NamingException e) {
throw LdapUtils.convertLdapException(e);
} finally {
LdapUtils.closeContext(ctx);
}
return null;
return null;
}
/**
@@ -120,13 +145,12 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
private class BindWithSpecificDnContextSource implements ContextSource {
private SpringSecurityContextSource ctxFactory;
DistinguishedName userDn;
private DistinguishedName userDn;
private String password;
public BindWithSpecificDnContextSource(SpringSecurityContextSource ctxFactory, String userDn, String password) {
public BindWithSpecificDnContextSource(SpringSecurityContextSource ctxFactory, DistinguishedName userDn, String password) {
this.ctxFactory = ctxFactory;
this.userDn = new DistinguishedName(userDn);
this.userDn.prepend(ctxFactory.getBaseLdapPath());
this.userDn = userDn;
this.password = password;
}
@@ -86,9 +86,9 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
sha.update(rawPass.getBytes("UTF-8"));
} catch (java.security.NoSuchAlgorithmException e) {
throw new IllegalStateException("No SHA implementation available!");
} catch (UnsupportedEncodingException ue) {
throw new IllegalStateException("UTF-8 not supported!");
}
} catch (UnsupportedEncodingException ue) {
throw new IllegalStateException("UTF-8 not supported!");
}
if (salt != null) {
Assert.isInstanceOf(byte[].class, salt, "Salt value must be a byte array");
@@ -131,7 +131,7 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
*/
public boolean isPasswordValid(final String encPass, final String rawPass, Object salt) {
String prefix = extractPrefix(encPass);
if (prefix == null) {
return encPass.equals(rawPass);
}
@@ -141,32 +141,32 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
} else if (!prefix.equals(SHA_PREFIX) && !prefix.equals(SHA_PREFIX_LC)) {
throw new IllegalArgumentException("Unsupported password prefix '" + prefix + "'");
} else {
// Standard SHA
salt = null;
// Standard SHA
salt = null;
}
int startOfHash = prefix.length() + 1;
int startOfHash = prefix.length();
String encodedRawPass = encodePassword(rawPass, salt).substring(startOfHash);
return encodedRawPass.equals(encPass.substring(startOfHash));
}
/**
* Returns the hash prefix or null if there isn't one.
* Returns the hash prefix or null if there isn't one.
*/
private String extractPrefix(String encPass) {
if (!encPass.startsWith("{")) {
return null;
return null;
}
int secondBrace = encPass.lastIndexOf('}');
if (secondBrace < 0) {
throw new IllegalArgumentException("Couldn't find closing brace for SHA prefix");
}
return encPass.substring(0, secondBrace + 1);
int secondBrace = encPass.lastIndexOf('}');
if (secondBrace < 0) {
throw new IllegalArgumentException("Couldn't find closing brace for SHA prefix");
}
return encPass.substring(0, secondBrace + 1);
}
public void setForceLowerCasePrefix(boolean forceLowerCasePrefix) {
@@ -45,7 +45,7 @@ import java.security.cert.X509Certificate;
*
* @author Luke Taylor
* @deprecated superceded by the preauth provider. Use the X.509 authentication support in org.springframework.security.ui.preauth.x509 instead
* or namespace support via the &lt;x509 /&gt; element.
* or namespace support via the &lt;x509 /&gt; element.
* @version $Id$
*/
public class X509AuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {
@@ -61,7 +61,7 @@ public class X509AuthenticationProvider implements AuthenticationProvider, Initi
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
public void afterPropertiesSet() throws Exception {
Assert.notNull(userCache, "An x509UserCache must be set");
Assert.notNull(x509AuthoritiesPopulator, "An X509AuthoritiesPopulator must be set");
Assert.notNull(this.messages, "A message source must be set");
@@ -101,7 +101,9 @@ public class X509AuthenticationProvider implements AuthenticationProvider, Initi
UserDetails user = userCache.getUserFromCache(clientCertificate);
if (user == null) {
logger.debug("Authenticating with certificate " + clientCertificate);
if (logger.isDebugEnabled()) {
logger.debug("Authenticating with certificate " + clientCertificate);
}
user = x509AuthoritiesPopulator.getUserDetails(clientCertificate);
userCache.putUserInCache(clientCertificate, user);
}
@@ -122,7 +122,8 @@ import javax.servlet.http.HttpSession;
* The behaviour is turned off by default. Additionally there is a property <tt>migrateInvalidatedSessionAttributes</tt>
* which tells if on session invalidation we are to migrate all session attributes from the old session to a newly
* created one. This is turned on by default, but not used unless <tt>invalidateSessionOnSuccessfulAuthentication</tt>
* is true.
* is true. If you are using this feature in combination with concurrent session control, you should set the
* <tt>sessionRegistry</tt> property to make sure that the session information is updated consistently.
*
* @author Ben Alex
* @version $Id$
@@ -147,10 +148,14 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
private Properties exceptionMappings = new Properties();
private RememberMeServices rememberMeServices = new NullRememberMeServices();
/**
* Delay use of NullRememberMeServices until initialization so that namespace has a chance to inject
* the RememberMeServices implementation into custom implementations.
*/
private RememberMeServices rememberMeServices = null;
private TargetUrlResolver targetUrlResolver = new TargetUrlResolverImpl();
/** Where to redirect the browser to if authentication fails */
private String authenticationFailureUrl;
@@ -206,23 +211,25 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
private boolean migrateInvalidatedSessionAttributes = true;
private boolean allowSessionCreation = true;
private boolean serverSideRedirect = false;
private SessionRegistry sessionRegistry;
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
Assert.hasLength(filterProcessesUrl, "filterProcessesUrl must be specified");
Assert.isTrue(UrlUtils.isValidRedirectUrl(filterProcessesUrl), filterProcessesUrl + " isn't a valid redirect URL");
Assert.isTrue(UrlUtils.isValidRedirectUrl(filterProcessesUrl), filterProcessesUrl + " isn't a valid redirect URL");
Assert.hasLength(defaultTargetUrl, "defaultTargetUrl must be specified");
Assert.isTrue(UrlUtils.isValidRedirectUrl(defaultTargetUrl), defaultTargetUrl + " isn't a valid redirect URL");
// Assert.hasLength(authenticationFailureUrl, "authenticationFailureUrl must be specified");
Assert.isTrue(UrlUtils.isValidRedirectUrl(defaultTargetUrl), defaultTargetUrl + " isn't a valid redirect URL");
Assert.isTrue(UrlUtils.isValidRedirectUrl(authenticationFailureUrl), authenticationFailureUrl + " isn't a valid redirect URL");
Assert.notNull(authenticationManager, "authenticationManager must be specified");
Assert.notNull(rememberMeServices, "rememberMeServices cannot be null");
Assert.notNull(targetUrlResolver, "targetUrlResolver cannot be null");
if (rememberMeServices == null) {
rememberMeServices = new NullRememberMeServices();
}
}
/**
@@ -272,8 +279,8 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
}
public static String obtainFullSavedRequestUrl(HttpServletRequest request) {
SavedRequest savedRequest = getSavedRequest(request);
SavedRequest savedRequest = getSavedRequest(request);
return savedRequest == null ? null : savedRequest.getFullRequestUrl();
}
@@ -286,9 +293,9 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
SavedRequest savedRequest = (SavedRequest) session.getAttribute(SPRING_SECURITY_SAVED_REQUEST_KEY);
return savedRequest;
}
return savedRequest;
}
protected void onPreAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException {
}
@@ -381,8 +388,8 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
protected String determineTargetUrl(HttpServletRequest request) {
// Don't attempt to obtain the url from the saved request if alwaysUsedefaultTargetUrl is set
String targetUrl = alwaysUseDefaultTargetUrl ? null :
targetUrlResolver.determineTargetUrl(getSavedRequest(request), request, SecurityContextHolder.getContext().getAuthentication());
String targetUrl = alwaysUseDefaultTargetUrl ? null :
targetUrlResolver.determineTargetUrl(getSavedRequest(request), request, SecurityContextHolder.getContext().getAuthentication());
if (targetUrl == null) {
targetUrl = getDefaultTargetUrl();
@@ -418,13 +425,13 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
onUnsuccessfulAuthentication(request, response, failed);
rememberMeServices.loginFail(request, response);
if (failureUrl == null) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed:" + failed.getMessage());
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed:" + failed.getMessage());
} else if (serverSideRedirect){
request.getRequestDispatcher(failureUrl).forward(request, response);
request.getRequestDispatcher(failureUrl).forward(request, response);
} else {
sendRedirect(request, response, failureUrl);
sendRedirect(request, response, failureUrl);
}
}
@@ -475,7 +482,7 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
this.defaultTargetUrl = defaultTargetUrl;
}
Properties getExceptionMappings() {
protected Properties getExceptionMappings() {
return new Properties(exceptionMappings);
}
@@ -549,33 +556,33 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
this.allowSessionCreation = allowSessionCreation;
}
/**
* @return the targetUrlResolver
*/
protected TargetUrlResolver getTargetUrlResolver() {
return targetUrlResolver;
}
/**
* @return the targetUrlResolver
*/
protected TargetUrlResolver getTargetUrlResolver() {
return targetUrlResolver;
}
/**
* @param targetUrlResolver the targetUrlResolver to set
*/
public void setTargetUrlResolver(TargetUrlResolver targetUrlResolver) {
this.targetUrlResolver = targetUrlResolver;
}
/**
* @param targetUrlResolver the targetUrlResolver to set
*/
public void setTargetUrlResolver(TargetUrlResolver targetUrlResolver) {
this.targetUrlResolver = targetUrlResolver;
}
/**
* Tells if we are to do a server side include of the error URL instead of a 302 redirect.
*
* @param serverSideRedirect
*/
public void setServerSideRedirect(boolean serverSideRedirect) {
this.serverSideRedirect = serverSideRedirect;
}
*/
public void setServerSideRedirect(boolean serverSideRedirect) {
this.serverSideRedirect = serverSideRedirect;
}
/**
* The session registry needs to be set if session fixation attack protection is in use (and concurrent
* session control is enabled).
*/
/**
* The session registry needs to be set if session fixation attack protection is in use (and concurrent
* session control is enabled).
*/
public void setSessionRegistry(SessionRegistry sessionRegistry) {
this.sessionRegistry = sessionRegistry;
}
@@ -48,7 +48,7 @@ public class SessionFixationProtectionFilter extends SpringSecurityFilter {
protected void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
// Session fixation isn't a problem if there's no session
if(request.getSession(false) == null || request.getAttribute(FILTER_APPLIED) != null) {
if(request.getSession(false) == null || request.getAttribute(FILTER_APPLIED) != null || !request.isRequestedSessionIdValid()) {
chain.doFilter(request, response);
return;
}
@@ -35,6 +35,7 @@ import org.springframework.security.ui.WebAuthenticationDetailsSource;
import org.springframework.security.ui.AuthenticationEntryPoint;
import org.springframework.security.ui.FilterChainOrder;
import org.springframework.security.ui.SpringSecurityFilter;
import org.springframework.security.ui.rememberme.NullRememberMeServices;
import org.springframework.security.ui.rememberme.RememberMeServices;
import org.springframework.util.Assert;
@@ -91,7 +92,7 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource();
private AuthenticationEntryPoint authenticationEntryPoint;
private AuthenticationManager authenticationManager;
private RememberMeServices rememberMeServices;
private RememberMeServices rememberMeServices = new NullRememberMeServices();
private boolean ignoreFailure = false;
private String credentialsCharset = "UTF-8";
@@ -105,10 +106,10 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
}
}
public void doFilterHttp(HttpServletRequest httpRequest, HttpServletResponse httpResponse, FilterChain chain)
public void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
String header = httpRequest.getHeader("Authorization");
String header = request.getHeader("Authorization");
if (logger.isDebugEnabled()) {
logger.debug("Authorization header: " + header);
@@ -116,7 +117,7 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
if ((header != null) && header.startsWith("Basic ")) {
byte[] base64Token = header.substring(6).getBytes("UTF-8");
String token = new String(Base64.decodeBase64(base64Token), getCredentialsCharset(httpRequest));
String token = new String(Base64.decodeBase64(base64Token), getCredentialsCharset(request));
String username = "";
String password = "";
@@ -130,7 +131,7 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
if (authenticationIsRequired(username)) {
UsernamePasswordAuthenticationToken authRequest =
new UsernamePasswordAuthenticationToken(username, password);
authRequest.setDetails(authenticationDetailsSource.buildDetails(httpRequest));
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
Authentication authResult;
@@ -144,14 +145,14 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
SecurityContextHolder.getContext().setAuthentication(null);
if (rememberMeServices != null) {
rememberMeServices.loginFail(httpRequest, httpResponse);
}
rememberMeServices.loginFail(request, response);
onUnsuccessfulAuthentication(request, response, failed);
if (ignoreFailure) {
chain.doFilter(httpRequest, httpResponse);
chain.doFilter(request, response);
} else {
authenticationEntryPoint.commence(httpRequest, httpResponse, failed);
authenticationEntryPoint.commence(request, response, failed);
}
return;
@@ -164,13 +165,13 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
SecurityContextHolder.getContext().setAuthentication(authResult);
if (rememberMeServices != null) {
rememberMeServices.loginSuccess(httpRequest, httpResponse, authResult);
}
rememberMeServices.loginSuccess(request, response, authResult);
onSuccessfulAuthentication(request, response, authResult);
}
}
chain.doFilter(httpRequest, httpResponse);
chain.doFilter(request, response);
}
private boolean authenticationIsRequired(String username) {
@@ -202,6 +203,14 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
return false;
}
protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
Authentication authResult) throws IOException {
}
protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
AuthenticationException failed) throws IOException {
}
protected AuthenticationEntryPoint getAuthenticationEntryPoint() {
return authenticationEntryPoint;
@@ -233,6 +242,7 @@ public class BasicProcessingFilter extends SpringSecurityFilter implements Initi
}
public void setRememberMeServices(RememberMeServices rememberMeServices) {
Assert.notNull(rememberMeServices, "rememberMeServices cannot be null");
this.rememberMeServices = rememberMeServices;
}
@@ -34,10 +34,10 @@ import javax.servlet.http.HttpSession;
* @version $Id$
*/
public class SecurityContextLogoutHandler implements LogoutHandler {
//~ Methods ========================================================================================================
private boolean invalidateHttpSession = true;
//~ Methods ========================================================================================================
/**
* Requires the request to be passed in.
*
@@ -69,6 +69,6 @@ public class SecurityContextLogoutHandler implements LogoutHandler {
*/
public void setInvalidateHttpSession(boolean invalidateHttpSession) {
this.invalidateHttpSession = invalidateHttpSession;
}
}
}
@@ -25,6 +25,13 @@ import org.springframework.util.Assert;
/**
* Base class for processing filters that handle pre-authenticated authentication requests. Subclasses must implement
* the getPreAuthenticatedPrincipal() and getPreAuthenticatedCredentials() methods.
* <p>
* By default, the filter chain will proceed when an authentication attempt fails in order to allow other
* authentication mechanisms to process the request. To reject the credentials immediately, set the
* <tt>continueFilterChainOnUnsuccessfulAuthentication</tt> flag to false. The exception raised by the
* <tt>AuthenticationManager</tt> will the be re-thrown. Note that this will not affect cases where the principal
* returned by {@link #getPreAuthenticatedPrincipal} is null, when the chain will still proceed as normal.
*
*
* @author Luke Taylor
* @author Ruud Senden
@@ -38,6 +45,8 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends SpringSec
private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource();
private AuthenticationManager authenticationManager = null;
private boolean continueFilterChainOnUnsuccessfulAuthentication = true;
/**
* Check whether all required properties have been set.
@@ -88,6 +97,10 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends SpringSec
successfulAuthentication(request, response, authResult);
} catch (AuthenticationException failed) {
unsuccessfulAuthentication(request, response, failed);
if (!continueFilterChainOnUnsuccessfulAuthentication) {
throw failed;
}
}
}
@@ -143,8 +156,19 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends SpringSec
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
public void setContinueFilterChainOnUnsuccessfulAuthentication(boolean shouldContinue) {
continueFilterChainOnUnsuccessfulAuthentication = shouldContinue;
}
/**
* Override to extract the principal information from the current request
*/
protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request);
/**
* Override to extract the credentials (if applicable) from the current request. Some implementations
* may return a dummy value.
*/
protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);
}
@@ -32,14 +32,14 @@ import javax.servlet.http.HttpServletResponse;
* @since 2.0
*/
public abstract class AbstractRememberMeServices implements RememberMeServices, InitializingBean, LogoutHandler {
//~ Static fields/initializers =====================================================================================
//~ Static fields/initializers =====================================================================================
public static final String SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY = "SPRING_SECURITY_REMEMBER_ME_COOKIE";
public static final String DEFAULT_PARAMETER = "_spring_security_remember_me";
private static final String DELIMITER = ":";
//~ Instance fields ================================================================================================
//~ Instance fields ================================================================================================
protected final Log logger = LogFactory.getLog(getClass());
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
@@ -49,7 +49,7 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource();
private String cookieName = SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY;
private String parameter = DEFAULT_PARAMETER;
private String parameter = DEFAULT_PARAMETER;
private boolean alwaysRemember;
private String key;
private int tokenValiditySeconds = 1209600; // 14 days
@@ -232,14 +232,14 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
}
String paramValue = request.getParameter(parameter);
if (paramValue != null) {
if (paramValue.equalsIgnoreCase("true") || paramValue.equalsIgnoreCase("on") ||
paramValue.equalsIgnoreCase("yes") || paramValue.equals("1")) {
return true;
}
}
if (paramValue.equalsIgnoreCase("true") || paramValue.equalsIgnoreCase("on") ||
paramValue.equalsIgnoreCase("yes") || paramValue.equals("1")) {
return true;
}
}
if (logger.isDebugEnabled()) {
logger.debug("Did not send remember-me cookie (principal did not set parameter '" + parameter + "')");
}
@@ -309,6 +309,10 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
this.cookieName = cookieName;
}
protected String getCookieName() {
return cookieName;
}
public void setAlwaysRemember(boolean alwaysRemember) {
this.alwaysRemember = alwaysRemember;
}
@@ -316,11 +320,11 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
/**
* Sets the name of the parameter which should be checked for to see if a remember-me has been requested
* during a login request. This should be the same name you assign to the checkbox in your login form.
*
*
* @param parameter the HTTP request parameter
*/
public void setParameter(String parameter) {
Assert.hasText(parameter, "Parameter name cannot be null");
Assert.hasText(parameter, "Parameter name cannot be null");
this.parameter = parameter;
}
@@ -333,7 +337,7 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
}
public void setUserDetailsService(UserDetailsService userDetailsService) {
Assert.notNull(userDetailsService, "UserDetailsService canot be null");
Assert.notNull(userDetailsService, "UserDetailsService canot be null");
this.userDetailsService = userDetailsService;
}
@@ -357,8 +361,8 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
return authenticationDetailsSource;
}
public void setAuthenticationDetailsSource(AuthenticationDetailsSource authenticationDetailsSource) {
Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource cannot be null");
this.authenticationDetailsSource = authenticationDetailsSource;
}
public void setAuthenticationDetailsSource(AuthenticationDetailsSource authenticationDetailsSource) {
Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource cannot be null");
this.authenticationDetailsSource = authenticationDetailsSource;
}
}
@@ -304,8 +304,7 @@ public class SwitchUserProcessingFilter extends SpringSecurityFilter implements
logger.debug("Switch User failed", failed);
if (switchFailureUrl != null) {
switchFailureUrl = request.getContextPath() + switchFailureUrl;
response.sendRedirect(response.encodeRedirectURL(switchFailureUrl));
sendRedirect(request, response, switchFailureUrl);
} else {
response.getWriter().print("Switch user failed: " + failed.getMessage());
response.flushBuffer();
@@ -25,6 +25,8 @@ import org.springframework.dao.DataAccessException;
* instead of only the directly assigned authorities.
*
* @author Michael Mayr
* @deprecated use a {@link RoleHierarchyVoter} instead of populating the user Authentication object
* with the additional authorities.
*/
public class UserDetailsServiceWrapper implements UserDetailsService {
@@ -23,6 +23,7 @@ import org.springframework.security.userdetails.UserDetails;
* delegated to the <tt>UserDetails</tt> implementation.
*
* @author Michael Mayr
* @deprecated use a {@link RoleHierarchyVoter} instead.
*/
public class UserDetailsWrapper implements UserDetails {
@@ -47,23 +47,53 @@ import javax.sql.DataSource;
/**
* Retrieves user details (username, password, enabled flag, and authorities) from a JDBC location.
* <tt>UserDetailsServiceRetrieves</tt> implementation which retrieves the user details
* (username, password, enabled flag, and authorities) from a database using JDBC queries.
*
* <h3>Default Schema</h3>
* A default database schema is assumed, with two tables "users" and "authorities".
*
* <h4>The Users table</h4>
*
* This table contains the login name, password and enabled status of the user.
*
* <table>
* <tr><th>Column</th></tr>
* <tr><td>username</td></tr>
* <tr><td>password</td></tr>
* <tr><td>enabled</td></tr>
* </table>
*
* <h4>The Authorities Table</h4>
*
* <table>
* <tr><th>Column</th></tr>
* <tr><td>username</td></tr>
* <tr><td>authority</td></tr>
* </table>
*
* If you are using an existing schema you will have to set the queries <tt>usersByUsernameQuery</tt> and
* <tt>authoritiesByUsernameQuery</tt> to match your database setup
* (see {@link #DEF_USERS_BY_USERNAME_QUERY} and {@link #DEF_AUTHORITIES_BY_USERNAME_QUERY}).
*
* <p>
* A default database structure is assumed, (see {@link #DEF_USERS_BY_USERNAME_QUERY} and {@link
* #DEF_AUTHORITIES_BY_USERNAME_QUERY}, which most users of this class will need to override, if using an existing
* scheme. This may be done by setting the default query strings used.
* <p>
* In order to minimise backward compatibility issues, this DAO does not recognise the expiration of user
* In order to minimise backward compatibility issues, this implementation doesn't recognise the expiration of user
* accounts or the expiration of user credentials. However, it does recognise and honour the user enabled/disabled
* column.
* <p>
* column. This should map to a <tt>boolean</tt> type in the result set (the SQL type will depend on the
* database you are using). All the other columns map to <tt>String</tt>s.
*
* <h3>Group Support</h3>
* Support for group-based authorities can be enabled by setting the <tt>enableGroups</tt> property to <tt>true</tt>
* (you may also then wish to set <tt>enableAuthorities</tt> to <tt>false</tt> to disable loading of authorities
* directly). With this approach, authorities are allocated to groups and a user's authorities are determined based
* on the groups they are a member of. The net result is the same (a UserDetails containing a set of
* <tt>GrantedAuthority</tt>s is loaded), but the different persistence strategy may be more suitable for the
* administration of some applications.
*
* <p>
* When groups are being used, the tables "groups", "group_members" and "group_authorities" are used. See
* {@link #DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY} for the default query which is used to load the group authorities.
* Again you can customize this by setting the <tt>groupAuthoritiesByUsernameQuery</tt> property, but the format of
* the rows returned should match the default.
*
* @author Ben Alex
* @author colin sampaleanu
@@ -184,7 +184,7 @@ public class LdapUserDetailsManager implements UserDetailsManager {
public Object executeWithContext(DirContext dirCtx) throws NamingException {
LdapContext ctx = (LdapContext) dirCtx;
ctx.removeFromEnvironment("com.sun.jndi.ldap.connect.pool");
ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, LdapUtils.getFullDn(dn, ctx).toUrl());
ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, LdapUtils.getFullDn(dn, ctx).toString());
ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, oldPassword);
// TODO: reconnect doesn't appear to actually change the credentials
try {
@@ -21,11 +21,17 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.security.firewall.DefaultHttpFirewall;
import org.springframework.security.firewall.FirewalledRequest;
import org.springframework.security.firewall.HttpFirewall;
import org.springframework.security.intercept.web.*;
import org.springframework.util.Assert;
import org.springframework.web.filter.DelegatingFilterProxy;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
@@ -34,7 +40,7 @@ import java.util.*;
* Delegates <code>Filter</code> requests to a list of Spring-managed beans.
* As of version 2.0, you shouldn't need to explicitly configure a <tt>FilterChainProxy</tt> bean in your application
* context unless you need very fine control over the filter chain contents. Most cases should be adequately covered
* by the default <tt>&lt;security:http /&gt</tt> namespace configuration options.
* by the default <tt>&lt;security:http /&gt;</tt> namespace configuration options.
*
* <p>The <code>FilterChainProxy</code> is loaded via a standard Spring {@link DelegatingFilterProxy} declaration in
* <code>web.xml</code>. <code>FilterChainProxy</code> will then pass {@link #init(FilterConfig)}, {@link #destroy()}
@@ -107,7 +113,9 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
/** Compiled pattern version of the filter chain map */
private Map filterChainMap;
private UrlMatcher matcher = new AntUrlPathMatcher();
private boolean stripQueryStringFromUrls = true;
private DefaultFilterInvocationDefinitionSource fids;
private HttpFirewall firewall = new DefaultHttpFirewall();
//~ Methods ========================================================================================================
@@ -116,8 +124,8 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
if (fids != null) {
Assert.isNull(uncompiledFilterChainMap, "Set the filterChainMap or FilterInvocationDefinitionSource but not both");
FIDSToFilterChainMapConverter converter = new FIDSToFilterChainMapConverter(fids, applicationContext);
setMatcher(converter.getMatcher());
setFilterChainMap(converter.getFilterChainMap());
setMatcher(converter.getMatcher());
setFilterChainMap(converter.getFilterChainMap());
fids = null;
}
@@ -153,10 +161,13 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
}
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
public void doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
FirewalledRequest fwRequest = firewall.getFirewalledRequest((HttpServletRequest) servletRequest);
HttpServletResponse fwResponse = firewall.getFirewalledResponse((HttpServletResponse) response);
FilterInvocation fi = new FilterInvocation(fwRequest, fwResponse, chain);
List filters = getFilters(fi.getRequestUrl());
if (filters == null || filters.size() == 0) {
@@ -165,7 +176,7 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
filters == null ? " has no matching filters" : " has an empty filter list");
}
chain.doFilter(request, response);
chain.doFilter(fwRequest, response);
return;
}
@@ -181,6 +192,16 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
* @return an ordered array of Filters defining the filter chain
*/
public List getFilters(String url) {
if (stripQueryStringFromUrls) {
// String query string - see SEC-953
int firstQuestionMarkIndex = url.indexOf("?");
if (firstQuestionMarkIndex != -1) {
url = url.substring(0, firstQuestionMarkIndex);
}
}
Iterator filterChains = filterChainMap.entrySet().iterator();
while (filterChains.hasNext()) {
@@ -319,6 +340,18 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
return matcher;
}
public void setFirewall(HttpFirewall firewall) {
this.firewall = firewall;
}
/**
* If set to 'true', the query string will be stripped from the request URL before
* attempting to find a matching filter chain. This is the default value.
*/
public void setStripQueryStringFromUrls(boolean stripQueryStringFromUrls) {
this.stripQueryStringFromUrls = stripQueryStringFromUrls;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("FilterChainProxy[");
@@ -355,6 +388,8 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
logger.debug(fi.getRequestUrl()
+ " reached end of additional filter chain; proceeding with original chain");
}
// Deactivate path stripping as we exit the security filter chain
resetWrapper(request);
fi.getChain().doFilter(request, response);
} else {
@@ -371,6 +406,16 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
nextFilter.doFilter(request, response, this);
}
}
private void resetWrapper(ServletRequest request) {
while (request instanceof ServletRequestWrapper) {
if (request instanceof FirewalledRequest) {
((FirewalledRequest)request).reset();
break;
}
request = ((ServletRequestWrapper)request).getRequest();
}
}
}
}
@@ -15,7 +15,7 @@ public class InMemoryXmlApplicationContext extends AbstractXmlApplicationContext
" xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n" +
" xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd\n" +
"http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd\n" +
"http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.2.xsd'>\n";
"http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.6.xsd'>\n";
private static final String BEANS_CLOSE = "</b:beans>\n";
Resource inMemoryXml;
@@ -2,18 +2,22 @@ package org.springframework.security.util;
/**
* Utilities for working with Strings and text.
*
*
* @author Luke Taylor
* @version $Id$
*/
public abstract class TextUtils {
public static String escapeEntities(String s) {
if (s == null || s.length() == 0) {
return s;
}
StringBuffer sb = new StringBuffer();
for (int i=0; i < s.length(); i++) {
char c = s.charAt(i);
if(c == '<') {
sb.append("&lt;");
} else if (c == '>') {
@@ -22,12 +26,14 @@ public abstract class TextUtils {
sb.append("&#034;");
} else if (c == '\'') {
sb.append("&#039;");
} else if (c == '&') {
sb.append("&amp;");
} else {
sb.append(c);
}
}
return sb.toString();
}
}
@@ -0,0 +1,29 @@
package org.springframework.security.vote;
import org.springframework.security.Authentication;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.userdetails.hierarchicalroles.RoleHierarchy;
import org.springframework.util.Assert;
/**
* Extended RoleVoter which uses a {@link RoleHierarchy} definition to determine the
* roles allocated to the current user before voting.
*
* @author Luke Taylor
* @since 2.0.4
*/
public class RoleHierarchyVoter extends RoleVoter {
private RoleHierarchy roleHierarchy = null;
public RoleHierarchyVoter(RoleHierarchy roleHierarchy) {
Assert.notNull(roleHierarchy, "RoleHierarchy must not be null");
this.roleHierarchy = roleHierarchy;
}
/**
* Calls the <tt>RoleHierarchy</tt> to obtain the complete set of user authorities.
*/
GrantedAuthority[] extractAuthorities(Authentication authentication) {
return roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
}
}
@@ -95,6 +95,7 @@ public class RoleVoter implements AccessDecisionVoter {
public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {
int result = ACCESS_ABSTAIN;
Iterator iter = config.getConfigAttributes().iterator();
GrantedAuthority[] authorities = extractAuthorities(authentication);
while (iter.hasNext()) {
ConfigAttribute attribute = (ConfigAttribute) iter.next();
@@ -102,7 +103,6 @@ public class RoleVoter implements AccessDecisionVoter {
if (this.supports(attribute)) {
result = ACCESS_DENIED;
GrantedAuthority[] authorities = authentication.getAuthorities();
// Attempt to find a matching granted authority
for (int i = 0; i < authorities.length; i++) {
if (attribute.getAttribute().equals(authorities[i].getAuthority())) {
@@ -114,4 +114,8 @@ public class RoleVoter implements AccessDecisionVoter {
return result;
}
GrantedAuthority[] extractAuthorities(Authentication authentication) {
return authentication.getAuthorities();
}
}
@@ -1,3 +1,6 @@
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-2.0.6.xsd
http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/springframework/security/config/spring-security-2.0.xsd
http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd
http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd
http\://www.springframework.org/schema/security/spring-security-2.0.4.xsd=org/springframework/security/config/spring-security-2.0.4.xsd
http\://www.springframework.org/schema/security/spring-security-2.0.6.xsd=org/springframework/security/config/spring-security-2.0.6.xsd
@@ -8,7 +8,7 @@ start = http | ldap-server | authentication-provider | ldap-authentication-provi
hash =
## Defines the hashing algorithm used on user passwords. We recommend strongly against using MD4, as it is a very weak hashing algorithm.
attribute hash {"plaintext" | "sha" | "sha-256" | "md5" | "md4" | "{sha}" | "{ssha}"}
base64 =
base64 =
## Whether a string should be base64 encoded
attribute base64 {"true" | "false"}
path-type =
@@ -20,9 +20,9 @@ port =
url =
## Specifies a URL.
attribute url { xsd:string }
id =
id =
## A bean identifier, used for referring to the bean elsewhere in the context.
attribute id {xsd:ID}
attribute id {xsd:ID}
ref =
## Defines a reference to a Spring bean Id.
attribute ref {xsd:string}
@@ -35,25 +35,26 @@ user-service-ref =
## A reference to a user-service (or UserDetailsService bean) Id
attribute user-service-ref {xsd:string}
data-source-ref =
data-source-ref =
## A reference to a DataSource bean
attribute data-source-ref {xsd:string}
password-encoder =
attribute data-source-ref {xsd:string}
password-encoder =
## element which defines a password encoding strategy. Used by an authentication provider to convert submitted passwords to hashed versions, for example.
element password-encoder {password-encoder.attlist, salt-source?}
element password-encoder {password-encoder.attlist, salt-source?}
password-encoder.attlist &=
ref | (hash? & base64?)
salt-source =
## Password salting strategy. A system-wide constant or a property from the UserDetails object can be used.
element salt-source {user-property | system-wide}
user-property =
## A property of the UserDetails object which will be used as salt by a password encoder. Typically something like "username" might be used.
## A property of the UserDetails object which will be used as salt by a password encoder. Typically something like "username" might be used.
attribute user-property {xsd:string}
system-wide =
## A single value that will be used as the salt for a password encoder.
## A single value that will be used as the salt for a password encoder.
attribute system-wide {xsd:string}
boolean = "true" | "false"
role-prefix =
@@ -62,16 +63,16 @@ role-prefix =
ldap-server =
## Defines an LDAP server location or starts an embedded server. The url indicates the location of a remote server. If no url is given, an embedded server will be started, listening on the supplied port number. The port is optional and defaults to 33389. A Spring LDAP ContextSource bean will be registered for the server with the id supplied.
## Defines an LDAP server location or starts an embedded server. The url indicates the location of a remote server. If no url is given, an embedded server will be started, listening on the supplied port number. The port is optional and defaults to 33389. A Spring LDAP ContextSource bean will be registered for the server with the id supplied.
element ldap-server {ldap-server.attlist}
ldap-server.attlist &= id?
ldap-server.attlist &= (url | port)?
ldap-server.attlist &=
## Username (DN) of the "manager" user identity which will be used to authenticate to a (non-embedded) LDAP server. If omitted, anonymous access will be used.
## Username (DN) of the "manager" user identity which will be used to authenticate to a (non-embedded) LDAP server. If omitted, anonymous access will be used.
attribute manager-dn {xsd:string}?
## The password for the manager DN.
ldap-server.attlist &=
attribute manager-password {xsd:string}?
## The password for the manager DN.
attribute manager-password {xsd:string}?
ldap-server.attlist &=
## Explicitly specifies an ldif file resource to load into an embedded LDAP server
attribute ldif { xsd:string }?
@@ -80,32 +81,33 @@ ldap-server.attlist &=
attribute root { xsd:string }?
ldap-server-ref-attribute =
## The optional server to use. If omitted, and a default LDAP server is registered (using <ldap-server> with no Id), that server will be used.
## The optional server to use. If omitted, and a default LDAP server is registered (using <ldap-server> with no Id), that server will be used.
attribute server-ref {xsd:string}
group-search-filter-attribute =
group-search-filter-attribute =
## Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user.
attribute group-search-filter {xsd:string}
group-search-base-attribute =
## Search base for group membership searches. Defaults to "ou=groups".
group-search-base-attribute =
## Search base for group membership searches. Defaults to "" (searching from the root).
attribute group-search-base {xsd:string}
user-search-filter-attribute =
## The LDAP filter used to search for users (optional). For example "(uid={0})". The substituted parameter is the user's login name.
attribute user-search-filter {xsd:string}
user-search-base-attribute =
## Search base for user searches. Defaults to "".
## Search base for user searches. Defaults to "". Only used with a 'user-search-filter'.
attribute user-search-base {xsd:string}
group-role-attribute-attribute =
## The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn".
attribute group-role-attribute {xsd:string}
user-details-class-attribute =
user-details-class-attribute =
## Allows the objectClass of the user entry to be specified. If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object
attribute user-details-class {"person" | "inetOrgPerson"}
ldap-user-service =
element ldap-user-service {ldap-us.attlist}
ldap-us.attlist &= id?
ldap-us.attlist &= id?
ldap-us.attlist &=
ldap-server-ref-attribute?
ldap-us.attlist &=
@@ -136,7 +138,7 @@ ldap-ap.attlist &=
user-search-filter-attribute?
ldap-ap.attlist &=
group-search-base-attribute?
ldap-ap.attlist &=
ldap-ap.attlist &=
group-search-filter-attribute?
ldap-ap.attlist &=
group-role-attribute-attribute?
@@ -151,7 +153,7 @@ ldap-ap.attlist &=
password-compare-element =
## Specifies that an LDAP provider should use an LDAP compare operation of the user's password to authenticate the user
element password-compare {password-compare.attlist, password-encoder?}
password-compare.attlist &=
## The attribute in the directory which contains the user password. Defaults to "userPassword".
attribute password-attribute {xsd:string}?
@@ -179,7 +181,7 @@ protect.attlist &=
global-method-security =
## Provides method security for all beans registered in the Spring application context. Specifically, beans will be scanned for Spring Security annotations and/or matches with the ordered list of "protect-pointcut" sub-elements. Where there is a match, the beans will automatically be proxied and security authorization applied to the methods accordingly. If you use and enable all three sources of method security metadata (ie "protect-pointcut" declarations, @Secured and also JSR 250 security annotations), the metadata sources will be queried in that order. In practical terms, this enables you to use XML to override method security metadata expressed by way of @Secured annotations, with @Secured annotations overriding method security metadata expressed by JSR 250 annotations. It is perfectly acceptable to mix and match, with a given Java type using a combination of XML, @Secured and JSR 250 to express method security metadata (albeit on different methods).
element global-method-security {global-method-security.attlist, protect-pointcut*}
element global-method-security {global-method-security.attlist, protect-pointcut*}
global-method-security.attlist &=
## Specifies whether the use of Spring Security's @Secured annotations should be enabled for this application context. Please ensure you have the spring-security-tiger-xxx.jar on the classpath. Defaults to "disabled".
attribute secured-annotations {"disabled" | "enabled" }?
@@ -191,6 +193,7 @@ global-method-security.attlist &=
attribute access-decision-manager-ref {xsd:string}?
custom-after-invocation-provider =
## Used to decorate an AfterInvocationProvider to specify that it should be used with method security.
element custom-after-invocation-provider {empty}
protect-pointcut =
@@ -203,6 +206,9 @@ protect-pointcut.attlist &=
## Access configuration attributes list that applies to all methods matching the pointcut, e.g. "ROLE_A,ROLE_B"
attribute access {xsd:string}
http-firewall =
## Allows a custom instance of HttpFirewall to be injected into the FilterChainProxy created by the namespace.
element http-firewall {ref}
http =
## Container element for HTTP security configuration
@@ -258,20 +264,20 @@ intercept-url.attlist &=
## The filter list for the path. Currently can be set to "none" to remove a path from having any filters applied. The full filter stack (consisting of all filters created by the namespace configuration, and any added using 'custom-filter'), will be applied to any other paths.
attribute filters {"none"}?
intercept-url.attlist &=
## Used to specify that a URL must be accessed over http or https
## Used to specify that a URL must be accessed over http or https, or that there is no preference.
attribute requires-channel {"http" | "https" | "any"}?
logout =
## Incorporates a logout processing filter. Most web applications require a logout filter, although you may not require one if you write a controller to provider similar logic.
## Incorporates a logout processing filter. Most web applications require a logout filter, although you may not require one if you write a controller to provider similar logic.
element logout {logout.attlist, empty}
logout.attlist &=
## Specifies the URL that will cause a logout. Spring Security will initialize a filter that responds to this particular URL. Defaults to /j_spring_security_logout if unspecified.
## Specifies the URL that will cause a logout. Spring Security will initialize a filter that responds to this particular URL. Defaults to /j_spring_security_logout if unspecified.
attribute logout-url {xsd:string}?
logout.attlist &=
## Specifies the URL to display once the user has logged out. If not specified, defaults to /.
## Specifies the URL to display once the user has logged out. If not specified, defaults to /.
attribute logout-success-url {xsd:string}?
logout.attlist &=
## Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true.
## Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true.
attribute invalidate-session {boolean}?
form-login =
@@ -284,8 +290,8 @@ form-login.attlist &=
## The URL that will be redirected to after successful authentication, if the user's previous action could not be resumed. This generally happens if the user visits a login page without having first requested a secured operation that triggers authentication. If unspecified, defaults to the root of the application.
attribute default-target-url {xsd:string}?
form-login.attlist &=
## Whether the user should always be redirected to the default-target-url after login.
attribute always-use-default-target {boolean}?
## Whether the user should always be redirected to the default-target-url after login.
attribute always-use-default-target {boolean}?
form-login.attlist &=
## The URL for the login page. If no login URL is specified, Spring Security will automatically create a login URL at /spring_security_login and a corresponding filter to render that login URL when requested.
attribute login-page {xsd:string}?
@@ -293,7 +299,7 @@ form-login.attlist &=
## The URL for the login failure page. If no login failure URL is specified, Spring Security will automatically create a failure login URL at /spring_security_login?login_error and a corresponding filter to render that login failure URL when requested.
attribute authentication-failure-url {xsd:string}?
openid-login =
openid-login =
## Sets up form login for authentication with an Open ID identity
element openid-login {form-login.attlist, user-service-ref?, empty}
@@ -313,7 +319,7 @@ filter-chain.attlist &=
attribute filters {xsd:string}
filter-invocation-definition-source =
## Used to explicitly configure a FilterInvocationDefinitionSource bean for use with a FilterSecurityInterceptor. Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the <http> element. The intercept-url elements used should only contain pattern, method and access attributes. Any others will result in a configuration error.
## Used to explicitly configure a FilterInvocationDefinitionSource bean for use with a FilterSecurityInterceptor. Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the <http> element. The intercept-url elements used should only contain pattern, method and access attributes. Any others will result in a configuration error.
element filter-invocation-definition-source {fids.attlist, intercept-url+}
fids.attlist &=
id?
@@ -333,45 +339,46 @@ concurrent-session-control =
## Adds support for concurrent session control, allowing limits to be placed on the number of sessions a user can have.
element concurrent-session-control {concurrent-sessions.attlist, empty}
concurrent-sessions.attlist &=
## The maximum number of sessions a single user can have open at the same time. Defaults to "1".
attribute max-sessions {xsd:positiveInteger}?
concurrent-sessions.attlist &=
## The URL a user will be redirected to if they attempt to use a session which has been "expired" by the concurrent session controller.
## The URL a user will be redirected to if they attempt to use a session which has been "expired" by the concurrent session controller because they have logged in again.
attribute expired-url {xsd:string}?
concurrent-sessions.attlist &=
## Specifies that an exception should be raised when a user attempts to login twice. The default behaviour is to expire the original session.
## Specifies that an exception should be raised when a user attempts to login when they already have the maximum configured sessions open. The default behaviour is to expire the original session.
attribute exception-if-maximum-exceeded {boolean}?
concurrent-sessions.attlist &=
## Allows you to define an alias for the SessionRegistry bean in order to access it in your own configuration
attribute session-registry-alias {xsd:string}?
concurrent-sessions.attlist &=
## A reference to an external SessionRegistry implementation which will be used in place of the standard one.
## A reference to an external SessionRegistry implementation which will be used in place of the standard one.
attribute session-registry-ref {xsd:string}?
remember-me =
## Sets up remember-me authentication. If used with the "key" attribute (or no attributes) the cookie-only implementation will be used. Specifying "token-repository-ref" or "remember-me-data-source-ref" will use the more secure, persisten token approach.
## Sets up remember-me authentication. If used with the "key" attribute (or no attributes) the cookie-only implementation will be used. Specifying "token-repository-ref" or "remember-me-data-source-ref" will use the more secure, persisten token approach.
element remember-me {remember-me.attlist}
remember-me.attlist &=
## The "key" used to identify cookies from a specific token-based remember-me application. You should set this to a unique value for your application.
attribute key {xsd:string}?
remember-me.attlist &=
(token-repository-ref | remember-me-data-source-ref | remember-me-services-ref)
remember-me.attlist &=
user-service-ref?
remember-me.attlist &=
## The period (in seconds) for which the remember-me cookie should be valid.
## The period (in seconds) for which the remember-me cookie should be valid.
attribute token-validity-seconds {xsd:positiveInteger}?
token-repository-ref =
## Reference to a PersistentTokenRepository bean for use with the persistent token remember-me implementation.
## Reference to a PersistentTokenRepository bean for use with the persistent token remember-me implementation.
attribute token-repository-ref {xsd:string}
remember-me-services-ref =
## Allows a custom implementation of RememberMeServices to be used. Note that this implementation should return RememberMeAuthenticationToken instances with the same "key" value as specified in the remember-me element. Alternatively it should register its own AuthenticationProvider.
remember-me-services-ref =
## Allows a custom implementation of RememberMeServices to be used. Note that this implementation should return RememberMeAuthenticationToken instances with the same "key" value as specified in the remember-me element. Alternatively it should register its own AuthenticationProvider.
attribute services-ref {xsd:string}?
remember-me-data-source-ref =
## DataSource bean for the database that contains the token
## DataSource bean for the database that contains the token repository schema.
data-source-ref
anonymous =
@@ -380,39 +387,39 @@ anonymous =
anonymous.attlist &=
## The key shared between the provider and filter. This generally does not need to be set. If unset, it will default to "doesNotMatter".
attribute key {xsd:string}?
anonymous.attlist &=
anonymous.attlist &=
## The username that should be assigned to the anonymous request. This allows the principal to be identified, which may be important for logging and auditing. if unset, defaults to "anonymousUser".
attribute username {xsd:string}?
anonymous.attlist &=
## The granted authority that should be assigned to the anonymous request. Commonly this is used to assign the anonymous request particular roles, which can subsequently be used in authorization decisions. If unset, defaults to "ROLE_ANONYMOUS".
attribute granted-authority {xsd:string}?
port-mappings =
port-mappings =
## Defines the list of mappings between http and https ports for use in redirects
element port-mappings {port-mappings.attlist, port-mapping+}
port-mappings.attlist &= empty
port-mapping =
port-mapping =
element port-mapping {http-port, https-port}
http-port = attribute http {xsd:integer}
https-port = attribute https {xsd:integer}
http-port = attribute http {xsd:string}
https-port = attribute https {xsd:string}
x509 =
x509 =
## Adds support for X.509 client authentication.
element x509 {x509.attlist}
x509.attlist &=
x509.attlist &=
## The regular expression used to obtain the username from the certificate's subject. Defaults to matching on the common name using the pattern "CN=(.*?),".
attribute subject-principal-regex {xsd:string}?
x509.attlist &=
## Explicitly specifies which user-service should be used to load user data for X.509 authenticated clients. If ommitted, the default user-service will be used.
## Explicitly specifies which user-service should be used to load user data for X.509 authenticated clients. If ommitted, the default user-service will be used.
user-service-ref?
authentication-manager =
## If you are using namespace configuration with Spring Security, an AuthenticationManager will automatically be registered. This element allows you to define an alias to allow you to reference the authentication-manager in your own beans.
## If you are using namespace configuration with Spring Security, an AuthenticationManager will automatically be registered. This element allows you to define an alias to allow you to reference the authentication-manager in your own beans.
element authentication-manager {authman.attlist}
authman.attlist &=
## The alias you wish to use for the AuthenticationManager bean
@@ -423,13 +430,14 @@ authman.attlist &=
authentication-provider =
## Indicates that the contained user-service should be used as an authentication source.
## Indicates that the contained user-service should be used as an authentication source.
element authentication-provider {ap.attlist & any-user-service & password-encoder?}
ap.attlist &=
## Specifies a reference to a separately configured UserDetailsService from which to obtain authentication data.
## Specifies a reference to a separately configured UserDetailsService from which to obtain authentication data.
user-service-ref?
custom-authentication-provider =
## Element used to decorate an AuthenticationProvider bean to add it to the internal AuthenticationManager maintained by the namespace.
element custom-authentication-provider {cap.attlist}
cap.attlist &= empty
@@ -438,31 +446,31 @@ user-service =
element user-service {id? & (properties-file | (user*))}
properties-file =
attribute properties {xsd:string}?
user =
## Represents a user in the application.
## Represents a user in the application.
element user {user.attlist, empty}
user.attlist &=
## The username assigned to the user.
## The username assigned to the user.
attribute name {xsd:string}
user.attlist &=
## The password assigned to the user. This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element).
## The password assigned to the user. This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element).
attribute password {xsd:string}
user.attlist &=
## One of more authorities granted to the user. Separate authorities with a comma (but no space). For example, "ROLE_USER,ROLE_ADMINISTRATOR"
## One of more authorities granted to the user. Separate authorities with a comma (but no space). For example, "ROLE_USER,ROLE_ADMINISTRATOR"
attribute authorities {xsd:string}
user.attlist &=
## Can be set to "true" to mark an account as locked and unusable.
## Can be set to "true" to mark an account as locked and unusable.
attribute locked {boolean}?
user.attlist &=
## Can be set to "true" to mark an account as disabled and unusable.
## Can be set to "true" to mark an account as disabled and unusable.
attribute disabled {boolean}?
jdbc-user-service =
## Causes creation of a JDBC-based UserDetailsService.
element jdbc-user-service {id? & jdbc-user-service.attlist}
## Causes creation of a JDBC-based UserDetailsService.
element jdbc-user-service {id? & jdbc-user-service.attlist}
jdbc-user-service.attlist &=
## The bean ID of the DataSource which provides the required tables.
## The bean ID of the DataSource which provides the required tables.
attribute data-source-ref {xsd:string}
jdbc-user-service.attlist &=
cache-ref?
@@ -477,15 +485,15 @@ jdbc-user-service.attlist &=
attribute group-authorities-by-username-query {xsd:string}?
jdbc-user-service.attlist &=
role-prefix?
any-user-service = user-service | jdbc-user-service | ldap-user-service
custom-filter =
## Used to indicate that a filter bean declaration should be incorporated into the security filter chain. If neither the 'after' or 'before' options are supplied, then the filter must implement the Ordered interface directly.
## Used to indicate that a filter bean declaration should be incorporated into the security filter chain. If neither the 'after' or 'before' options are supplied, then the filter must implement the Ordered interface directly.
element custom-filter {after | before | position}?
after =
## The filter immediately after which the custom-filter should be placed in the chain. This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. The filter names map to specific Spring Security implementation filters.
## The filter immediately after which the custom-filter should be placed in the chain. This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. The filter names map to specific Spring Security implementation filters.
attribute after {named-security-filter}
before =
## The filter immediately before which the custom-filter should be placed in the chain
@@ -496,6 +504,4 @@ position =
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "CONCURRENT_SESSION_FILTER" | "SESSION_CONTEXT_INTEGRATION_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_PROCESSING_FILTER" | "AUTHENTICATION_PROCESSING_FILTER" | "BASIC_PROCESSING_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "NTLM_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "CONCURRENT_SESSION_FILTER" | "SESSION_CONTEXT_INTEGRATION_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_PROCESSING_FILTER" | "AUTHENTICATION_PROCESSING_FILTER" | "OPENID_PROCESSING_FILTER" |"BASIC_PROCESSING_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "NTLM_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
@@ -222,7 +222,7 @@
<xs:attribute name="group-search-base" use="required" type="xs:string">
<xs:annotation>
<xs:documentation>Search base for group membership searches. Defaults to
"ou=groups".</xs:documentation>
"" (searching from the root).</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
@@ -0,0 +1,53 @@
AuthByAdapterProvider.incorrectKey=La actual implementación de AuthByAdapter no contiene la clave esperada
BasicAclEntryAfterInvocationProvider.noPermission=Authentication {0} NO tiene permisos para el objeto de dominio {1}
BasicAclEntryAfterInvocationProvider.insufficientPermission=Authentication {0} tiene permisos ACL para objeto de dominio, pero no los permisos ACL requeridos para el objeto de dominio {1}
ConcurrentSessionControllerImpl.exceededAllowed=Sesiones máximas de {0} para esta Identificación excedidas
ProviderManager.providerNotFound=AuthenticationProvider no encontrado para {0}
AnonymousAuthenticationProvider.incorrectKey=El actual AnonymousAuthenticationToken no contiene la clave esperada
CasAuthenticationProvider.incorrectKey=El actual CasAuthenticationToken no contiene la clave esperada
CasAuthenticationProvider.noServiceTicket=No se ha podido proporcionar un billete de servicio CAS para validar
NamedCasProxyDecider.untrusted=El proxy más cercano {0} no es confiable
RejectProxyTickets.reject=Las entradas del proxy han sido rechazadas
AbstractSecurityInterceptor.authenticationNotFound=El objeto Authentication no ha sido encontrado en el SecurityContext
AbstractUserDetailsAuthenticationProvider.onlySupports=Sólo UsernamePasswordAuthenticationToken es soportada
AbstractUserDetailsAuthenticationProvider.locked=La cuenta del usuario está bloqueada
AbstractUserDetailsAuthenticationProvider.disabled=El usuario está deshabilitado
AbstractUserDetailsAuthenticationProvider.expired=La cuenta del usuario ha expirado
AbstractUserDetailsAuthenticationProvider.credentialsExpired=Las credenciales del usuario han expirado
AbstractUserDetailsAuthenticationProvider.badCredentials=Credenciales erróneas
X509AuthenticationProvider.certificateNull=Cerfificado nulo
DaoX509AuthoritiesPopulator.noMatching=No se ha encontrado un patrón coincidente en subjectDN: {0}
RememberMeAuthenticationProvider.incorrectKey=El actual RememberMeAuthenticationToken no contiene la clave esperada
RunAsImplAuthenticationProvider.incorrectKey=El actual RunAsUserToken no contiene la clave esperada
DigestProcessingFilter.missingMandatory=Valor digest obligatorio perdido; header recibido {0}
DigestProcessingFilter.missingAuth=Valor digest obligatorio perdido para 'auth' QOP; header recibido {0}
DigestProcessingFilter.incorrectRealm=Respuesta realm de nombre {0} no coincide con realm del sistema de nombre {1}
DigestProcessingFilter.nonceExpired=Nonce ha expirado/fuera de tiempo
DigestProcessingFilter.nonceEncoding=Nonce no está codificado en Base64; nonce recibido {0}
DigestProcessingFilter.nonceNotTwoTokens=Nonce token debería tener dos fichas pero tenía {0}
DigestProcessingFilter.nonceNotNumeric=Nonce token debería tener primero un token numérico, pero tenía {0}
DigestProcessingFilter.nonceCompromised=Nonce token comprometido {0}
DigestProcessingFilter.usernameNotFound=Usuario y nombre {0} no encontrado
DigestProcessingFilter.incorrectResponse=Respuesta incorrecta
JdbcDaoImpl.notFound=Usuario {0} no encontrado
JdbcDaoImpl.noAuthority=Usuario {0} no tiene GrantedAuthority
SwitchUserProcessingFilter.noCurrentUser=No hay usuario actual asociado con esta petición
SwitchUserProcessingFilter.noOriginalAuthentication=No se puede encontrar el objeto Authentication original
SwitchUserProcessingFilter.usernameNotFound=Usuario y nombre {0} no encontrado
SwitchUserProcessingFilter.locked=La cuenta del usuario está bloqueada
SwitchUserProcessingFilter.disabled=El usuario está deshabilitado
SwitchUserProcessingFilter.expired=La cuenta del usuario ha expirado
SwitchUserProcessingFilter.credentialsExpired=Las credenciales del usuario han expirado
AbstractAccessDecisionManager.accessDenied=Acceso denegado
LdapAuthenticationProvider.emptyUsername=Usuario y nombre no permitido
LdapAuthenticationProvider.emptyPassword=Credenciales erróneas
DefaultIntitalDirContextFactory.communicationFailure=No se puede conectar con el servidor LDAP
DefaultIntitalDirContextFactory.badCredentials=Credenciales erróneas
DefaultIntitalDirContextFactory.unexpectedException=Error al obtener el InitialDirContext debido a una excepción inesperada
PasswordComparisonAuthenticator.badCredentials=Credenciales erróneas
BindAuthenticator.badCredentials=Credenciales erróneas
BindAuthenticator.failedToLoadAttributes=Credenciales erróneas
UserDetailsService.locked=La cuenta del usuario está bloqueada
UserDetailsService.disabled=El usuario está deshabilitado
UserDetailsService.expired=La cuenta del usuario ha expirado
UserDetailsService.credentialsExpired=Las credenciales del usuario han expirado
@@ -6,12 +6,12 @@ ProviderManager.providerNotFound=\u672a\u67e5\u627e\u5230\u9488\u5bf9{0}\u7684Au
AnonymousAuthenticationProvider.incorrectKey=\u5c55\u793a\u7684AnonymousAuthenticationToken\u4e0d\u542b\u6709\u9884\u671f\u7684key
CasAuthenticationProvider.incorrectKey=\u5c55\u793a\u7684CasAuthenticationToken\u4e0d\u542b\u6709\u9884\u671f\u7684key
CasAuthenticationProvider.noServiceTicket=\u672a\u80fd\u591f\u6b63\u786e\u63d0\u4f9b\u5f85\u9a8c\u8bc1\u7684CAS\u670d\u52a1\u7968\u6839
NamedCasProxyDecider.untrusted=\u4ee3\u7406({0}) \u4e0d\u53d7\u4fe1\u4efb
NamedCasProxyDecider.untrusted=\u4ee3\u7406({0})\u4e0d\u53d7\u4fe1\u4efb
RejectProxyTickets.reject=Proxy\u7968\u6839\u88ab\u62d2\u7edd
AbstractSecurityInterceptor.authenticationNotFound=\u672a\u5728SecurityContext\u4e2d\u67e5\u627e\u5230\u8ba4\u8bc1\u5bf9\u8c61
AbstractUserDetailsAuthenticationProvider.onlySupports=\u4ec5\u4ec5\u652f\u6301UsernamePasswordAuthenticationToken
AbstractUserDetailsAuthenticationProvider.locked=\u7528\u6237\u5e10\u53f7\u5df2\u88ab\u9501\u5b9a
AbstractUserDetailsAuthenticationProvider.disabled=\u7528\u6237\u5df2\u88ab\u5931\u6548
AbstractUserDetailsAuthenticationProvider.disabled=\u7528\u6237\u5df2\u5931\u6548
AbstractUserDetailsAuthenticationProvider.expired=\u7528\u6237\u5e10\u53f7\u5df2\u8fc7\u671f
AbstractUserDetailsAuthenticationProvider.credentialsExpired=\u7528\u6237\u51ed\u8bc1\u5df2\u8fc7\u671f
AbstractUserDetailsAuthenticationProvider.badCredentials=\u574f\u7684\u51ed\u8bc1
@@ -29,11 +29,13 @@ DigestProcessingFilter.nonceNotNumeric=Nonce\u4ee4\u724c\u7684\u7b2c1\u90e8\u520
DigestProcessingFilter.nonceCompromised=Nonce\u4ee4\u724c\u5df2\u7ecf\u5b58\u5728\u95ee\u9898\u4e86\uff0c{0}
DigestProcessingFilter.usernameNotFound=\u7528\u6237\u540d{0}\u672a\u627e\u5230
DigestProcessingFilter.incorrectResponse=\u9519\u8bef\u7684\u54cd\u5e94\u7ed3\u679c
JdbcDaoImpl.notFound=\u672a\u627e\u5230\u7528\u6237{0}
JdbcDaoImpl.noAuthority=\u6ca1\u6709\u4e3a\u7528\u6237{0}\u6307\u5b9a\u89d2\u8272
SwitchUserProcessingFilter.noCurrentUser=\u4e0d\u5b58\u5728\u5f53\u524d\u7528\u6237
SwitchUserProcessingFilter.noOriginalAuthentication=\u4e0d\u80fd\u591f\u67e5\u627e\u5230\u539f\u5148\u7684\u5df2\u8ba4\u8bc1\u5bf9\u8c61
SwitchUserProcessingFilter.usernameNotFound=\u7528\u6237\u540d{0}\u672a\u627e\u5230
SwitchUserProcessingFilter.locked=\u7528\u6237\u5e10\u53f7\u5df2\u88ab\u9501\u5b9a
SwitchUserProcessingFilter.disabled=\u7528\u6237\u5df2\u88ab\u5931\u6548
SwitchUserProcessingFilter.disabled=\u7528\u6237\u5df2\u5931\u6548
SwitchUserProcessingFilter.expired=\u7528\u6237\u5e10\u53f7\u5df2\u8fc7\u671f
SwitchUserProcessingFilter.credentialsExpired=\u7528\u6237\u51ed\u8bc1\u5df2\u8fc7\u671f
AbstractAccessDecisionManager.accessDenied=\u4e0d\u5141\u8bb8\u8bbf\u95ee
@@ -45,4 +47,8 @@ DefaultIntitalDirContextFactory.unexpectedException=\u7531\u4e8e\u672a\u9884\u67
PasswordComparisonAuthenticator.badCredentials=\u574f\u7684\u51ed\u8bc1
BindAuthenticator.badCredentials=\u574f\u7684\u51ed\u8bc1
BindAuthenticator.failedToLoadAttributes=\u574f\u7684\u51ed\u8bc1
UserDetailsService.locked=\u7528\u6237\u5e10\u53f7\u5df2\u88ab\u9501\u5b9a
UserDetailsService.disabled=\u7528\u6237\u5df2\u5931\u6548
UserDetailsService.expired=\u7528\u6237\u5e10\u53f7\u5df2\u8fc7\u671f
UserDetailsService.credentialsExpired=\u7528\u6237\u51ed\u8bc1\u5df2\u8fc7\u671f
@@ -15,7 +15,9 @@
package org.springframework.security;
import junit.framework.TestCase;
import static org.junit.Assert.*;
import org.junit.Test;
/**
@@ -24,28 +26,10 @@ import junit.framework.TestCase;
* @author Ben Alex
* @version $Id$
*/
public class GrantedAuthorityImplTests extends TestCase {
//~ Constructors ===================================================================================================
public GrantedAuthorityImplTests() {
super();
}
public GrantedAuthorityImplTests(String arg0) {
super(arg0);
}
//~ Methods ========================================================================================================
public static void main(String[] args) {
junit.textui.TestRunner.run(GrantedAuthorityImplTests.class);
}
public final void setUp() throws Exception {
super.setUp();
}
public void testObjectEquals() throws Exception {
public class GrantedAuthorityImplTests {
@Test
public void equalsBehavesAsExpected() throws Exception {
GrantedAuthorityImpl auth1 = new GrantedAuthorityImpl("TEST");
GrantedAuthorityImpl auth2 = new GrantedAuthorityImpl("TEST");
assertEquals(auth1, auth2);
@@ -59,32 +43,52 @@ public class GrantedAuthorityImplTests extends TestCase {
GrantedAuthorityImpl auth3 = new GrantedAuthorityImpl("NOT_EQUAL");
assertTrue(!auth1.equals(auth3));
MockGrantedAuthorityImpl mock1 = new MockGrantedAuthorityImpl("TEST");
MockGrantedAuthority mock1 = new MockGrantedAuthority("TEST");
assertEquals(auth1, mock1);
MockGrantedAuthorityImpl mock2 = new MockGrantedAuthorityImpl("NOT_EQUAL");
MockGrantedAuthority mock2 = new MockGrantedAuthority("NOT_EQUAL");
assertTrue(!auth1.equals(mock2));
Integer int1 = new Integer(222);
assertTrue(!auth1.equals(int1));
}
public void testToString() {
@Test
public void toStringReturnsAuthorityValue() {
GrantedAuthorityImpl auth = new GrantedAuthorityImpl("TEST");
assertEquals("TEST", auth.toString());
}
@Test
public void compareToGrantedAuthorityWithSameValueReturns0() {
assertEquals(0, new GrantedAuthorityImpl("TEST").compareTo(new MockGrantedAuthority("TEST")));
}
@Test
public void compareToNullReturnsNegativeOne() {
assertEquals(-1, new GrantedAuthorityImpl("TEST").compareTo(null));
}
/* SEC-899 */
@Test
public void compareToHandlesCustomAuthorityWhichReturnsNullFromGetAuthority() {
assertEquals(-1, new GrantedAuthorityImpl("TEST").compareTo(new MockGrantedAuthority()));
}
//~ Inner Classes ==================================================================================================
private class MockGrantedAuthorityImpl implements GrantedAuthority, Comparable {
private class MockGrantedAuthority implements GrantedAuthority {
private String role;
public MockGrantedAuthorityImpl(String role) {
public MockGrantedAuthority() {
}
public MockGrantedAuthority(String role) {
this.role = role;
}
public int compareTo(Object o) {
return this.role.compareTo(((GrantedAuthority)o).getAuthority());
throw new UnsupportedOperationException();
}
public String getAuthority() {
@@ -0,0 +1,232 @@
package org.springframework.security.authoritymapping;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import junit.framework.TestCase;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
/**
*
* @author Ruud Senden
*/
public class MapBasedAttributes2GrantedAuthoritiesMapperTest extends TestCase {
protected void setUp() throws Exception {
// Set Log4j loglevel to debug to include all logstatements in tests
Logger.getRootLogger().setLevel(Level.DEBUG);
}
public final void testAfterPropertiesSetNoMap() {
MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper();
try {
mapper.afterPropertiesSet();
fail("Expected exception not thrown");
} catch (IllegalArgumentException expected) {
// Expected exception
} catch (Exception unexpected) {
fail("Unexpected exception: " + unexpected);
}
}
public final void testAfterPropertiesSetEmptyMap() {
MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper();
mapper.setAttributes2grantedAuthoritiesMap(new HashMap());
try {
mapper.afterPropertiesSet();
fail("Expected exception not thrown");
} catch (IllegalArgumentException expected) {
// Expected exception
} catch (Exception unexpected) {
fail("Unexpected exception: " + unexpected);
}
}
public final void testAfterPropertiesSetInvalidKeyTypeMap() {
MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper();
HashMap m = new HashMap();
m.put(new Object(),"ga1");
mapper.setAttributes2grantedAuthoritiesMap(m);
try {
mapper.afterPropertiesSet();
fail("Expected exception not thrown");
} catch (IllegalArgumentException expected) {
// Expected exception
} catch (Exception unexpected) {
fail("Unexpected exception: " + unexpected);
}
}
public final void testAfterPropertiesSetInvalidValueTypeMap1() {
MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper();
HashMap m = new HashMap();
m.put("role1",new Object());
mapper.setAttributes2grantedAuthoritiesMap(m);
try {
mapper.afterPropertiesSet();
fail("Expected exception not thrown");
} catch (IllegalArgumentException expected) {
// Expected exception
} catch (Exception unexpected) {
fail("Unexpected exception: " + unexpected);
}
}
public final void testAfterPropertiesSetInvalidValueTypeMap2() {
MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper();
HashMap m = new HashMap();
m.put("role1",new Object[]{new String[]{"ga1","ga2"}, new Object()});
mapper.setAttributes2grantedAuthoritiesMap(m);
try {
mapper.afterPropertiesSet();
fail("Expected exception not thrown");
} catch (IllegalArgumentException expected) {
// Expected exception
} catch (Exception unexpected) {
fail("Unexpected exception: " + unexpected);
}
}
public final void testAfterPropertiesSetValidMap() {
MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper();
HashMap m = getValidAttributes2GrantedAuthoritiesMap();
mapper.setAttributes2grantedAuthoritiesMap(m);
try {
mapper.afterPropertiesSet();
} catch (Exception unexpected) {
fail("Unexpected exception: " + unexpected);
}
}
public final void testMapping1() {
String[] roles = { "role1" };
String[] expectedGas = { "ga1" };
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
testGetGrantedAuthorities(mapper, roles, expectedGas);
}
public final void testMapping2() {
String[] roles = { "role2" };
String[] expectedGas = { "ga2" };
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
testGetGrantedAuthorities(mapper, roles, expectedGas);
}
public final void testMapping3() {
String[] roles = { "role3" };
String[] expectedGas = { "ga3", "ga4" };
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
testGetGrantedAuthorities(mapper, roles, expectedGas);
}
public final void testMapping4() {
String[] roles = { "role4" };
String[] expectedGas = { "ga5", "ga6" };
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
testGetGrantedAuthorities(mapper, roles, expectedGas);
}
public final void testMapping5() {
String[] roles = { "role5" };
String[] expectedGas = { "ga7", "ga8", "ga9" };
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
testGetGrantedAuthorities(mapper, roles, expectedGas);
}
public final void testMapping6() {
String[] roles = { "role6" };
String[] expectedGas = { "ga10", "ga11", "ga12" };
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
testGetGrantedAuthorities(mapper, roles, expectedGas);
}
public final void testMapping7() {
String[] roles = { "role7" };
String[] expectedGas = { "ga13", "ga14" };
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
testGetGrantedAuthorities(mapper, roles, expectedGas);
}
public final void testMapping8() {
String[] roles = { "role8" };
String[] expectedGas = { "ga13", "ga14" };
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
testGetGrantedAuthorities(mapper, roles, expectedGas);
}
public final void testMapping9() {
String[] roles = { "role9" };
String[] expectedGas = {};
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
testGetGrantedAuthorities(mapper, roles, expectedGas);
}
public final void testMapping10() {
String[] roles = { "role10" };
String[] expectedGas = {};
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
testGetGrantedAuthorities(mapper, roles, expectedGas);
}
public final void testMapping11() {
String[] roles = { "role11" };
String[] expectedGas = {};
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
testGetGrantedAuthorities(mapper, roles, expectedGas);
}
public final void testNonExistingMapping() {
String[] roles = { "nonExisting" };
String[] expectedGas = {};
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
testGetGrantedAuthorities(mapper, roles, expectedGas);
}
public final void testMappingCombination() {
String[] roles = { "role1", "role2", "role3", "role4", "role5", "role6", "role7", "role8", "role9", "role10", "role11" };
String[] expectedGas = { "ga1", "ga2", "ga3", "ga4", "ga5", "ga6", "ga7", "ga8", "ga9", "ga10", "ga11", "ga12", "ga13", "ga14"};
Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper();
testGetGrantedAuthorities(mapper, roles, expectedGas);
}
private HashMap getValidAttributes2GrantedAuthoritiesMap() {
HashMap m = new HashMap();
m.put("role1","ga1");
m.put("role2",new GrantedAuthorityImpl("ga2"));
m.put("role3",Arrays.asList(new Object[]{"ga3",new GrantedAuthorityImpl("ga4")}));
m.put("role4","ga5,ga6");
m.put("role5",Arrays.asList(new Object[]{"ga7","ga8",new Object[]{new GrantedAuthorityImpl("ga9")}}));
m.put("role6",new Object[]{"ga10","ga11",new Object[]{new GrantedAuthorityImpl("ga12")}});
m.put("role7",new String[]{"ga13","ga14"});
m.put("role8",new String[]{"ga13","ga14",null});
m.put("role9",null);
m.put("role10",new Object[]{});
m.put("role11",Arrays.asList(new Object[]{null}));
return m;
}
private MapBasedAttributes2GrantedAuthoritiesMapper getDefaultMapper() {
MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper();
mapper.setAttributes2grantedAuthoritiesMap(getValidAttributes2GrantedAuthoritiesMap());
mapper.afterPropertiesSet();
return mapper;
}
private void testGetGrantedAuthorities(Attributes2GrantedAuthoritiesMapper mapper, String[] roles, String[] expectedGas) {
GrantedAuthority[] result = mapper.getGrantedAuthorities(roles);
Collection resultColl = new ArrayList(result.length);
for (int i = 0; i < result.length; i++) {
resultColl.add(result[i].getAuthority());
}
Collection expectedColl = Arrays.asList(expectedGas);
assertTrue("Role collections do not match; result: " + resultColl + ", expected: " + expectedColl, expectedColl
.containsAll(resultColl)
&& resultColl.containsAll(expectedColl));
}
}
@@ -0,0 +1,13 @@
package org.springframework.security.config;
public abstract class ConfigTestUtils {
public static final String AUTH_PROVIDER_XML =
" <authentication-provider>" +
" <user-service id='us'>" +
" <user name='bob' password='bobspassword' authorities='ROLE_A,ROLE_B' />" +
" <user name='bill' password='billspassword' authorities='ROLE_A,ROLE_B,AUTH_OTHER' />" +
" <user name='admin' password='password' authorities='ROLE_ADMIN,ROLE_USER' />" +
" <user name='user' password='password' authorities='ROLE_USER' />" +
" </user-service>" +
" </authentication-provider>";
}
@@ -11,7 +11,7 @@ import org.springframework.security.util.InMemoryXmlApplicationContext;
public class CustomAfterInvocationProviderBeanDefinitionDecoratorTests {
private AbstractXmlApplicationContext appContext;
@After
public void closeAppContext() {
if (appContext != null) {
@@ -19,7 +19,7 @@ public class CustomAfterInvocationProviderBeanDefinitionDecoratorTests {
appContext = null;
}
}
@Test
public void customAfterInvocationProviderIsAddedToInterceptor() {
setContext(
@@ -27,11 +27,11 @@ public class CustomAfterInvocationProviderBeanDefinitionDecoratorTests {
"<b:bean id='aip' class='org.springframework.security.config.MockAfterInvocationProvider'>" +
" <custom-after-invocation-provider />" +
"</b:bean>" +
HttpSecurityBeanDefinitionParserTests.AUTH_PROVIDER_XML
ConfigTestUtils.AUTH_PROVIDER_XML
);
MethodSecurityInterceptor msi = (MethodSecurityInterceptor) appContext.getBean(BeanIds.METHOD_SECURITY_INTERCEPTOR);
AfterInvocationProviderManager apm = (AfterInvocationProviderManager) msi.getAfterInvocationManager();
AfterInvocationProviderManager apm = (AfterInvocationProviderManager) msi.getAfterInvocationManager();
assertNotNull(apm);
assertEquals(1, apm.getProviders().size());
assertTrue(apm.getProviders().get(0) instanceof MockAfterInvocationProvider);

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