1
0
mirror of synced 2026-07-08 20:30:04 +00:00

Compare commits

...

156 Commits

Author SHA1 Message Date
Luke Taylor 37fb78baf8 Added appendices to end of doc. Corrected minor typo. 2008-10-02 14:52:28 +00:00
Luke Taylor 2ed9723b9a [maven-release-plugin] copy for tag spring-security-parent-2.0.4 2008-09-05 19:02:17 +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
Luke Taylor 2fa991c44f Some reorganization of itest module 2008-06-22 21:42:25 +00:00
Luke Taylor 3ee8733261 SEC-879: Added required BeanPostProcessor to set SessionRegistry is set on namespace registered AbstractProcessingFilter and SessionFixationProtectionFilter when using custom ConcurrentSessionController
http://jira.springframework.org/browse/SEC-879.
2008-06-20 22:08:05 +00:00
Luke Taylor d5ee89bb7c Correct typo in error message. 2008-06-19 15:21:03 +00:00
Luke Taylor ff5bfccdba SEC-892: Linked use of create-session='never' in namespace to corresponding properties in ExceptionTranslationFilter and AbstractProcessingFilter 2008-06-19 13:46:45 +00:00
Scott Battaglia 5b089aea16 SEC-852
provided mechanism to do get a proxy ticket
2008-06-18 17:34:14 +00:00
Scott Battaglia d7f194df78 SEC-886
upgraded to the most recent CAS Client for Java (3.1.3)
2008-06-18 17:22:20 +00:00
Luke Taylor c56d524bd9 SEC-887: Added setter method for account status checker. 2008-06-18 12:00:45 +00:00
Luke Taylor af5f193ec1 SEC-890: Corrected use of dataSource property name in RememberMeBDP. 2008-06-18 10:35:30 +00:00
Luke Taylor 7d79ae5424 SEC-880: Fix incorrect index value. 2008-06-13 10:58:01 +00:00
Luke Taylor 3e5b65bd85 Updated version names etc in petclinic tutorial 2008-06-12 12:23:25 +00:00
Luke Taylor 64b5fa0131 Added OWASP and Spring Framework links to site template 2008-06-11 17:46:43 +00:00
Luke Taylor fe929bf9b9 Added reference to OWASP site to preface of ref manual 2008-06-11 17:35:27 +00:00
Luke Taylor 8a2581c939 Experimental integration test module 2008-06-10 22:17:44 +00:00
Luke Taylor 55caab3bbc Added spring-jdbc dep back in core-tiger (since it's optional in core) hence not transient) 2008-06-10 22:00:27 +00:00
Luke Taylor 269865ca65 Removed spring deps from core-tiger pom as they are transiently available anyway 2008-06-10 21:41:20 +00:00
Luke Taylor 32b8009bee SEC-875: Removed duplicated parameters from SavedRequestWrapper.getParameterValues() 2008-06-09 23:33:36 +00:00
Luke Taylor 3b775d29d3 SEC-870: Polish messages file contribution 2008-06-08 22:09:47 +00:00
Luke Taylor 0401dddda8 SEC-868: Added example siteminder config 2008-06-08 18:53:22 +00:00
Ben Alex 358f284f42 SEC-760: Correct bug where more than one concurrent JaasAuthenticationProvider used. 2008-06-06 06:13:14 +00:00
Ben Alex b403216494 SEC-838: Make fields in AbstractAclProvider protected to facilitate subclass reuse. 2008-06-06 03:01:51 +00:00
Ben Alex 371769740a SEC-831: Improve support for Postges, which requires "AS" for table aliasing, together with stored procedures for sequence allocation. 2008-06-06 02:55:53 +00:00
Ben Alex e38d5dfd87 SEC-813: Allow custom Permission classes to be used. 2008-06-06 02:37:19 +00:00
Ben Alex ff5666ae83 SEC-819: Properly support integer (and other numeric) identifiers. 2008-06-06 01:05:46 +00:00
Ben Alex de897ad1ac SEC-867: Remove superfluous <property /> entry. 2008-06-05 22:51:47 +00:00
Luke Taylor ff785a829f [maven-release-plugin] prepare for next development iteration 2008-06-03 16:07:20 +00:00
Luke Taylor db1d8604a6 [maven-release-plugin] prepare release spring-security-parent-2.0.2 2008-06-03 16:05:40 +00:00
Luke Taylor f762920239 Typo 2008-06-03 15:49:21 +00:00
Luke Taylor 70826f1202 Shorten faq question 2008-06-03 15:48:30 +00:00
Luke Taylor ea25299bd0 Removed sandbox from build because of site generation problems 2008-06-03 15:37:41 +00:00
Luke Taylor d784d854cd Corrected log file name. 2008-06-03 14:57:40 +00:00
Luke Taylor 9308284bd4 SEC-864: Removed duplicate OpenID provider. 2008-06-03 14:53:43 +00:00
Luke Taylor c34eb497c8 Correct captcha module dependency 2008-06-03 14:11:30 +00:00
Luke Taylor de250d2073 Add sandbox code to build for 2.0.2 release 2008-06-03 13:41:38 +00:00
Luke Taylor 8df56c8ac5 Test log4j properties file for core-tiger module 2008-06-03 13:21:23 +00:00
Luke Taylor 192aa25b60 Addtional sample app files 2008-06-03 13:04:50 +00:00
Luke Taylor d95a5597c8 Bug-testing changes to heavyduty sample 2008-06-03 12:58:13 +00:00
296 changed files with 12532 additions and 3307 deletions
+8 -2
View File
@@ -3,13 +3,12 @@
<parent>
<artifactId>spring-security-parent</artifactId>
<groupId>org.springframework.security</groupId>
<version>2.0.2-SNAPSHOT</version>
<version>2.0.4</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.2-SNAPSHOT</version>
<packaging>bundle</packaging>
<dependencies>
@@ -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>
@@ -0,0 +1,59 @@
package org.springframework.security.acls.domain;
import org.springframework.security.acls.AclFormattingUtils;
import org.springframework.security.acls.Permission;
/**
* Provides an abstract superclass for {@link Permission} implementations.
*
* @author Ben Alex
* @since 2.0.3
* @see AbstractRegisteredPermission
*
*/
public abstract class AbstractPermission implements Permission {
//~ Instance fields ================================================================================================
protected char code;
protected int mask;
//~ Constructors ===================================================================================================
protected AbstractPermission(int mask, char code) {
this.mask = mask;
this.code = code;
}
//~ Methods ========================================================================================================
public final boolean equals(Object arg0) {
if (arg0 == null) {
return false;
}
if (!(arg0 instanceof Permission)) {
return false;
}
Permission rhs = (Permission) arg0;
return (this.mask == rhs.getMask());
}
public final int getMask() {
return mask;
}
public String getPattern() {
return AclFormattingUtils.printBinary(mask, code);
}
public final String toString() {
return this.getClass().getSimpleName() + "[" + getPattern() + "=" + mask + "]";
}
public final int hashCode() {
return this.mask;
}
}
@@ -14,157 +14,59 @@
*/
package org.springframework.security.acls.domain;
import org.springframework.security.acls.AclFormattingUtils;
import org.springframework.security.acls.Permission;
import org.springframework.util.Assert;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
* A set of standard permissions.
*
*
* <p>
* You may subclass this class to add additional permissions, or use this class as a guide
* for creating your own permission classes.
* </p>
*
* @author Ben Alex
* @version $Id$
*/
public final class BasePermission implements Permission {
//~ Static fields/initializers =====================================================================================
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
private static Map locallyDeclaredPermissionsByInteger = new HashMap();
private static Map locallyDeclaredPermissionsByName = new HashMap();
protected static DefaultPermissionFactory defaultPermissionFactory = new DefaultPermissionFactory();
static {
Field[] fields = BasePermission.class.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
try {
Object fieldValue = fields[i].get(null);
if (BasePermission.class.isAssignableFrom(fieldValue.getClass())) {
// Found a BasePermission static field
BasePermission perm = (BasePermission) fieldValue;
locallyDeclaredPermissionsByInteger.put(new Integer(perm.getMask()), perm);
locallyDeclaredPermissionsByName.put(fields[i].getName(), perm);
}
} catch (Exception ignore) {}
}
}
//~ Instance fields ================================================================================================
private char code;
private int mask;
//~ Constructors ===================================================================================================
private BasePermission(int mask, char code) {
this.mask = mask;
this.code = code;
}
//~ Methods ========================================================================================================
/**
* Dynamically creates a <code>CumulativePermission</code> or <code>BasePermission</code> representing the
* active bits in the passed mask.
*
* @param mask to build
*
* @return a Permission representing the requested object
/**
* Registers the public static permissions defined on this class. This is mandatory so
* that the static methods will operate correctly.
*/
public static Permission buildFromMask(int mask) {
if (locallyDeclaredPermissionsByInteger.containsKey(new Integer(mask))) {
// The requested mask has an exactly match against a statically-defined BasePermission, so return it
return (Permission) locallyDeclaredPermissionsByInteger.get(new Integer(mask));
}
// To get this far, we have to use a CumulativePermission
CumulativePermission permission = new CumulativePermission();
for (int i = 0; i < 32; i++) {
int permissionToCheck = 1 << i;
if ((mask & permissionToCheck) == permissionToCheck) {
Permission p = (Permission) locallyDeclaredPermissionsByInteger.get(new Integer(permissionToCheck));
Assert.state(p != null,
"Mask " + permissionToCheck + " does not have a corresponding static BasePermission");
permission.set(p);
}
}
return permission;
static {
registerPermissionsFor(BasePermission.class);
}
public static Permission[] buildFromMask(int[] masks) {
if ((masks == null) || (masks.length == 0)) {
return new Permission[0];
}
Permission[] permissions = new Permission[masks.length];
for (int i = 0; i < masks.length; i++) {
permissions[i] = buildFromMask(masks[i]);
}
return permissions;
protected BasePermission(int mask, char code) {
super(mask, code);
}
public static Permission buildFromName(String name) {
Assert.isTrue(locallyDeclaredPermissionsByName.containsKey(name), "Unknown permission '" + name + "'");
return (Permission) locallyDeclaredPermissionsByName.get(name);
protected final static void registerPermissionsFor(Class subClass) {
defaultPermissionFactory.registerPublicPermissions(subClass);
}
public final static Permission buildFromMask(int mask) {
return defaultPermissionFactory.buildFromMask(mask);
}
public static Permission[] buildFromName(String[] names) {
if ((names == null) || (names.length == 0)) {
return new Permission[0];
}
Permission[] permissions = new Permission[names.length];
for (int i = 0; i < names.length; i++) {
permissions[i] = buildFromName(names[i]);
}
return permissions;
public final static Permission[] buildFromMask(int[] masks) {
return defaultPermissionFactory.buildFromMask(masks);
}
public boolean equals(Object arg0) {
if (arg0 == null) {
return false;
}
if (!(arg0 instanceof Permission)) {
return false;
}
Permission rhs = (Permission) arg0;
return (this.mask == rhs.getMask());
public final static Permission buildFromName(String name) {
return defaultPermissionFactory.buildFromName(name);
}
public int getMask() {
return mask;
public final static Permission[] buildFromName(String[] names) {
return defaultPermissionFactory.buildFromName(names);
}
public String getPattern() {
return AclFormattingUtils.printBinary(mask, code);
}
public String toString() {
return "BasePermission[" + getPattern() + "=" + mask + "]";
}
public int hashCode() {
return this.mask;
}
}
}
@@ -19,20 +19,21 @@ import org.springframework.security.acls.Permission;
/**
* Represents a <code>Permission</code> that is constructed at runtime from other permissions.<p>Methods return
* <code>this</code>, in order to facilitate method chaining.</p>
* Represents a <code>Permission</code> that is constructed at runtime from other permissions.
*
* <p>Methods return <code>this</code>, in order to facilitate method chaining.</p>
*
* @author Ben Alex
* @version $Id$
*/
public class CumulativePermission implements Permission {
//~ Instance fields ================================================================================================
public class CumulativePermission extends AbstractPermission {
private String pattern = THIRTY_TWO_RESERVED_OFF;
private int mask = 0;
//~ Methods ========================================================================================================
public CumulativePermission() {
super(0, ' ');
}
public CumulativePermission clear(Permission permission) {
this.mask &= ~permission.getMask();
this.pattern = AclFormattingUtils.demergePatterns(this.pattern, permission.getPattern());
@@ -46,43 +47,16 @@ public class CumulativePermission implements Permission {
return this;
}
public boolean equals(Object arg0) {
if (arg0 == null)
{
return false;
}
if (!(arg0 instanceof Permission)) {
return false;
}
Permission rhs = (Permission) arg0;
return (this.mask == rhs.getMask());
}
public int hashCode() {
return this.mask;
}
public int getMask() {
return this.mask;
}
public String getPattern() {
return this.pattern;
}
public CumulativePermission set(Permission permission) {
this.mask |= permission.getMask();
this.pattern = AclFormattingUtils.mergePatterns(this.pattern, permission.getPattern());
return this;
}
public String toString() {
return "CumulativePermission[" + pattern + "=" + this.mask + "]";
public String getPattern() {
return this.pattern;
}
}
@@ -0,0 +1,127 @@
package org.springframework.security.acls.domain;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import org.springframework.security.acls.Permission;
import org.springframework.security.acls.jdbc.LookupStrategy;
import org.springframework.util.Assert;
/**
* Default implementation of {@link PermissionFactory}.
*
* <p>
* Generally this class will be used by a {@link Permission} instance, as opposed to being dependency
* injected into a {@link LookupStrategy} or similar. Nevertheless, the latter mode of operation is
* fully supported (in which case your {@link Permission} implementations probably should extend
* {@link AbstractPermission} instead of {@link AbstractRegisteredPermission}).
* </p>
*
* @author Ben Alex
* @since 2.0.3
*
*/
public class DefaultPermissionFactory implements PermissionFactory {
private Map registeredPermissionsByInteger = new HashMap();
private Map registeredPermissionsByName = new HashMap();
/**
* Permit registration of a {@link DefaultPermissionFactory} class. The class must provide
* public static fields of type {@link Permission} to represent the possible permissions.
*
* @param clazz a {@link Permission} class with public static fields to register
*/
public void registerPublicPermissions(Class clazz) {
Assert.notNull(clazz, "Class required");
Assert.isAssignable(Permission.class, clazz);
Field[] fields = clazz.getFields();
for (int i = 0; i < fields.length; i++) {
try {
Object fieldValue = fields[i].get(null);
if (Permission.class.isAssignableFrom(fieldValue.getClass())) {
// Found a Permission static field
Permission perm = (Permission) fieldValue;
String permissionName = fields[i].getName();
registerPermission(perm, permissionName);
}
} catch (Exception ignore) {}
}
}
public void registerPermission(Permission perm, String permissionName) {
Assert.notNull(perm, "Permission required");
Assert.hasText(permissionName, "Permission name required");
Integer mask = new Integer(perm.getMask());
// Ensure no existing Permission uses this integer or code
Assert.isTrue(!registeredPermissionsByInteger.containsKey(mask), "An existing Permission already provides mask " + mask);
Assert.isTrue(!registeredPermissionsByName.containsKey(permissionName), "An existing Permission already provides name '" + permissionName + "'");
// Register the new Permission
registeredPermissionsByInteger.put(mask, perm);
registeredPermissionsByName.put(permissionName, perm);
}
public Permission buildFromMask(int mask) {
if (registeredPermissionsByInteger.containsKey(new Integer(mask))) {
// The requested mask has an exactly match against a statically-defined Permission, so return it
return (Permission) registeredPermissionsByInteger.get(new Integer(mask));
}
// To get this far, we have to use a CumulativePermission
CumulativePermission permission = new CumulativePermission();
for (int i = 0; i < 32; i++) {
int permissionToCheck = 1 << i;
if ((mask & permissionToCheck) == permissionToCheck) {
Permission p = (Permission) registeredPermissionsByInteger.get(new Integer(permissionToCheck));
Assert.state(p != null, "Mask " + permissionToCheck + " does not have a corresponding static Permission");
permission.set(p);
}
}
return permission;
}
public Permission[] buildFromMask(int[] masks) {
if ((masks == null) || (masks.length == 0)) {
return new Permission[0];
}
Permission[] permissions = new Permission[masks.length];
for (int i = 0; i < masks.length; i++) {
permissions[i] = buildFromMask(masks[i]);
}
return permissions;
}
public Permission buildFromName(String name) {
Assert.isTrue(registeredPermissionsByName.containsKey(name), "Unknown permission '" + name + "'");
return (Permission) registeredPermissionsByName.get(name);
}
public Permission[] buildFromName(String[] names) {
if ((names == null) || (names.length == 0)) {
return new Permission[0];
}
Permission[] permissions = new Permission[names.length];
for (int i = 0; i < names.length; i++) {
permissions[i] = buildFromName(names[i]);
}
return permissions;
}
}
@@ -0,0 +1,24 @@
package org.springframework.security.acls.domain;
import org.springframework.security.acls.Permission;
/**
* Provides a simple mechanism to retrieve {@link Permission} instances from integer masks.
*
* @author Ben Alex
* @since 2.0.3
*
*/
public interface PermissionFactory {
/**
* Dynamically creates a <code>CumulativePermission</code> or <code>BasePermission</code> representing the
* active bits in the passed mask.
*
* @param mask to build
*
* @return a Permission representing the requested object
*/
public abstract Permission buildFromMask(int mask);
}
@@ -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;
@@ -49,6 +51,7 @@ import org.springframework.security.acls.sid.PrincipalSid;
import org.springframework.security.acls.sid.Sid;
import org.springframework.security.util.FieldUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
@@ -172,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;
}
@@ -239,7 +261,8 @@ public final class BasicLookupStrategy implements LookupStrategy {
recipient = new GrantedAuthoritySid(rs.getString("ace_sid"));
}
Permission permission = BasePermission.buildFromMask(rs.getInt("mask"));
int mask = rs.getInt("mask");
Permission permission = convertMaskIntoPermission(mask);
boolean granting = rs.getBoolean("granting");
boolean auditSuccess = rs.getBoolean("audit_success");
boolean auditFailure = rs.getBoolean("audit_failure");
@@ -264,6 +287,10 @@ public final class BasicLookupStrategy implements LookupStrategy {
}
}
protected Permission convertMaskIntoPermission(int mask) {
return BasePermission.buildFromMask(mask);
}
/**
* Looks up a batch of <code>ObjectIdentity</code>s directly from the database.<p>The caller is responsible
* for optimization issues, such as selecting the identities to lookup, ensuring the cache doesn't contain them
@@ -293,10 +320,10 @@ public final class BasicLookupStrategy implements LookupStrategy {
for (int i = 0; i < objectIdentities.length; i++) {
// Determine prepared statement values for this iteration
String javaType = objectIdentities[i].getJavaType().getName();
Assert.isInstanceOf(Long.class, objectIdentities[i].getIdentifier(),
"This class requires ObjectIdentity.getIdentifier() to be a Long");
long id = ((Long) objectIdentities[i].getIdentifier()).longValue();
// No need to check for nulls, as guaranteed non-null by ObjectIdentity.getIdentifier() interface contract
String identifier = objectIdentities[i].getIdentifier().toString();
long id = (Long.valueOf(identifier)).longValue();
// Inject values
ps.setLong((2 * i) + 1, id);
@@ -53,7 +53,7 @@ public class JdbcAclService implements AclService {
//~ Static fields/initializers =====================================================================================
protected static final Log log = LogFactory.getLog(JdbcAclService.class);
private static final String selectAclObjectWithParent = "select obj.object_id_identity obj_id, class.class class "
private static final String selectAclObjectWithParent = "select obj.object_id_identity as obj_id, class.class as class "
+ "from acl_object_identity obj, acl_object_identity parent, acl_class class "
+ "where obj.parent_object = parent.id and obj.object_id_class = class.id "
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
@@ -64,7 +64,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
private AclCache aclCache;
private String deleteEntryByObjectIdentityForeignKey = "delete from acl_entry where acl_object_identity=?";
private String deleteObjectIdentityByPrimaryKey = "delete from acl_object_identity where id=?";
private String identityQuery = "call identity()";
private String classIdentityQuery = "call identity()"; // should be overridden for postgres : select currval('acl_class_seq')
private String sidIdentityQuery = "call identity()"; // should be overridden for postgres : select currval('acl_siq_seq')
private String insertClass = "insert into acl_class (class) values (?)";
private String insertEntry = "insert into acl_entry "
+ "(acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure)"
@@ -176,7 +177,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
jdbcTemplate.update(insertClass, new Object[] {clazz.getName()});
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
"Transaction must be running");
classId = new Long(jdbcTemplate.queryForLong(identityQuery));
classId = new Long(jdbcTemplate.queryForLong(classIdentityQuery));
}
} else {
classId = (Long) classIds.iterator().next();
@@ -221,7 +222,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
jdbcTemplate.update(insertSid, new Object[] {new Boolean(principal), sidName});
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
"Transaction must be running");
sidId = new Long(jdbcTemplate.queryForLong(identityQuery));
sidId = new Long(jdbcTemplate.queryForLong(sidIdentityQuery));
}
} else {
sidId = (Long) sidIds.iterator().next();
@@ -380,11 +381,15 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
}
}
public void setIdentityQuery(String identityQuery) {
public void setClassIdentityQuery(String identityQuery) {
Assert.hasText(identityQuery, "New identity query is required");
this.identityQuery = identityQuery;
this.classIdentityQuery = identityQuery;
}
public void setSidIdentityQuery(String identityQuery) {
Assert.hasText(identityQuery, "New identity query is required");
this.sidIdentityQuery = identityQuery;
}
/**
* @param foreignKeysInDatabase if false this class will perform additional FK constrain checking, which may
* cause deadlocks (the default is true, so deadlocks are avoided but the database is expected to enforce FKs)
@@ -15,6 +15,7 @@
package org.springframework.security.acls.objectidentity;
import org.springframework.security.acls.IdentityUnavailableException;
import org.springframework.security.acls.jdbc.LookupStrategy;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -97,6 +98,12 @@ public class ObjectIdentityImpl implements ObjectIdentity {
/**
* Important so caching operates properly.<P>Considers an object of the same class equal if it has the same
* <code>classname</code> and <code>id</code> properties.</p>
*
* <p>
* Note that this class uses string equality for the identifier field, which ensures it better supports
* differences between {@link LookupStrategy} requirements and the domain object represented by this
* <code>ObjectIdentityImpl</code>.
* </p>
*
* @param arg0 object to compare
*
@@ -113,7 +120,7 @@ public class ObjectIdentityImpl implements ObjectIdentity {
ObjectIdentityImpl other = (ObjectIdentityImpl) arg0;
if (this.getIdentifier().equals(other.getIdentifier()) && this.getJavaType().equals(other.getJavaType())) {
if (this.getIdentifier().toString().equals(other.getIdentifier().toString()) && this.getJavaType().equals(other.getJavaType())) {
return true;
}
@@ -34,20 +34,20 @@ import org.springframework.util.Assert;
/**
* DOCUMENT ME!
* Abstract {@link AfterInvocationProvider} which provides commonly-used ACL-related services.
*
* @author $author$
* @version $Revision$
* @author Ben Alex
* @version $Id$
*/
public abstract class AbstractAclProvider implements AfterInvocationProvider {
//~ Instance fields ================================================================================================
private AclService aclService;
private Class processDomainObjectClass = Object.class;
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
private String processConfigAttribute;
private Permission[] requirePermission = {BasePermission.READ};
protected AclService aclService;
protected Class processDomainObjectClass = Object.class;
protected ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
protected SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
protected String processConfigAttribute;
protected Permission[] requirePermission = {BasePermission.READ};
//~ Constructors ===================================================================================================
@@ -22,7 +22,7 @@ import org.springframework.security.acls.Permission;
/**
* Tests BasePermission and CumulativePermission.
* Tests classes associated with Permission.
*
* @author Ben Alex
* @version $Id${date}
@@ -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());
@@ -63,9 +69,9 @@ public class PermissionTests {
assertEquals("CumulativePermission[...............................R=1]",
new CumulativePermission().set(BasePermission.READ).toString());
System.out.println("A = " + new CumulativePermission().set(BasePermission.ADMINISTRATION).toString());
assertEquals("CumulativePermission[...........................A....=16]",
new CumulativePermission().set(BasePermission.ADMINISTRATION).toString());
System.out.println("A = " + new CumulativePermission().set(SpecialPermission.ENTER).set(BasePermission.ADMINISTRATION).toString());
assertEquals("CumulativePermission[..........................EA....=48]",
new CumulativePermission().set(SpecialPermission.ENTER).set(BasePermission.ADMINISTRATION).toString());
System.out.println("RA = "
+ new CumulativePermission().set(BasePermission.ADMINISTRATION).set(BasePermission.READ).toString());
@@ -0,0 +1,40 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
import org.springframework.security.acls.Permission;
/**
* A test permission.
*
* @author Ben Alex
* @version $Id$
*/
public class SpecialPermission extends BasePermission {
public static final Permission ENTER = new SpecialPermission(1 << 5, 'E'); // 32
/**
* Registers the public static permissions defined on this class. This is mandatory so
* that the static methods will operate correctly.
*/
static {
registerPermissionsFor(SpecialPermission.class);
}
protected SpecialPermission(int mask, char code) {
super(mask, code);
}
}
@@ -120,7 +120,8 @@ public class BasicLookupStrategyTests {
public void testAclsRetrievalWithDefaultBatchSize() throws Exception {
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
// Deliberately use an integer for the child, to reproduce bug report in SEC-819
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(102));
Map map = this.strategy.readAclsById(new ObjectIdentity[] { topParentOid, middleParentOid, childOid }, null);
checkEntries(topParentOid, middleParentOid, childOid, map);
@@ -128,7 +129,7 @@ public class BasicLookupStrategyTests {
@Test
public void testAclsRetrievalFromCacheOnly() throws Exception {
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(100));
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
@@ -145,7 +146,7 @@ public class BasicLookupStrategyTests {
@Test
public void testAclsRetrievalWithCustomBatchSize() throws Exception {
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(101));
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
// Set a batch size to allow multiple database queries in order to retrieve all acls
@@ -227,7 +228,7 @@ public class BasicLookupStrategyTests {
jdbcTemplate.execute(query);
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(101));
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
ObjectIdentity middleParent2Oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(103));
@@ -260,8 +261,8 @@ public class BasicLookupStrategyTests {
ObjectIdentity grandParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(104));
ObjectIdentity parent1Oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(105));
ObjectIdentity parent2Oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(106));
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(107));
ObjectIdentity parent2Oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(106));
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(107));
// First lookup only child, thus populating the cache with grandParent, parent1 and child
Permission[] checkPermission = new Permission[] { BasePermission.READ };
@@ -290,21 +291,4 @@ public class BasicLookupStrategyTests {
Assert.assertTrue(foundParent2Acl.isGranted(checkPermission, sids, false));
}
@Test
public void testAclsWithDifferentSerializableTypesAsObjectIdentities() throws Exception {
String query = "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (4,2,104,null,1,1);"
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (5,4,0,1,1,1,0,0)";
jdbcTemplate.execute(query);
ObjectIdentity oid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(104));
Sid[] sids = new Sid[] { new PrincipalSid("ben") };
ObjectIdentity[] childOids = new ObjectIdentity[] { oid };
try {
Map foundAcls = strategy.readAclsById(childOids, sids);
Assert.fail("It should have thrown IllegalArgumentException");
} catch(IllegalArgumentException expected) {
Assert.assertTrue(true);
}
}
}
@@ -97,7 +97,7 @@ public class JdbcAclServiceTests extends AbstractTransactionalDataSourceSpringCo
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(102));
MutableAcl topParent = jdbcMutableAclService.createAcl(topParentOid);
MutableAcl middleParent = jdbcMutableAclService.createAcl(middleParentOid);
@@ -337,7 +337,7 @@ public class JdbcAclServiceTests extends AbstractTransactionalDataSourceSpringCo
ObjectIdentity topParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100));
ObjectIdentity middleParentOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(101));
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(102));
ObjectIdentity childOid = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Integer(102));
// Remove the child and check all related database rows were removed accordingly
jdbcMutableAclService.deleteAcl(childOid, false);
@@ -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);
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-adapters</artifactId>
<version>2.0.2-SNAPSHOT</version>
<version>2.0.4</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.2-SNAPSHOT</version>
<version>2.0.4</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.2-SNAPSHOT</version>
<version>2.0.4</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.2-SNAPSHOT</version>
<version>2.0.4</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.2-SNAPSHOT</version>
<version>2.0.4</version>
</parent>
<artifactId>spring-security-resin</artifactId>
<name>Spring Security - Resin adapter</name>
+10 -3
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-parent</artifactId>
<version>2.0.2-SNAPSHOT</version>
<version>2.0.4</version>
</parent>
<artifactId>spring-security-cas-client</artifactId>
<name>Spring Security - CAS support</name>
@@ -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.1</version>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
@@ -54,7 +61,7 @@
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.1, 4.0.0)"
org.jasig.cas.client.*;version="[3.1.3, 4.0.0)"
</spring.osgi.import>
<spring.osgi.private.pkg>
@@ -15,6 +15,11 @@
package org.springframework.security.ui.cas;
import java.io.IOException;
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.validation.TicketValidator;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationException;
@@ -24,6 +29,7 @@ import org.springframework.security.ui.AbstractProcessingFilter;
import org.springframework.security.ui.FilterChainOrder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
@@ -38,7 +44,11 @@ import javax.servlet.http.HttpServletRequest;
* <p>The configured <code>AuthenticationManager</code> is expected to provide a provider that can recognise
* <code>UsernamePasswordAuthenticationToken</code>s containing this special <code>principal</code> name, and process
* them accordingly by validation with the CAS server.</p>
* <p><b>Do not use this class directly.</b> Instead configure <code>web.xml</code> to use the {@link
* <p>By configuring a shared {@link ProxyGrantingTicketStorage} between the {@link TicketValidator} and the CasProcessingFilter
* one can have the CasProcessingFilter handle the proxying requirements for CAS. In addition, the URI endpoint for the proxying
* would also need to be configured (i.e. the part after protocol, hostname, and port).
*
* <p><b>Do not use this class directly.</b> Instead configure <code>web.xml</code> to use the {@link
* org.springframework.security.util.FilterToBeanProxy}.</p>
*
* @author Ben Alex
@@ -57,8 +67,17 @@ public class CasProcessingFilter extends AbstractProcessingFilter {
*/
public static final String CAS_STATELESS_IDENTIFIER = "_cas_stateless_";
//~ Methods ========================================================================================================
/**
* The last portion of the receptor url, i.e. /proxy/receptor
*/
private String proxyReceptorUrl;
/**
* The backing storage to store ProxyGrantingTicket requests.
*/
private ProxyGrantingTicketStorage proxyGrantingTicketStorage;
//~ Methods ========================================================================================================
public Authentication attemptAuthentication(final HttpServletRequest request)
throws AuthenticationException {
final String username = CAS_STATEFUL_IDENTIFIER;
@@ -87,4 +106,35 @@ public class CasProcessingFilter extends AbstractProcessingFilter {
public int getOrder() {
return FilterChainOrder.CAS_PROCESSING_FILTER;
}
/**
* Overridden to provide proxying capabilities.
*/
protected boolean requiresAuthentication(final HttpServletRequest request,
final HttpServletResponse response) {
final String requestUri = request.getRequestURI();
if (CommonUtils.isEmpty(this.proxyReceptorUrl) || !requestUri.endsWith(this.proxyReceptorUrl) || this.proxyGrantingTicketStorage == null) {
return super.requiresAuthentication(request, response);
}
try {
CommonUtils.readAndRespondToProxyReceptorRequest(request, response, this.proxyGrantingTicketStorage);
return false;
} catch (final IOException e) {
return super.requiresAuthentication(request, response);
}
}
public final void setProxyReceptorUrl(final String proxyReceptorUrl) {
this.proxyReceptorUrl = proxyReceptorUrl;
}
public final void setProxyGrantingTicketStorage(
final ProxyGrantingTicketStorage proxyGrantingTicketStorage) {
this.proxyGrantingTicketStorage = proxyGrantingTicketStorage;
}
}
+7 -16
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-parent</artifactId>
<version>2.0.2-SNAPSHOT</version>
<version>2.0.4</version>
</parent>
<packaging>bundle</packaging>
<artifactId>spring-security-core-tiger</artifactId>
@@ -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>
@@ -32,20 +37,6 @@
<artifactId>aspectjweaver</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-support</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
@@ -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");
}
@@ -0,0 +1,12 @@
# Logging
#
# $Id: log4j.properties 2385 2007-12-20 20:53:26Z luke_t $
log4j.rootCategory=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p %c - %m%n
log4j.category.org.springframework.security=DEBUG
@@ -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>
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-parent</artifactId>
<version>2.0.2-SNAPSHOT</version>
<version>2.0.4</version>
</parent>
<packaging>bundle</packaging>
<artifactId>spring-security-core</artifactId>
@@ -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;
}
}
@@ -158,4 +158,8 @@ public class ConcurrentSessionControllerImpl implements ConcurrentSessionControl
public void setSessionRegistry(SessionRegistry sessionRegistry) {
this.sessionRegistry = sessionRegistry;
}
public SessionRegistry getSessionRegistry() {
return sessionRegistry;
}
}
@@ -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));
@@ -1,5 +1,6 @@
package org.springframework.security.config;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -21,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);
@@ -32,14 +33,20 @@ 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",
new RuntimeBeanReference(sessionControllerRef));
RootBeanDefinition sessionRegistryInjector = new RootBeanDefinition(SessionRegistryInjectionBeanPostProcessor.class);
sessionRegistryInjector.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
sessionRegistryInjector.getConstructorArgumentValues().addGenericArgumentValue(sessionControllerRef);
parserContext.getRegistry().registerBeanDefinition(BeanIds.SESSION_REGISTRY_INJECTION_POST_PROCESSOR, sessionRegistryInjector);
}
parserContext.getRegistry().registerAlias(BeanIds.AUTHENTICATION_MANAGER, alias);
return null;
}
}
}
@@ -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;
}
@@ -18,6 +18,7 @@ public abstract class BeanIds {
static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = "_contextSettingPostProcessor";
static final String ENTRY_POINT_INJECTION_POST_PROCESSOR = "_entryPointInjectionBeanPostProcessor";
static final String USER_DETAILS_SERVICE_INJECTION_POST_PROCESSOR = "_userServiceInjectionPostProcessor";
static final String SESSION_REGISTRY_INJECTION_POST_PROCESSOR = "_sessionRegistryInjectionPostProcessor";
static final String FILTER_CHAIN_POST_PROCESSOR = "_filterChainProxyPostProcessor";
static final String FILTER_LIST = "_filterChainList";
@@ -41,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";
@@ -48,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";
@@ -65,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;
}
@@ -66,7 +66,7 @@ public class FilterChainProxyPostProcessor implements BeanPostProcessor, BeanFac
unwrapFilter(previous) + "' have the same 'order' value. When using custom filters, " +
"please make sure the positions do not conflict with default filters. " +
"Alternatively you can disable the default filters by removing the corresponding " +
"child elements from <http> and not avoiding the use of <http auto-config='true'>.");
"child elements from <http> and avoiding the use of <http auto-config='true'>.");
}
}
}
@@ -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);
registerHttpSessionIntegrationFilter(element, 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,31 +127,31 @@ 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);
registry.registerBeanDefinition(BeanIds.PORT_MAPPER, portMapper);
registerExceptionTranslationFilter(element, parserContext);
registerExceptionTranslationFilter(element, parserContext, allowSessionCreation);
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,22 +159,9 @@ 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);
}
parseBasicFormLoginAndOpenID(element, parserContext, autoConfig);
parseRememberMeAndLogout(element, autoConfig, parserContext);
parseBasicFormLoginAndOpenID(element, parserContext, autoConfig, allowSessionCreation);
Element x509Elt = DomUtils.getChildElementByTagName(element, Elements.X509);
if (x509Elt != null) {
@@ -188,26 +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 void registerHttpSessionIntegrationFilter(Element element, ParserContext pc) {
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);
@@ -215,6 +225,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
} else if (OPT_CREATE_SESSION_NEVER.equals(createSession)) {
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.FALSE);
httpScif.getPropertyValues().addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
sessionCreationAllowed = false;
} else {
createSession = DEF_CREATE_SESSION_IF_REQUIRED;
httpScif.getPropertyValues().addPropertyValue("allowSessionCreation", Boolean.TRUE);
@@ -223,9 +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)) {
@@ -238,26 +251,27 @@ 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) {
String accessDeniedPage = element.getAttribute(ATT_ACCESS_DENIED_PAGE);
ConfigUtils.validateHttpRedirect(accessDeniedPage, pc, pc.extractSource(element));
private void registerExceptionTranslationFilter(Element element, ParserContext pc, boolean allowSessionCreation) {
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);
@@ -267,27 +281,27 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
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",
@@ -295,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);
@@ -316,160 +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) {
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();
ConfigUtils.getRegisteredProviders(pc).add(openIDProvider);
pc.getRegistry().registerBeanDefinition(BeanIds.OPEN_ID_PROVIDER, openIDProvider);
ConfigUtils.addAuthenticationProvider(pc, BeanIds.OPEN_ID_PROVIDER);
}
boolean needLoginPage = false;
if (formLoginFilter != null) {
needLoginPage = true;
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;
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)) {
@@ -503,8 +518,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
}
// Default for regex is no change
}
return matcher;
return matcher;
}
/**
@@ -548,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)) {
@@ -561,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();
@@ -591,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;
@@ -84,7 +85,7 @@ public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
tokenRepo = new RuntimeBeanReference(tokenRepository);
} else {
tokenRepo = new RootBeanDefinition(JdbcTokenRepositoryImpl.class);
((BeanDefinition)tokenRepo).getPropertyValues().addPropertyValue(ATT_DATA_SOURCE,
((BeanDefinition)tokenRepo).getPropertyValues().addPropertyValue("dataSource",
new RuntimeBeanReference(dataSource));
}
services.getPropertyValues().addPropertyValue("tokenRepository", tokenRepo);
@@ -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];
}
@@ -0,0 +1,94 @@
package org.springframework.security.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.security.concurrent.ConcurrentSessionController;
import org.springframework.security.concurrent.ConcurrentSessionControllerImpl;
import org.springframework.security.concurrent.SessionRegistry;
import org.springframework.security.ui.AbstractProcessingFilter;
import org.springframework.security.ui.SessionFixationProtectionFilter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Registered by the <tt>AuthenticationManagerBeanDefinitionParser</tt> if an external
* ConcurrentSessionController is set (and hence an external SessionRegistry).
* Its responsibility is to set the SessionRegistry on namespace-registered beans which require access
* to it.
* <p>
* It will attempt to read the registry directly from the registered controller. If that fails, it will look in
* the application context for a registered SessionRegistry bean.
*
* See SEC-879.
*
* @author Luke Taylor
* @since 2.0.3
*/
class SessionRegistryInjectionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
private final Log logger = LogFactory.getLog(getClass());
private ListableBeanFactory beanFactory;
private SessionRegistry sessionRegistry;
private final String controllerBeanName;
SessionRegistryInjectionBeanPostProcessor(String controllerBeanName) {
this.controllerBeanName = controllerBeanName;
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (BeanIds.FORM_LOGIN_FILTER.equals(beanName) ||
BeanIds.OPEN_ID_FILTER.equals(beanName)) {
((AbstractProcessingFilter) bean).setSessionRegistry(getSessionRegistry());
} else if (BeanIds.SESSION_FIXATION_PROTECTION_FILTER.equals(beanName)) {
((SessionFixationProtectionFilter)bean).setSessionRegistry(getSessionRegistry());
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
private SessionRegistry getSessionRegistry() {
if (sessionRegistry != null) {
return sessionRegistry;
}
logger.info("Attempting to read SessionRegistry from registered ConcurrentSessionController bean");
ConcurrentSessionController controller = (ConcurrentSessionController) beanFactory.getBean(controllerBeanName);
if (controller instanceof ConcurrentSessionControllerImpl) {
sessionRegistry = ((ConcurrentSessionControllerImpl)controller).getSessionRegistry();
return sessionRegistry;
}
logger.info("ConcurrentSessionController is not a standard implementation. SessionRegistry could not be read from it. Looking for it in the context.");
List sessionRegs = new ArrayList(beanFactory.getBeansOfType(SessionRegistry.class).values());
if (sessionRegs.size() == 0) {
throw new SecurityConfigurationException("concurrent-session-controller-ref was set but no SessionRegistry could be obtained from the application context.");
}
if (sessionRegs.size() > 1) {
logger.warn("More than one SessionRegistry instance in application context. Possible configuration errors may result.");
}
sessionRegistry = (SessionRegistry) sessionRegs.get(0);
return sessionRegistry;
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ListableBeanFactory) beanFactory;
}
}
@@ -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);
@@ -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,18 @@ 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;
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 +77,90 @@ 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 {
// Obtain methods for the present bean
Method[] methods;
try {
methods = bean.getClass().getMethods();
} catch (Exception e) {
throw new IllegalStateException(e.getMessage());
}
// 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);
}
}
// 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
}
}
}
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();
}
}
@@ -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,38 @@ 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());
NamingEnumeration resultsEnum = ctx.search(base, filter, params, searchControls);
Set results = new HashSet();
try {
while (resultsEnum.hasMore()) {
NamingEnumeration results = ctx.search(base, filter, params, searchControls);
SearchResult searchResult = (SearchResult) resultsEnum.next();
// Work out the DN of the matched entry
StringBuffer dn = new StringBuffer(searchResult.getName());
if (!results.hasMore()) {
if (base.length() > 0) {
dn.append(",");
dn.append(base);
}
results.add(new DirContextAdapter(searchResult.getAttributes(),
new DistinguishedName(dn.toString()), 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");
}
@@ -158,7 +158,7 @@ public class JaasAuthenticationProvider implements AuthenticationProvider, Appli
Assert.hasLength(loginContextName, "loginContextName must be set on " + getClass());
configureJaas(loginConfig);
Assert.notNull(Configuration.getConfiguration(),
"As per http://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/login/Configuration.html "
+ "\"If a Configuration object was set via the Configuration.setConfiguration method, then that object is "
@@ -246,6 +246,9 @@ public class JaasAuthenticationProvider implements AuthenticationProvider, Appli
*/
protected void configureJaas(Resource loginConfig) throws IOException {
configureJaasUsingLoop();
// Overcome issue in SEC-760
Configuration.getConfiguration().refresh();
}
/**
@@ -375,7 +378,9 @@ public class JaasAuthenticationProvider implements AuthenticationProvider, Appli
* @param token The {@link UsernamePasswordAuthenticationToken} being processed
*/
protected void publishSuccessEvent(UsernamePasswordAuthenticationToken token) {
applicationEventPublisher.publishEvent(new JaasAuthenticationSuccessEvent(token));
if (applicationEventPublisher != null) {
applicationEventPublisher.publishEvent(new JaasAuthenticationSuccessEvent(token));
}
}
/**
@@ -88,7 +88,6 @@ public class PreAuthenticatedAuthenticationProvider implements AuthenticationPro
result.setDetails(authentication.getDetails());
return result;
}
/**
@@ -123,4 +122,14 @@ public class PreAuthenticatedAuthenticationProvider implements AuthenticationPro
public void setThrowExceptionWhenTokenRejected(boolean throwExceptionWhenTokenRejected) {
this.throwExceptionWhenTokenRejected = throwExceptionWhenTokenRejected;
}
/**
* Sets the strategy which will be used to validate the loaded <tt>UserDetails</tt> object
* for the user. Defaults to an {@link AccountStatusUserDetailsChecker}.
* @param userDetailsChecker
*/
public void setUserDetailsChecker(UserDetailsChecker userDetailsChecker) {
Assert.notNull(userDetailsChecker, "userDetailsChacker cannot be null");
this.userDetailsChecker = userDetailsChecker;
}
}
@@ -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);
}
@@ -147,7 +147,11 @@ 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();
@@ -218,11 +222,13 @@ public abstract class AbstractProcessingFilter extends SpringSecurityFilter impl
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(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();
}
}
/**
@@ -58,7 +58,7 @@ public class AuthenticationDetailsSourceImpl implements AuthenticationDetailsSou
Constructor constructor = null;
for (int i = 0; i < constructors.length; i++) {
Class[] parameterTypes = constructors[i].getParameterTypes();
if (parameterTypes.length == 1 && (object == null || parameterTypes[i].isInstance(object))) {
if (parameterTypes.length == 1 && (object == null || parameterTypes[0].isInstance(object))) {
constructor = constructors[i];
break;
}
@@ -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 {
@@ -107,6 +107,7 @@ 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;
//~ Methods ========================================================================================================
@@ -116,8 +117,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;
}
@@ -181,6 +182,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 +330,14 @@ public class FilterChainProxy implements Filter, InitializingBean, ApplicationCo
return matcher;
}
/**
* 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[");
@@ -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();
}
}
@@ -31,10 +31,12 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.Map.Entry;
@@ -274,58 +276,62 @@ public class SavedRequestAwareWrapper extends SecurityContextHolderAwareRequestW
}
public Map getParameterMap() {
Map parameters = super.getParameterMap();
if (savedRequest == null) {
return parameters;
return super.getParameterMap();
}
// We have a saved request so merge the values, with the wrapped request taking precedence (see getParameter())
Map newParameters = new HashMap(savedRequest.getParameterMap().size() + parameters.size());
newParameters.putAll(parameters);
Set names = getCombinedParameterNames();
Iterator nameIter = names.iterator();
Map parameterMap = new HashMap(names.size());
Iterator savedParams = savedRequest.getParameterMap().entrySet().iterator();
while (savedParams.hasNext()) {
Map.Entry entry = (Entry) savedParams.next();
String name = (String) entry.getKey();
String[] savedParamValues = (String[]) entry.getValue();
if (newParameters.containsKey(name)) {
// merge values
String[] existingValues = (String[]) newParameters.get(name);
String[] mergedValues = new String[savedParamValues.length + existingValues.length];
System.arraycopy(existingValues, 0, mergedValues, 0, existingValues.length);
System.arraycopy(savedParamValues, 0, mergedValues, existingValues.length, savedParamValues.length);
newParameters.put(name, mergedValues);
} else {
newParameters.put(name, savedParamValues);
}
while (nameIter.hasNext()) {
String name = (String) nameIter.next();
parameterMap.put(name, getParameterValues(name));
}
return newParameters;
return parameterMap;
}
private Set getCombinedParameterNames() {
Set names = new HashSet();
names.addAll(super.getParameterMap().keySet());
if (savedRequest != null) {
names.addAll(savedRequest.getParameterMap().keySet());
}
return names;
}
public Enumeration getParameterNames() {
return new Enumerator(getParameterMap().keySet());
return new Enumerator(getCombinedParameterNames());
}
public String[] getParameterValues(String name) {
String[] savedRequestParams = savedRequest == null ? null : savedRequest.getParameterValues(name);
if (savedRequest == null) {
return super.getParameterValues(name);
}
String[] savedRequestParams = savedRequest.getParameterValues(name);
String[] wrappedRequestParams = super.getParameterValues(name);
if (savedRequestParams == null && wrappedRequestParams == null) {
return null;
if (savedRequestParams == null) {
return wrappedRequestParams;
}
if (wrappedRequestParams == null) {
return savedRequestParams;
}
List combinedParams = new ArrayList();
// We have params in both saved and wrapped requests so have to merge them
List wrappedParamsList = Arrays.asList(wrappedRequestParams);
List combinedParams = new ArrayList(wrappedParamsList);
if (wrappedRequestParams != null) {
combinedParams.addAll(Arrays.asList(wrappedRequestParams));
}
if (savedRequestParams != null) {
combinedParams.addAll(Arrays.asList(savedRequestParams));
// We want to add all parameters of the saved request *apart from* duplicates of those already added
for (int i = 0; i < savedRequestParams.length; i++) {
if (!wrappedParamsList.contains(savedRequestParams[i])) {
combinedParams.add(savedRequestParams[i]);
}
}
return (String[]) combinedParams.toArray(new String[combinedParams.size()]);
@@ -1,3 +1,5 @@
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-2.0.4.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
@@ -46,6 +46,7 @@ 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.
@@ -69,8 +70,8 @@ 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.
attribute manager-dn {xsd:string}?
## The password for the manager DN.
ldap-server.attlist &=
## 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
@@ -88,12 +89,13 @@ 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".
## 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".
@@ -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 =
@@ -258,7 +261,7 @@ 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 =
@@ -333,12 +336,13 @@ 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
@@ -371,7 +375,7 @@ 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 =
@@ -396,9 +400,9 @@ port-mappings.attlist &= empty
port-mapping =
element port-mapping {http-port, https-port}
http-port = attribute http {xsd:integer}
http-port = attribute http {xsd:string}
https-port = attribute https {xsd:integer}
https-port = attribute https {xsd:string}
x509 =
@@ -430,6 +434,7 @@ ap.attlist &=
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
@@ -496,6 +501,6 @@ 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
@@ -0,0 +1,53 @@
AuthByAdapterProvider.incorrectKey=Podana implementacja AuthByAdapter nie zawiera oczekiwanego klucza
BasicAclEntryAfterInvocationProvider.noPermission=U\u017cytkownik {0} nie posiada \u017bADNYCH uprawnie\u0144 do obiektu {1}
BasicAclEntryAfterInvocationProvider.insufficientPermission=U\u017cytkownik {0} nie posiada wymaganych uprawnie\u0144 do obiektu {1}
ConcurrentSessionControllerImpl.exceededAllowed=Maksymalna liczba sesji ({0}) dla tego u\u017cytkownika zosta\u0142a przekroczona
ProviderManager.providerNotFound=AuthenticationProvider dla {0} nie zosta\u0142 znaleziony
AnonymousAuthenticationProvider.incorrectKey=Podany AnonymousAuthenticationToken nie zawiera oczekiwanego klucza
CasAuthenticationProvider.incorrectKey=Podany CasAuthenticationToken nie zawiera oczekiwanego klucza
CasAuthenticationProvider.noServiceTicket=Dostarczenie biletu serwisu CAS do walidacji nie powiod\u0142o si\u0119
NamedCasProxyDecider.untrusted=Najbli\u017cszy serwer po\u015brednicz\u0105cy {0} jest niezaufany
RejectProxyTickets.reject=Bilety serwera po\u015brednicz\u0105cego zosta\u0142y odrzucone
AbstractSecurityInterceptor.authenticationNotFound=Obiekt Authentication nie zosta\u0142 odnaleziony w SecurityContext
AbstractUserDetailsAuthenticationProvider.onlySupports=Tylko UsernamePasswordAuthenticationToken jest obs\u0142ugiwany
AbstractUserDetailsAuthenticationProvider.locked=Konto u\u017cytkownika jest zablokowane
AbstractUserDetailsAuthenticationProvider.disabled=Konto u\u017cytkownika jest wy\u0142\u0105czone
AbstractUserDetailsAuthenticationProvider.expired=Wa\u017cno\u015b\u0107 konta u\u017cytkownika wygas\u0142a
AbstractUserDetailsAuthenticationProvider.credentialsExpired=Wa\u017cno\u015b\u0107 danych uwierzytelniaj\u0105cych wygas\u0142a
AbstractUserDetailsAuthenticationProvider.badCredentials=Niepoprawne dane uwierzytelniaj\u0105ce
X509AuthenticationProvider.certificateNull=Certyfikat jest pusty
DaoX509AuthoritiesPopulator.noMatching=Nie odnaleziono pasuj\u0105cego wzorca w subjectDN: {0}
RememberMeAuthenticationProvider.incorrectKey=Podany RememberMeAuthenticationToken nie zawiera oczekiwanego klucza
RunAsImplAuthenticationProvider.incorrectKey=Podany RunAsUserToken nie zawiera oczekiwanego klucza
DigestProcessingFilter.missingMandatory=Brakuje wymaganej warto\u015bci skr\u00f3tu; otrzymany nag\u0142\u00f3wek {0}
DigestProcessingFilter.missingAuth=Brakuje wymaganej warto\u015bci skr\u00f3tu dla 'auth' QOP; otrzymany nag\u0142\u00f3wek {0}
DigestProcessingFilter.incorrectRealm=Nazwa domeny {0} w odpowiedzi nie jest zgodna z nazw\u0105 domeny {1} w systemie
DigestProcessingFilter.nonceExpired=Wa\u017cno\u015b\u0107 kodu jednorazowego (nonce) wygas\u0142a
DigestProcessingFilter.nonceEncoding=Kod jednorazowy (nonce) nie jest zakodowany w Base64; otrzymany kod {0}
DigestProcessingFilter.nonceNotTwoTokens=Kod jednorazowy (nonce) powinien zawiera\u0107 dwie warto\u015bci {0}
DigestProcessingFilter.nonceNotNumeric=Pierwsza warto\u015b\u0107 kodu jednorazowego (nonce) nie jest warto\u015bci\u0105 numeryczn\u0105: {0}
DigestProcessingFilter.nonceCompromised=Niepoprawny kod jednorazowy (nonce) {0}
DigestProcessingFilter.usernameNotFound=Nazwa u\u017cytkownika {0} nie zosta\u0142a odnaleziona
DigestProcessingFilter.incorrectResponse=Niepoprawna odpowied\u017a
JdbcDaoImpl.notFound=Nazwa u\u017cytkownika {0} nie zosta\u0142a odnaleziona
JdbcDaoImpl.noAuthority=U\u017cytkownik {0} nie posiada \u017cadnych uprawnie\u0144 (GrantedAuthority)
SwitchUserProcessingFilter.noCurrentUser=\u017baden aktualny u\u017cytkownik nie jest powi\u0105zany z tym zapytaniem
SwitchUserProcessingFilter.noOriginalAuthentication=Nie mo\u017cna by\u0142o odnale\u017a\u0107 oryginalnego obiektu Authentication
SwitchUserProcessingFilter.usernameNotFound=Nazwa u\u017cytkownika {0} nie zosta\u0142a odnaleziona
SwitchUserProcessingFilter.locked=Konto u\u017cytkownika jest zablokowane
SwitchUserProcessingFilter.disabled=Konto u\u017cytkownika jest wy\u0142\u0105czone
SwitchUserProcessingFilter.expired=Wa\u017cno\u015b\u0107 konta u\u017cytkownika wygas\u0142a
SwitchUserProcessingFilter.credentialsExpired=Wa\u017cno\u015b\u0107 danych uwierzytelniaj\u0105cych wygas\u0142a
AbstractAccessDecisionManager.accessDenied=Dost\u0119p zabroniony
LdapAuthenticationProvider.emptyUsername=Pusta nazwa u\u017cytkownika jest niedozwolona
LdapAuthenticationProvider.emptyPassword=Niepoprawne dane uwierzytelniaj\u0105ce
DefaultIntitalDirContextFactory.communicationFailure=Po\u0142\u0105czenie z serwerem LDAP nie powiod\u0142o si\u0119
DefaultIntitalDirContextFactory.badCredentials=Niepoprawne dane uwierzytelniaj\u0105ce
DefaultIntitalDirContextFactory.unexpectedException=Nie mo\u017cna by\u0142o uzyska\u0107 InitialDirContext z powodu nieoczekiwanego wyj\u0105tku
PasswordComparisonAuthenticator.badCredentials=Niepoprawne dane uwierzytelniaj\u0105ce
BindAuthenticator.badCredentials=Niepoprawne dane uwierzytelniaj\u0105ce
BindAuthenticator.failedToLoadAttributes=Niepoprawne dane uwierzytelniaj\u0105ce
UserDetailsService.locked=Konto u\u017cytkownika jest zablokowane
UserDetailsService.disabled=Konto u\u017cytkownika jest wy\u0142\u0105czone
UserDetailsService.expired=Wa\u017cno\u015b\u0107 konta u\u017cytkownika wygas\u0142a
UserDetailsService.credentialsExpired=Wa\u017cno\u015b\u0107 danych uwierzytelniaj\u0105cych wygas\u0142a
@@ -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);
@@ -15,36 +15,36 @@ import org.springframework.security.intercept.web.FilterInvocation;
import org.springframework.security.util.InMemoryXmlApplicationContext;
/**
*
*
* @author Luke Taylor
* @version $Id$
*/
public class FilterInvocationDefinitionSourceParserTests {
private AbstractXmlApplicationContext appContext;
@After
public void closeAppContext() {
if (appContext != null) {
appContext.close();
appContext = null;
}
}
}
private void setContext(String context) {
appContext = new InMemoryXmlApplicationContext(context);
}
}
@Test
public void parsingMinimalConfigurationIsSuccessful() {
setContext(
"<filter-invocation-definition-source id='fids'>" +
" <intercept-url pattern='/**' access='ROLE_A'/>" +
"</filter-invocation-definition-source>");
" <intercept-url pattern='/**' access='ROLE_A'/>" +
"</filter-invocation-definition-source>");
DefaultFilterInvocationDefinitionSource fids = (DefaultFilterInvocationDefinitionSource) appContext.getBean("fids");
ConfigAttributeDefinition cad = fids.getAttributes(createFilterInvocation("/anything", "GET"));
assertTrue(cad.contains(new SecurityConfig("ROLE_A")));
}
@Test
public void parsingWithinFilterSecurityInterceptorIsSuccessful() {
setContext(
@@ -57,12 +57,12 @@ public class FilterInvocationDefinitionSourceParserTests {
" <intercept-url pattern='/**' access='ROLE_USER'/>" +
" </filter-invocation-definition-source>" +
" </b:property>" +
"</b:bean>" + HttpSecurityBeanDefinitionParserTests.AUTH_PROVIDER_XML);
"</b:bean>" + ConfigTestUtils.AUTH_PROVIDER_XML);
}
private FilterInvocation createFilterInvocation(String path, String method) {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI(null);
@@ -1,6 +1,7 @@
package org.springframework.security.config;
import static org.junit.Assert.*;
import static org.springframework.security.config.ConfigTestUtils.*;
import java.lang.reflect.Method;
import java.util.Iterator;
@@ -34,6 +35,7 @@ import org.springframework.security.ui.SessionFixationProtectionFilter;
import org.springframework.security.ui.WebAuthenticationDetails;
import org.springframework.security.ui.basicauth.BasicProcessingFilter;
import org.springframework.security.ui.logout.LogoutFilter;
import org.springframework.security.ui.logout.LogoutHandler;
import org.springframework.security.ui.preauth.x509.X509PreAuthenticatedProcessingFilter;
import org.springframework.security.ui.rememberme.NullRememberMeServices;
import org.springframework.security.ui.rememberme.PersistentTokenBasedRememberMeServices;
@@ -55,13 +57,7 @@ import org.springframework.util.ReflectionUtils;
*/
public class HttpSecurityBeanDefinitionParserTests {
private AbstractXmlApplicationContext appContext;
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-service>" +
" </authentication-provider>";
@After
public void closeAppContext() {
@@ -75,7 +71,7 @@ public class HttpSecurityBeanDefinitionParserTests {
public void minimalConfigurationParses() {
setContext("<http><http-basic /></http>" + AUTH_PROVIDER_XML);
}
@Test
public void httpAutoConfigSetsUpCorrectFilterList() throws Exception {
setContext("<http auto-config='true' />" + AUTH_PROVIDER_XML);
@@ -83,24 +79,26 @@ public class HttpSecurityBeanDefinitionParserTests {
List filterList = getFilters("/anyurl");
checkAutoConfigFilters(filterList);
assertEquals(true, FieldUtils.getFieldValue(appContext.getBean("_filterChainProxy"), "stripQueryStringFromUrls"));
assertEquals(true, FieldUtils.getFieldValue(filterList.get(10), "objectDefinitionSource.stripQueryStringFromUrls"));
}
@Test(expected=BeanDefinitionParsingException.class)
public void duplicateElementCausesError() throws Exception {
setContext("<http auto-config='true' /><http auto-config='true' />" + AUTH_PROVIDER_XML);
}
}
private void checkAutoConfigFilters(List filterList) throws Exception {
assertEquals("Expected 11 filters in chain", 11, filterList.size());
Iterator filters = filterList.iterator();
assertTrue(filters.next() instanceof HttpSessionContextIntegrationFilter);
assertTrue(filters.next() instanceof HttpSessionContextIntegrationFilter);
assertTrue(filters.next() instanceof LogoutFilter);
Object authProcFilter = filters.next();
assertTrue(authProcFilter instanceof AuthenticationProcessingFilter);
// Check RememberMeServices has been set on AuthenticationProcessingFilter
// Check RememberMeServices has been set on AuthenticationProcessingFilter
Object rms = FieldUtils.getFieldValue(authProcFilter, "rememberMeServices");
assertNotNull(rms);
assertTrue(rms instanceof RememberMeServices);
@@ -111,7 +109,7 @@ public class HttpSecurityBeanDefinitionParserTests {
assertTrue(filters.next() instanceof RememberMeProcessingFilter);
assertTrue(filters.next() instanceof AnonymousProcessingFilter);
assertTrue(filters.next() instanceof ExceptionTranslationFilter);
assertTrue(filters.next() instanceof SessionFixationProtectionFilter);
assertTrue(filters.next() instanceof SessionFixationProtectionFilter);
Object fsiObj = filters.next();
assertTrue(fsiObj instanceof FilterSecurityInterceptor);
FilterSecurityInterceptor fsi = (FilterSecurityInterceptor) fsiObj;
@@ -140,6 +138,7 @@ public class HttpSecurityBeanDefinitionParserTests {
// This will be matched by the default pattern ".*"
List allFilters = getFilters("/ImCaughtByTheUniversalMatchPattern");
checkAutoConfigFilters(allFilters);
assertEquals(false, FieldUtils.getFieldValue(appContext.getBean("_filterChainProxy"), "stripQueryStringFromUrls"));
assertEquals(false, FieldUtils.getFieldValue(allFilters.get(10), "objectDefinitionSource.stripQueryStringFromUrls"));
}
@@ -153,7 +152,6 @@ public class HttpSecurityBeanDefinitionParserTests {
// These will be matched by the default pattern "/**"
checkAutoConfigFilters(getFilters("/secure"));
checkAutoConfigFilters(getFilters("/ImCaughtByTheUniversalMatchPattern"));
}
@Test
@@ -184,34 +182,34 @@ public class HttpSecurityBeanDefinitionParserTests {
"<http>" +
" <form-login login-page='noLeadingSlash'/>" +
"</http>" + AUTH_PROVIDER_XML);
}
}
@Test(expected=BeanCreationException.class)
public void invalidDefaultTargetUrlIsDetected() throws Exception {
setContext(
"<http>" +
" <form-login default-target-url='noLeadingSlash'/>" +
"</http>" + AUTH_PROVIDER_XML);
}
}
@Test(expected=BeanCreationException.class)
public void invalidLogoutUrlIsDetected() throws Exception {
setContext(
"<http>" +
" <logout logout-url='noLeadingSlash'/>" +
" <logout logout-url='noLeadingSlash'/>" +
" <form-login />" +
"</http>" + AUTH_PROVIDER_XML);
}
}
@Test(expected=BeanCreationException.class)
public void invalidLogoutSuccessUrlIsDetected() throws Exception {
setContext(
"<http>" +
" <logout logout-success-url='noLeadingSlash'/>" +
" <logout logout-success-url='noLeadingSlash'/>" +
" <form-login />" +
"</http>" + AUTH_PROVIDER_XML);
}
}
@Test
public void lowerCaseComparisonIsRespectedBySecurityFilterInvocationDefinitionSource() throws Exception {
setContext(
@@ -253,27 +251,27 @@ public class HttpSecurityBeanDefinitionParserTests {
public void oncePerRequestAttributeIsSupported() throws Exception {
setContext("<http once-per-request='false'><http-basic /></http>" + AUTH_PROVIDER_XML);
List filters = getFilters("/someurl");
FilterSecurityInterceptor fsi = (FilterSecurityInterceptor) filters.get(filters.size() - 1);
assertFalse(fsi.isObserveOncePerRequest());
}
@Test
public void accessDeniedPageAttributeIsSupported() throws Exception {
setContext("<http access-denied-page='/access-denied'><http-basic /></http>" + AUTH_PROVIDER_XML);
List filters = getFilters("/someurl");
ExceptionTranslationFilter etf = (ExceptionTranslationFilter) filters.get(filters.size() - 3);
assertEquals("/access-denied", FieldUtils.getFieldValue(etf, "accessDeniedHandler.errorPage"));
}
@Test(expected=BeanDefinitionStoreException.class)
public void invalidAccessDeniedUrlIsDetected() throws Exception {
setContext("<http auto-config='true' access-denied-page='noLeadingSlash'/>" + AUTH_PROVIDER_XML);
}
}
@Test
public void interceptUrlWithRequiresChannelAddsChannelFilterToStack() throws Exception {
setContext(
@@ -302,6 +300,24 @@ public class HttpSecurityBeanDefinitionParserTests {
assertEquals(Integer.valueOf(9443), pm.lookupHttpsPort(9080));
}
@Test
public void portMappingsWorkWithPlaceholders() throws Exception {
System.setProperty("http", "9080");
System.setProperty("https", "9443");
setContext(
" <b:bean id='configurer' class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
" <http auto-config='true'>" +
" <port-mappings>" +
" <port-mapping http='${http}' https='${https}'/>" +
" </port-mappings>" +
" </http>" + AUTH_PROVIDER_XML);
PortMapperImpl pm = (PortMapperImpl) appContext.getBean(BeanIds.PORT_MAPPER);
assertEquals(1, pm.getTranslatedPortMappings().size());
assertEquals(Integer.valueOf(9080), pm.lookupHttpPort(9443));
assertEquals(Integer.valueOf(9443), pm.lookupHttpsPort(9080));
}
@Test
public void externalFiltersAreTreatedCorrectly() throws Exception {
// Decorated user-filters should be added to stack. The others should be ignored.
@@ -312,21 +328,21 @@ public class HttpSecurityBeanDefinitionParserTests {
"</b:bean>" +
"<b:bean id='userFilter1' class='org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter'>" +
" <custom-filter before='SESSION_CONTEXT_INTEGRATION_FILTER'/>" +
"</b:bean>" +
"</b:bean>" +
"<b:bean id='userFilter2' class='org.springframework.security.util.MockFilter'>" +
" <custom-filter position='FIRST'/>" +
"</b:bean>" +
"</b:bean>" +
"<b:bean id='userFilter3' class='org.springframework.security.util.MockFilter'/>" +
"<b:bean id='userFilter4' class='org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter'/>"
);
List filters = getFilters("/someurl");
assertEquals(14, filters.size());
assertTrue(filters.get(0) instanceof MockFilter);
assertTrue(filters.get(0) instanceof MockFilter);
assertTrue(filters.get(1) instanceof SecurityContextHolderAwareRequestFilter);
assertTrue(filters.get(4) instanceof SecurityContextHolderAwareRequestFilter);
}
@Test(expected=BeanCreationException.class)
public void twoFiltersWithSameOrderAreRejected() {
setContext(
@@ -345,10 +361,25 @@ public class HttpSecurityBeanDefinitionParserTests {
"<b:bean id='tokenRepo' " +
"class='org.springframework.security.ui.rememberme.InMemoryTokenRepositoryImpl'/> " + AUTH_PROVIDER_XML);
Object rememberMeServices = appContext.getBean(BeanIds.REMEMBER_ME_SERVICES);
assertTrue(rememberMeServices instanceof PersistentTokenBasedRememberMeServices);
}
@Test
public void rememberMeServiceWorksWithDataSourceRef() {
setContext(
"<http auto-config='true'>" +
" <remember-me data-source-ref='ds'/>" +
"</http>" +
"<b:bean id='ds' class='org.springframework.security.TestDataSource'> " +
" <b:constructor-arg value='tokendb'/>" +
"</b:bean>" + AUTH_PROVIDER_XML);
Object rememberMeServices = appContext.getBean(BeanIds.REMEMBER_ME_SERVICES);
assertTrue(rememberMeServices instanceof PersistentTokenBasedRememberMeServices);
}
@Test
public void rememberMeServiceWorksWithExternalServicesImpl() throws Exception {
setContext(
@@ -361,9 +392,13 @@ public class HttpSecurityBeanDefinitionParserTests {
" <b:property name='tokenValiditySeconds' value='5000'/>" +
"</b:bean>" +
AUTH_PROVIDER_XML);
assertEquals(5000, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES),
"tokenValiditySeconds"));
assertEquals(5000, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES),
"tokenValiditySeconds"));
// SEC-909
LogoutHandler[] logoutHandlers = (LogoutHandler[]) FieldUtils.getFieldValue(appContext.getBean(BeanIds.LOGOUT_FILTER), "handlers");
assertEquals(2, logoutHandlers.length);
assertEquals(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES), logoutHandlers[1]);
}
@Test
@@ -372,10 +407,10 @@ public class HttpSecurityBeanDefinitionParserTests {
"<http auto-config='true'>" +
" <remember-me key='ourkey' token-validity-seconds='10000' />" +
"</http>" + AUTH_PROVIDER_XML);
assertEquals(10000, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES),
"tokenValiditySeconds"));
}
assertEquals(10000, FieldUtils.getFieldValue(appContext.getBean(BeanIds.REMEMBER_ME_SERVICES),
"tokenValiditySeconds"));
}
@Test
public void rememberMeServiceConfigurationParsesWithCustomUserService() {
setContext(
@@ -385,8 +420,8 @@ public class HttpSecurityBeanDefinitionParserTests {
"<b:bean id='userService' class='org.springframework.security.userdetails.MockUserDetailsService'/> " +
AUTH_PROVIDER_XML);
// AbstractRememberMeServices rememberMeServices = (AbstractRememberMeServices) appContext.getBean(BeanIds.REMEMBER_ME_SERVICES);
}
}
@Test
public void x509SupportAddsFilterAtExpectedPosition() throws Exception {
setContext(
@@ -405,11 +440,11 @@ public class HttpSecurityBeanDefinitionParserTests {
" <concurrent-session-control session-registry-alias='seshRegistry' expired-url='/expired'/>" +
"</http>" + AUTH_PROVIDER_XML);
List filters = getFilters("/someurl");
assertTrue(filters.get(0) instanceof ConcurrentSessionFilter);
assertTrue(filters.get(0) instanceof ConcurrentSessionFilter);
assertNotNull(appContext.getBean("seshRegistry"));
assertNotNull(appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER));
}
}
@Test
public void externalSessionRegistryBeanIsConfiguredCorrectly() throws Exception {
@@ -421,12 +456,12 @@ public class HttpSecurityBeanDefinitionParserTests {
AUTH_PROVIDER_XML);
Object sessionRegistry = appContext.getBean("seshRegistry");
Object sessionRegistryFromFilter = FieldUtils.getFieldValue(
appContext.getBean(BeanIds.CONCURRENT_SESSION_FILTER),"sessionRegistry");
appContext.getBean(BeanIds.CONCURRENT_SESSION_FILTER),"sessionRegistry");
Object sessionRegistryFromController = FieldUtils.getFieldValue(
appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER),"sessionRegistry");
appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER),"sessionRegistry");
Object sessionRegistryFromFixationFilter = FieldUtils.getFieldValue(
appContext.getBean(BeanIds.SESSION_FIXATION_PROTECTION_FILTER),"sessionRegistry");
appContext.getBean(BeanIds.SESSION_FIXATION_PROTECTION_FILTER),"sessionRegistry");
assertSame(sessionRegistry, sessionRegistryFromFilter);
assertSame(sessionRegistry, sessionRegistryFromController);
assertSame(sessionRegistry, sessionRegistryFromFixationFilter);
@@ -458,8 +493,8 @@ public class HttpSecurityBeanDefinitionParserTests {
" </b:property>" +
"</b:bean>" +
"<authentication-manager alias='authManager' session-controller-ref='sc'/>" + AUTH_PROVIDER_XML);
}
}
@Test(expected=ConcurrentLoginException.class)
public void concurrentSessionMaxSessionsIsCorrectlyConfigured() throws Exception {
setContext(
@@ -473,16 +508,16 @@ public class HttpSecurityBeanDefinitionParserTests {
req.setSession(new MockHttpSession());
auth.setDetails(new WebAuthenticationDetails(req));
try {
seshController.checkAuthenticationAllowed(auth);
seshController.checkAuthenticationAllowed(auth);
} catch (ConcurrentLoginException e) {
fail("First login should be allowed");
}
fail("First login should be allowed");
}
seshController.registerSuccessfulAuthentication(auth);
req.setSession(new MockHttpSession());
try {
seshController.checkAuthenticationAllowed(auth);
seshController.checkAuthenticationAllowed(auth);
} catch (ConcurrentLoginException e) {
fail("Second login should be allowed");
fail("Second login should be allowed");
}
auth.setDetails(new WebAuthenticationDetails(req));
seshController.registerSuccessfulAuthentication(auth);
@@ -499,10 +534,10 @@ public class HttpSecurityBeanDefinitionParserTests {
" <b:constructor-arg value='/customlogin'/>" +
"</b:bean>" + AUTH_PROVIDER_XML);
ExceptionTranslationFilter etf = (ExceptionTranslationFilter) getFilters("/someurl").get(8);
assertTrue("ExceptionTranslationFilter should be configured with custom entry point",
assertTrue("ExceptionTranslationFilter should be configured with custom entry point",
etf.getAuthenticationEntryPoint() instanceof MockAuthenticationEntryPoint);
}
@Test
/** SEC-742 */
public void rememberMeServicesWorksWithoutBasicProcessingFilter() {
@@ -523,7 +558,7 @@ public class HttpSecurityBeanDefinitionParserTests {
assertFalse(filters.get(1) instanceof SessionFixationProtectionFilter);
}
/**
* See SEC-750. If the http security post processor causes beans to be instantiated too eagerly, they way miss
* additional processing. In this method we have a UserDetailsService which is referenced from the namespace
@@ -542,18 +577,18 @@ public class HttpSecurityBeanDefinitionParserTests {
assertEquals("Hello from the post processor!", service.getPostProcessorWasHere());
}
/**
* SEC-795. Two methods that exercise the scenarios that will or won't result in a protected login page warning.
* Check the log.
*/
@Test
public void unprotectedLoginPageDoesntResultInWarning() {
// Anonymous access configured
// Anonymous access configured
setContext(
" <http>" +
" <intercept-url pattern='/login.jsp*' access='IS_AUTHENTICATED_ANONYMOUSLY'/>" +
" <intercept-url pattern='/**' access='ROLE_A'/>" +
" <intercept-url pattern='/**' access='ROLE_A'/>" +
" <anonymous />" +
" <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
" </http>" + AUTH_PROVIDER_XML);
@@ -565,9 +600,9 @@ public class HttpSecurityBeanDefinitionParserTests {
" <intercept-url pattern='/**' access='ROLE_A'/>" +
" <anonymous />" +
" <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
" </http>" + AUTH_PROVIDER_XML);
" </http>" + AUTH_PROVIDER_XML);
}
@Test
public void protectedLoginPageResultsInWarning() {
// Protected, no anonymous filter configured.
@@ -586,6 +621,36 @@ public class HttpSecurityBeanDefinitionParserTests {
" </http>" + AUTH_PROVIDER_XML);
}
@Test
public void settingCreateSessionToAlwaysSetsFilterPropertiesCorrectly() throws Exception {
setContext("<http auto-config='true' create-session='always'/>" + AUTH_PROVIDER_XML);
assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(appContext.getBean(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER), "forceEagerSessionCreation"));
assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(appContext.getBean(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER), "allowSessionCreation"));
}
@Test
public void settingCreateSessionToNeverSetsFilterPropertiesCorrectly() throws Exception {
setContext("<http auto-config='true' create-session='never'/>" + AUTH_PROVIDER_XML);
assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(appContext.getBean(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER), "forceEagerSessionCreation"));
assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(appContext.getBean(BeanIds.HTTP_SESSION_CONTEXT_INTEGRATION_FILTER), "allowSessionCreation"));
}
/* SEC-934 */
@Test
public void supportsTwoIdenticalInterceptUrls() {
setContext(
"<http auto-config='true'>" +
" <intercept-url pattern='/someurl' access='ROLE_A'/>" +
" <intercept-url pattern='/someurl' access='ROLE_B'/>" +
"</http>" + AUTH_PROVIDER_XML);
FilterSecurityInterceptor fis = (FilterSecurityInterceptor) appContext.getBean(BeanIds.FILTER_SECURITY_INTERCEPTOR);
FilterInvocationDefinitionSource fids = fis.getObjectDefinitionSource();
ConfigAttributeDefinition attrDef = fids.getAttributes(createFilterinvocation("/someurl", null));
assertEquals(1, attrDef.getConfigAttributes().size());
assertTrue(attrDef.contains(new SecurityConfig("ROLE_B")));
}
private void setContext(String context) {
appContext = new InMemoryXmlApplicationContext(context);
}

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