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

Compare commits

...

196 Commits

Author SHA1 Message Date
Spring Buildmaster 902b8c1a5e Release version 3.0.8.RELEASE 2012-10-08 15:38:46 -07:00
Rob Winch 915b2acf73 SEC-2056: DaoAuthenticationProvider performs isPasswordValid when user not found
Previously authenticating a user could take significantly longer than
determining that a user does not exist. This was due to the fact that only
users that were found would use the password encoder and comparing a
password can take a significant amount of time. The difference in the
time required could allow a side channel attack that reveals if a user
exists.

The code has been updated to do comparison against a dummy password
even when the the user was not found.

Conflicts:

	core/src/main/java/org/springframework/security/authentication/dao/DaoAuthenticationProvider.java
2012-10-08 07:45:02 -05:00
Rob Winch c3f5f4686e Added SCM information to pom for OSS requirements 2012-10-08 07:44:24 -05:00
Rob Winch 4c9a13a755 SEC-2031: PreInvocationAuthorizationAdviceVoter supports subclasses 2012-10-07 11:59:43 -05:00
Rob Winch dc201b7989 Remove log4jConfigLocation from sample web.xml files
This prevents errors looking for the LogManager which is no longer
on the classpath since we use sl4j.
2012-10-06 10:15:35 -05:00
Rob Winch fb227b5433 SEC-2025: SecurityContextLogoutHandler removes Authentication from SecurityContext
Previously there was a race condition could occur when the user attempts to access
a slow resource and then logs out which would result in the user not being logged
out.

SecurityContextLogoutHandler will now remove the Authentication from the
SecurityContext to protect against this scenario.
2012-10-05 14:18:19 -05:00
Rob Winch aa489f7ff6 SEC-1882: Velocity AuthzImpl now works with Spring 3.0.6+ 2012-10-05 11:09:10 -05:00
Rob Winch 70d5ba536e SEC-2057: ConcurrentSessionFilter is now after SecurityContextPersistenceFilter
Previously, ConcurrentSessionFilter was placed after SecurityContextPersistenceFilter
which meant that the SecurityContextHolder was empty when ConcurrentSessionFilter was
invoked. This caused the Authentication to be null when performing a logout. It also
caused complications with LogoutHandler implementations that would be accessing the
SecurityContextHolder and potentially clear it out expecting that
SecurityContextPersistenceFilter would then clear the SecurityContextRepository.

The ConcurrentSessionFilter is now positioned after the
SecurityContextPersistenceFilter to ensure that the SecurityContextHolder is populated
and cleared out appropriately.
2012-10-03 14:04:24 -05:00
Rob Winch d50184deda SEC-1753: Cater for missing DiscoveryInformation object in OpenID4JavaConsumer.endConsumption. 2012-10-02 16:37:25 -05:00
Rob Winch 5c4f4cbe4d SEC-2061: Fix typo in messages.properties 2012-10-02 16:26:05 -05:00
Rob Winch b192680df3 removed maven.gradle in favor of maven-deployment.gradle 2012-10-02 13:55:34 -05:00
Rob Winch 95d0e08059 Eclipse Project names include 3.0.x suffix 2012-10-02 12:05:18 -05:00
Rob Winch 4f993d95b5 Updates for 3.0.x autorepo support 2012-10-02 11:20:40 -05:00
Rob Winch 4c832fc946 SEC-2038: AbstractPreAuthenticationFilter afterPropertiesSet invokes super 2012-09-21 15:23:42 -05:00
Rob Winch 5945abb10a Revert "SEC-2045: AbstractPreAuthenticationFilter afterPropertiesSet invokes super"
This commit contains the wrong JIRA ID.

This reverts commit c53fd99430.
2012-09-21 15:23:42 -05:00
Rob Winch 8c224f39dc SEC-2045: AbstractPreAuthenticationFilter afterPropertiesSet invokes super 2012-09-21 14:52:42 -05:00
Rob Winch f0a6b7ca27 SEC-2041: SaveContextServletOutputStream/SaveContextPrintWriter delegate all methods 2012-09-21 14:51:32 -05:00
Rob Winch 0350c2833e SEC-2055: SaveContextServletOutputStream flush/close delegates to original ServletOutputStream instead of using super 2012-09-21 14:51:18 -05:00
Rob Winch 7406e03306 SEC-1975: Ignore anonymous users for AuthenticationSimpleHttpInvokerRequestExecutor
Previously anonymous authentication was submitted as credentials over the wire which
caused the applications to attempt to authenticate the anonymous user.

Now if the user is anonymous (determined by the AuthenticationTrustResolver), the
AuthenticationSimpleHttpInvokerRequestExecutor does not populate any credentials.
2012-08-09 10:04:03 -05:00
Rob Winch ca3c1979b8 SEC-2005: Ensure SecurityContext saved prior to the response being committed
Previously Spring Security did not save the Security Context immediately prior
to the following methods being invoked:

   - HttpServletResonse.flushBuffer()
   - HttpServletResonse.getWriter().close()
   - HttpServletResonse.getWriter().flush()
   - HttpServletRespose.getOutputStream().close()
   - HttpServletRespose.getOutputStream().flush()

This meant that the client could get a response prior to the SecurityContext
being stored. After the client got the response, it would make another request
and this would not yet be authenticated. The reason this can occur is because
all of the above methods commit the response, which means that the server can
signal to the client the response is completed. A similar issue happened in
SEC-398.

Now the previously listed methods are wrapped in order to ensure the SecurityContext
is persisted prior to the response being committed.
2012-08-09 10:03:48 -05:00
Rob Winch c9facdd993 SEC-2013: Add space to log of AbstractAuthenticationProcessingFilter 2012-07-19 16:13:33 -05:00
Rob Winch d2e6343295 SEC-1968: AbstractPreAuthenticatedProcessingFilter clears SecurityContext on null principal change with invalidateSessionOnPrincipalChange = true 2012-06-27 15:46:10 -05:00
Rob Winch 31338a7bdb SEC-1875: ConcurrentSessionControlStrategy no longer adds/removes the session to the SessionRegistry twice
This fixes two issues introduced by SEC-1229

 * SessionRegistry.registerNewSession is invoked twice

 * SessionRegistry.removeSession is invoked twice (once by the
ConcurrentSessionControlStrategy#onSessionChange and once by
SessionRegistryImpl#onApplicationEvent). This is not nearly
as problematic since the interface states that implementations
should be handle removing the session twice. However, as removing
twice requires an unnecessary database hit we should only remove
sessions once.
2012-06-26 16:39:08 -05:00
Rob Winch 7714c5cd02 .gitignore bin and */src/*/java/META-INF 2012-06-15 14:54:48 -05:00
Rob Winch 5ed5590268 SEC-1970: Cleanup of pre authentication documentation
* Removed custom-authentication-provider from documentation
* Rephrased to make the pre authentication documentation a little more concise
* Removed nested () within text (not code)
* Removed user which should have been use
2012-06-15 14:51:50 -05:00
Rob Winch 5dd6b4a77a SEC-1865: Remove invalid OWASP link in TextEscapeUtils 2012-06-11 16:36:25 -05:00
Rob Winch 5118e0b86e SEC-1943: Corrected namespace doc to state SecurityContextHolderAwareRequestFilter instead of SecurityContextHolderAwareFilter 2012-03-20 19:22:54 -05:00
Rob Winch 21f2991ab4 Call SecurityContextHolder.clearContext() in tear down of HttpSessionSecurityContextRepositoryTests 2011-12-30 16:31:37 -06:00
Rob Winch 3679227b11 SEC-1735: Do not remove SecurityContext from HttpSession when anonymous Authentication is saved if original SecurityContext was anonymous 2011-12-30 16:31:31 -06:00
Rob Winch 25e17c1568 SEC-1881: Configure surefire to include **/*Test.class to avoid accidentally not running new tests that end in Test 2011-12-30 12:53:33 -06:00
Rob Winch 9847366d5e SEC-1881: Renamed **/*Test.java to **/*Tests.java since **/*Test.java are not included in surefire configuration
NOTE: Some tests no longer pass and thus are being ignored until SEC-1882 is fixed. This is still better than
the previous situation since before all the tests ending in Test.java were ignored and this ensures that most of
these tests will be ran with the build.
2011-12-30 12:46:41 -06:00
Rob Winch 7cb472f105 SEC-1880: Corrected error message when using both logout-success-url and success-handler-ref 2011-12-30 11:35:48 -06:00
Rob Winch 863b36962b SEC-1878: Added test to ensure that DefaultFilterChainValidator can handle web expressions 2011-12-28 16:24:48 -06:00
Rob Winch bbfb3da9c7 Updated to maven-resources-plugin 2.4
This is to fix an error when using the latest m2e plugin that states: 'maven-resources-plugin prior to 2.4 is not supported by m2e'
2011-12-28 15:20:06 -06:00
Luke Taylor b1af3d00ee SEC-1857: Use Principal.getName() in ContextPropagatingRemoteInvocation
This is a better option than using the toString() method
where the latter doesn't return the username. e.g when the
principal is a UserDetails.
2011-12-05 21:24:28 +00:00
Luke Taylor daa7f3f64e SEC-1848: LDAP encode name when using user DN patterns in AbstractLdapAuthenticator. 2011-11-01 13:30:44 +00:00
Rob Winch 7a3135f0f9 SEC-1839: Updated preauth example to use </security:authentication-manager> instead of </security-authentication-manager> 2011-10-18 19:19:27 -05:00
Luke Taylor 82163e2546 Remove ancient code formatter artifacts. 2011-09-25 21:20:02 +01:00
Luke Taylor 2d27b28199 Set version to 3.0.8.CI-SNAPSHOT. 2011-09-05 23:04:06 +01:00
Luke Taylor 714ee3e960 Set version to 3.0.7.RELEASE. 2011-09-05 23:03:17 +01:00
Luke Taylor ee74c4ced2 SEC-1803: Add check in AbstractAuthenticationTargetUrlRequestHandler for null targetUrlParameter before attempting to read it from the request. Prevents NPE when targetUrlParameter is not set. 2011-08-29 13:47:31 +01:00
Luke Taylor 102027a44c SEC-1804: Updated Javadoc wrt immutability of User class. 2011-08-25 11:10:41 +01:00
Luke Taylor 799a43d72e SEC-1804: Update InMemoryDaoImpl to use User class directly and create a copy. Otherwise credentials are cleared on cached user instances. 2011-08-25 11:09:02 +01:00
Luke Taylor 3dc4158f7d Set version to 3.0.7.CI-SNAPSHOT 2011-08-19 12:52:39 -07:00
Luke Taylor 62f70f17ff Set project release version to 3.0.6.RELEASE 2011-08-19 12:47:55 -07:00
Luke Taylor 4b0fbe1606 Remove session timeout check in tutorial sample. 2011-08-19 12:47:06 -07:00
Luke Taylor a8bce41876 SEC-1795: Fix possible NPEs in AclImpl.equals() 2011-08-19 12:03:04 -07:00
Luke Taylor cea1f4499f SEC-1686: Upgrade to Spring 3.0.6 2011-08-19 10:15:48 -07:00
Luke Taylor c19a5ffd73 SEC-1796: Check for annotated annotations at class/interface level. Previously only the specific security annotation was checked for. By delegating to Spring's AnnotationUtils, custom annotations carrying the security annotation are also detected. 2011-08-12 14:36:42 +01:00
Luke Taylor 594ee9515e Taglib test fixes to take latest SFW changes into account. 2011-08-11 23:44:01 +01:00
Luke Taylor a087e828a6 SEC-1790: Disable use of spring-security-redirect by default for SimpleUrlLogoutSuccesshandler. 2011-08-05 16:54:35 +01:00
Luke Taylor 5238ba0e26 SEC-1790: Reject redirect locations containing CR or LF. 2011-07-29 16:34:48 +01:00
Luke Taylor 887e3361d2 SEC-1750: Make sure RunAs replacement is constrained to the SecurityContext of the current thread. 2011-07-29 16:32:40 +01:00
Luke Taylor a24570ae06 SEC-1744: Do not trust authorities contained in the authentication request in JaasAuthenticationProvider. 2011-07-29 16:32:40 +01:00
Luke Taylor ba719dc0e1 SEC-1741: Modify ContextPropagatingRemoteInvocation to pass a simple combination of principal/credentials as Strings, rather than serializing the whole SecurityContext object from the client. 2011-07-29 16:32:40 +01:00
Luke Taylor 28e70db8f2 SEC-1742: Deprecate use of extraInformation field in AuthenticationException, making it transient and removing any sensitive data in UserDetails objects which are stored in it. 2011-07-29 16:32:40 +01:00
Rob Winch 84031c6001 SEC-1792: Fixed NullPointerException in RunAsUserToken#toString() 2011-07-29 10:00:37 -05:00
Luke Taylor ca2af8bc59 SEC-1770: Call refreshLastRequest on the session registry rather than the SessionInformation object to make sure it works with alternative SessionRegistry implementations. 2011-07-13 20:57:18 +01:00
Luke Taylor 6f59805ef3 SEC-1782: Javadoc correction for LdapAuthenticationProvider. 2011-07-12 01:51:42 +01:00
Rob Winch f359bed596 SEC-1777: Corrected log in HttpSessionSecurityContextRepository to reference itself instead of HttpSessionContextIntegrationFilter 2011-07-09 19:27:59 -05:00
Florian Fankhauser 0f1ae574ab SEC-1776: Corrected typo in manual 2011-07-09 19:26:29 -05:00
Luke Taylor cb7a94af88 SEC-1768: Use AopProxyUtils.ultimateTargetClass to cater for situation where security interceptor is applied to a proxy. 2011-06-18 14:46:28 +01:00
Luke Taylor 9b8d2719a6 SEC-1686: Up required minimum version to 3.0.6 in version check. 2011-06-18 14:45:23 +01:00
Luke Taylor 73b67da3a8 SEC-1762: Fix input value assertion check for targetUrlParameter. 2011-06-17 13:43:15 +01:00
Luke Taylor b5546d1d29 SEC-1764: Remove use of Java 6 method Arrays.copyOfRange. 2011-06-15 11:18:26 +01:00
Luke Taylor 70ca0d1a39 SEC-1764: Ensure password encoders use UTF-8 charset when creating strings from byte arrays. 2011-06-14 20:15:34 +01:00
Luke Taylor 7a5a062cd0 SEC-1764: Backport Utf8 encoder to 3.0.x 2011-06-14 20:11:03 +01:00
Luke Taylor 977da0da1f SEC-1733: Support explicit zero netmask correctly. 2011-06-07 16:47:22 +01:00
Luke Taylor dfbc938e99 Added note in namespace docs on mismatch between using filters="none" and other attributes. 2011-06-06 12:37:52 +01:00
Rob Winch d5f1f6cbff SEC-1757: Updated tutorial sample to state that listing of accounts is allowed by anyone and to display accounts for the different types of access to posting to Accounts 2011-06-02 21:20:27 -05:00
Luke Taylor a2cdbab50c SEC-1747: Upgrade to Spring LDAP 1.3.1 2011-05-17 23:40:07 +01:00
Luke Taylor 1833b234a5 SEC-1722: Correct javadoc 2011-04-22 11:51:46 +01:00
Luke Taylor 6c97fccc91 SEC-1700: Allow for case where JAAS config is not a simple file, but may be a jar resource, for example. 2011-04-20 14:53:22 +01:00
Luke Taylor 2888f2b86f SEC-1720: Avoid bean-creation side-effects in ContextSourceSettingPostProcessor. 2011-04-20 13:00:56 +01:00
Luke Taylor 04d42211b1 SEC-1705: Make sure a single OpenIDAuthenticationFilter bean is created by the namespace. Likewise for UsernamePasswordAuthenticationFilter. 2011-03-31 22:03:27 +01:00
Rob Winch 6a87a5f1a1 SEC-1703: Updated namespace for intercept-url 2011-03-29 21:59:07 -05:00
Rob Winch f6b21880a2 SEC-1703: Updated cas custom-filter@ref to match example bean id and custom-filter@position to be CAS_FILTER 2011-03-29 20:18:01 -05:00
Luke Taylor 198d5d0482 SEC-1701: Trim claimed identity parameter value before submitting to OpenID4Java. 2011-03-25 19:11:34 +00:00
Rob Winch acee3e2593 SEC-1698: Update documentation to use correct package for RequestHeaderAuthenticationFilter 2011-03-16 23:53:47 -05:00
Luke Taylor b87dabe1ac SEC-1683: Corrected typo 2011-02-28 15:44:53 +00:00
Luke Taylor f509193604 Update Base64 implementation to include fixes (using diff) from the original up to version 2.3.7. 2011-02-16 15:58:28 +00:00
Luke Taylor 11a091f051 SEC-1680: Revert accidental updates to 3.0.x namespace appendix. 2011-02-16 15:01:15 +00:00
Luke Taylor 8e48658efb SEC-1675: Added missing "body-content" elements to taglib descriptor. 2011-02-14 21:31:15 +00:00
Rob Winch afd556412e SEC-1672: Provide error message when ambiguous configuration of intercept-url contains attributes filters=none and (access or requires-channel) 2011-02-09 20:37:03 -06:00
Luke Taylor 187a530760 SEC-1670: Take account of JNDI CompositeName escaping in value of SearchResult.getName() when performing a search for a user entry in SpringSecurityLdapTemplate. 2011-02-03 18:00:03 +00:00
Rob Winch 1b6587a5d4 SEC-1666: Use constant time comparison for sensitive data.
Constant time comparison helps to mitigate timing attacks. See the following link for more information

 * http://rdist.root.org/2010/07/19/exploiting-remote-timing-attacks/
 * http://en.wikipedia.org/wiki/Timing_attack for more information.
2011-01-31 23:21:38 -06:00
Rob Winch ece824fca2 SEC-1592: Updated CasAuthenticationFilter so that it does not continue FilterChain when handling proxy requests.
The fix moves CommonUtils.readAndRespondToProxyReceptorRequest into CasAuthenticationFilter.attemptAuthentication. This makes sense since
The CAS server is authenticating that the proxy url is valid (i.e. it exists and the SSL handshake succeeds). It also allows the FilterChain
to not be processed by returning a null Authentication.
2011-01-27 10:49:24 -06:00
Luke Taylor e3644e2d27 SEC-1661: Use a DistinguishedName to wrap the search base to avoid the need for JNDI escaping. 2011-01-26 17:20:54 +00:00
Rob Winch b3943ac268 SEC-1545: Removed unused i18n keys, changed keys to follow naming conventions, found missing keys based upon old keys, sorted keys, any unknown keys are entered as a comment with the English value.
NOTE: The Groovy code that automated most of this is attached to SEC-1545

A mapping of Missing Key to the file that the key is found are as follows:

----------../core/src/main/resources/org/springframework/security/messages_cs_CZ.properties----------
JdbcDaoImpl.noAuthority=[../core/src/main/java/org/springframework/security/core/userdetails/jdbc/JdbcDaoImpl.java]
JdbcDaoImpl.notFound=[../core/src/main/java/org/springframework/security/core/userdetails/jdbc/JdbcDaoImpl.java]
PersistentTokenBasedRememberMeServices.cookieStolen=[../web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java]
----------../core/src/main/resources/org/springframework/security/messages_de.properties----------
JdbcDaoImpl.noAuthority=[../core/src/main/java/org/springframework/security/core/userdetails/jdbc/JdbcDaoImpl.java]
JdbcDaoImpl.notFound=[../core/src/main/java/org/springframework/security/core/userdetails/jdbc/JdbcDaoImpl.java]
PersistentTokenBasedRememberMeServices.cookieStolen=[../web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java]
----------../core/src/main/resources/org/springframework/security/messages_it.properties----------
JdbcDaoImpl.noAuthority=[../core/src/main/java/org/springframework/security/core/userdetails/jdbc/JdbcDaoImpl.java]
JdbcDaoImpl.notFound=[../core/src/main/java/org/springframework/security/core/userdetails/jdbc/JdbcDaoImpl.java]
PersistentTokenBasedRememberMeServices.cookieStolen=[../web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java]
----------../core/src/main/resources/org/springframework/security/messages_ko_KR.properties----------
PersistentTokenBasedRememberMeServices.cookieStolen=[../web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java]
----------../core/src/main/resources/org/springframework/security/messages_pl.properties----------
PersistentTokenBasedRememberMeServices.cookieStolen=[../web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java]
----------../core/src/main/resources/org/springframework/security/messages_pt_BR.properties----------
PersistentTokenBasedRememberMeServices.cookieStolen=[../web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java]
----------../core/src/main/resources/org/springframework/security/messages_pt_PT.properties----------
PersistentTokenBasedRememberMeServices.cookieStolen=[../web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java]
----------../core/src/main/resources/org/springframework/security/messages_uk_UA.properties----------
PersistentTokenBasedRememberMeServices.cookieStolen=[../web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java]
----------../core/src/main/resources/org/springframework/security/messages_zh_CN.properties----------
PersistentTokenBasedRememberMeServices.cookieStolen=[../web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java]

How unknown keys were gussed by existing keys

----------../core/src/main/resources/org/springframework/security/messages_cs_CZ.properties----------
   AccountStatusUserDetailsChecker.credentialsExpired was guessed using SwitchUserProcessingFilter.credentialsExpired
   AccountStatusUserDetailsChecker.disabled was guessed using AbstractUserDetailsAuthenticationProvider.disabled
   AccountStatusUserDetailsChecker.expired was guessed using SwitchUserProcessingFilter.expired
   AccountStatusUserDetailsChecker.locked was guessed using AbstractUserDetailsAuthenticationProvider.locked
   AclEntryAfterInvocationProvider.noPermission was guessed using BasicAclEntryAfterInvocationProvider.noPermission
   BindAuthenticator.emptyPassword was guessed using LdapAuthenticationProvider.emptyPassword
   ConcurrentSessionControlStrategy.exceededAllowed was guessed using ConcurrentSessionControllerImpl.exceededAllowed
   DigestAuthenticationFilter.incorrectRealm was guessed using DigestProcessingFilter.incorrectRealm
   DigestAuthenticationFilter.incorrectResponse was guessed using DigestProcessingFilter.incorrectResponse
   DigestAuthenticationFilter.missingAuth was guessed using DigestProcessingFilter.missingAuth
   DigestAuthenticationFilter.missingMandatory was guessed using DigestProcessingFilter.missingMandatory
   DigestAuthenticationFilter.nonceCompromised was guessed using DigestProcessingFilter.nonceCompromised
   DigestAuthenticationFilter.nonceEncoding was guessed using DigestProcessingFilter.nonceEncoding
   DigestAuthenticationFilter.nonceExpired was guessed using DigestProcessingFilter.nonceExpired
   DigestAuthenticationFilter.nonceNotNumeric was guessed using DigestProcessingFilter.nonceNotNumeric
   DigestAuthenticationFilter.nonceNotTwoTokens was guessed using DigestProcessingFilter.nonceNotTwoTokens
   DigestAuthenticationFilter.usernameNotFound was guessed using SwitchUserProcessingFilter.usernameNotFound
   LdapAuthenticationProvider.badCredentials was guessed using PasswordComparisonAuthenticator.badCredentials
   LdapAuthenticationProvider.onlySupports was guessed using AbstractUserDetailsAuthenticationProvider.onlySupports
   SubjectDnX509PrincipalExtractor.noMatching was guessed using DaoX509AuthoritiesPopulator.noMatching
   SwitchUserFilter.noCurrentUser was guessed using SwitchUserProcessingFilter.noCurrentUser
   SwitchUserFilter.noOriginalAuthentication was guessed using SwitchUserProcessingFilter.noOriginalAuthentication

----------../core/src/main/resources/org/springframework/security/messages_de.properties----------
   AccountStatusUserDetailsChecker.credentialsExpired was guessed using SwitchUserProcessingFilter.credentialsExpired
   AccountStatusUserDetailsChecker.disabled was guessed using AbstractUserDetailsAuthenticationProvider.disabled
   AccountStatusUserDetailsChecker.expired was guessed using SwitchUserProcessingFilter.expired
   AccountStatusUserDetailsChecker.locked was guessed using AbstractUserDetailsAuthenticationProvider.locked
   AclEntryAfterInvocationProvider.noPermission was guessed using BasicAclEntryAfterInvocationProvider.noPermission
   BindAuthenticator.emptyPassword was guessed using LdapAuthenticationProvider.emptyPassword
   ConcurrentSessionControlStrategy.exceededAllowed was guessed using ConcurrentSessionControllerImpl.exceededAllowed
   DigestAuthenticationFilter.incorrectRealm was guessed using DigestProcessingFilter.incorrectRealm
   DigestAuthenticationFilter.incorrectResponse was guessed using DigestProcessingFilter.incorrectResponse
   DigestAuthenticationFilter.missingAuth was guessed using DigestProcessingFilter.missingAuth
   DigestAuthenticationFilter.missingMandatory was guessed using DigestProcessingFilter.missingMandatory
   DigestAuthenticationFilter.nonceCompromised was guessed using DigestProcessingFilter.nonceCompromised
   DigestAuthenticationFilter.nonceEncoding was guessed using DigestProcessingFilter.nonceEncoding
   DigestAuthenticationFilter.nonceExpired was guessed using DigestProcessingFilter.nonceExpired
   DigestAuthenticationFilter.nonceNotNumeric was guessed using DigestProcessingFilter.nonceNotNumeric
   DigestAuthenticationFilter.nonceNotTwoTokens was guessed using DigestProcessingFilter.nonceNotTwoTokens
   DigestAuthenticationFilter.usernameNotFound was guessed using SwitchUserProcessingFilter.usernameNotFound
   LdapAuthenticationProvider.badCredentials was guessed using PasswordComparisonAuthenticator.badCredentials
   LdapAuthenticationProvider.onlySupports was guessed using AbstractUserDetailsAuthenticationProvider.onlySupports
   SubjectDnX509PrincipalExtractor.noMatching was guessed using DaoX509AuthoritiesPopulator.noMatching
   SwitchUserFilter.noCurrentUser was guessed using SwitchUserProcessingFilter.noCurrentUser
   SwitchUserFilter.noOriginalAuthentication was guessed using SwitchUserProcessingFilter.noOriginalAuthentication

----------../core/src/main/resources/org/springframework/security/messages_es_ES.properties----------
   AccountStatusUserDetailsChecker.credentialsExpired was guessed using UserDetailsService.credentialsExpired
   AccountStatusUserDetailsChecker.disabled was guessed using UserDetailsService.disabled
   AccountStatusUserDetailsChecker.expired was guessed using SwitchUserProcessingFilter.expired
   AccountStatusUserDetailsChecker.locked was guessed using AbstractUserDetailsAuthenticationProvider.locked
   AclEntryAfterInvocationProvider.noPermission was guessed using BasicAclEntryAfterInvocationProvider.noPermission
   BindAuthenticator.emptyPassword was guessed using LdapAuthenticationProvider.emptyPassword
   ConcurrentSessionControlStrategy.exceededAllowed was guessed using ConcurrentSessionControllerImpl.exceededAllowed
   DigestAuthenticationFilter.incorrectRealm was guessed using DigestProcessingFilter.incorrectRealm
   DigestAuthenticationFilter.incorrectResponse was guessed using DigestProcessingFilter.incorrectResponse
   DigestAuthenticationFilter.missingAuth was guessed using DigestProcessingFilter.missingAuth
   DigestAuthenticationFilter.missingMandatory was guessed using DigestProcessingFilter.missingMandatory
   DigestAuthenticationFilter.nonceCompromised was guessed using DigestProcessingFilter.nonceCompromised
   DigestAuthenticationFilter.nonceEncoding was guessed using DigestProcessingFilter.nonceEncoding
   DigestAuthenticationFilter.nonceExpired was guessed using DigestProcessingFilter.nonceExpired
   DigestAuthenticationFilter.nonceNotNumeric was guessed using DigestProcessingFilter.nonceNotNumeric
   DigestAuthenticationFilter.nonceNotTwoTokens was guessed using DigestProcessingFilter.nonceNotTwoTokens
   DigestAuthenticationFilter.usernameNotFound was guessed using DigestProcessingFilter.usernameNotFound
   LdapAuthenticationProvider.badCredentials was guessed using PasswordComparisonAuthenticator.badCredentials
   LdapAuthenticationProvider.onlySupports was guessed using AbstractUserDetailsAuthenticationProvider.onlySupports
   SubjectDnX509PrincipalExtractor.noMatching was guessed using DaoX509AuthoritiesPopulator.noMatching
   SwitchUserFilter.noCurrentUser was guessed using SwitchUserProcessingFilter.noCurrentUser
   SwitchUserFilter.noOriginalAuthentication was guessed using SwitchUserProcessingFilter.noOriginalAuthentication

----------../core/src/main/resources/org/springframework/security/messages_fr.properties----------
   AccountStatusUserDetailsChecker.credentialsExpired was guessed using UserDetailsService.credentialsExpired
   AccountStatusUserDetailsChecker.disabled was guessed using UserDetailsService.disabled
   AccountStatusUserDetailsChecker.expired was guessed using SwitchUserProcessingFilter.expired
   AccountStatusUserDetailsChecker.locked was guessed using AbstractUserDetailsAuthenticationProvider.locked
   AclEntryAfterInvocationProvider.noPermission was guessed using BasicAclEntryAfterInvocationProvider.noPermission
   BindAuthenticator.emptyPassword was guessed using LdapAuthenticationProvider.emptyPassword
   ConcurrentSessionControlStrategy.exceededAllowed was guessed using ConcurrentSessionControllerImpl.exceededAllowed
   DigestAuthenticationFilter.incorrectRealm was guessed using DigestProcessingFilter.incorrectRealm
   DigestAuthenticationFilter.incorrectResponse was guessed using DigestProcessingFilter.incorrectResponse
   DigestAuthenticationFilter.missingAuth was guessed using DigestProcessingFilter.missingAuth
   DigestAuthenticationFilter.missingMandatory was guessed using DigestProcessingFilter.missingMandatory
   DigestAuthenticationFilter.nonceCompromised was guessed using DigestProcessingFilter.nonceCompromised
   DigestAuthenticationFilter.nonceEncoding was guessed using DigestProcessingFilter.nonceEncoding
   DigestAuthenticationFilter.nonceExpired was guessed using DigestProcessingFilter.nonceExpired
   DigestAuthenticationFilter.nonceNotNumeric was guessed using DigestProcessingFilter.nonceNotNumeric
   DigestAuthenticationFilter.nonceNotTwoTokens was guessed using DigestProcessingFilter.nonceNotTwoTokens
   DigestAuthenticationFilter.usernameNotFound was guessed using DigestProcessingFilter.usernameNotFound
   LdapAuthenticationProvider.badCredentials was guessed using PasswordComparisonAuthenticator.badCredentials
   LdapAuthenticationProvider.onlySupports was guessed using AbstractUserDetailsAuthenticationProvider.onlySupports
   SubjectDnX509PrincipalExtractor.noMatching was guessed using DaoX509AuthoritiesPopulator.noMatching
   SwitchUserFilter.noCurrentUser was guessed using SwitchUserProcessingFilter.noCurrentUser
   SwitchUserFilter.noOriginalAuthentication was guessed using SwitchUserProcessingFilter.noOriginalAuthentication

----------../core/src/main/resources/org/springframework/security/messages_it.properties----------
   AccountStatusUserDetailsChecker.credentialsExpired was guessed using SwitchUserProcessingFilter.credentialsExpired
   AccountStatusUserDetailsChecker.disabled was guessed using AbstractUserDetailsAuthenticationProvider.disabled
   AccountStatusUserDetailsChecker.expired was guessed using SwitchUserProcessingFilter.expired
   AccountStatusUserDetailsChecker.locked was guessed using AbstractUserDetailsAuthenticationProvider.locked
   AclEntryAfterInvocationProvider.noPermission was guessed using BasicAclEntryAfterInvocationProvider.noPermission
   BindAuthenticator.emptyPassword was guessed using LdapAuthenticationProvider.emptyPassword
   ConcurrentSessionControlStrategy.exceededAllowed was guessed using ConcurrentSessionControllerImpl.exceededAllowed
   DigestAuthenticationFilter.incorrectRealm was guessed using DigestProcessingFilter.incorrectRealm
   DigestAuthenticationFilter.incorrectResponse was guessed using DigestProcessingFilter.incorrectResponse
   DigestAuthenticationFilter.missingAuth was guessed using DigestProcessingFilter.missingAuth
   DigestAuthenticationFilter.missingMandatory was guessed using DigestProcessingFilter.missingMandatory
   DigestAuthenticationFilter.nonceCompromised was guessed using DigestProcessingFilter.nonceCompromised
   DigestAuthenticationFilter.nonceEncoding was guessed using DigestProcessingFilter.nonceEncoding
   DigestAuthenticationFilter.nonceExpired was guessed using DigestProcessingFilter.nonceExpired
   DigestAuthenticationFilter.nonceNotNumeric was guessed using DigestProcessingFilter.nonceNotNumeric
   DigestAuthenticationFilter.nonceNotTwoTokens was guessed using DigestProcessingFilter.nonceNotTwoTokens
   DigestAuthenticationFilter.usernameNotFound was guessed using DigestProcessingFilter.usernameNotFound
   LdapAuthenticationProvider.badCredentials was guessed using PasswordComparisonAuthenticator.badCredentials
   LdapAuthenticationProvider.onlySupports was guessed using AbstractUserDetailsAuthenticationProvider.onlySupports
   SubjectDnX509PrincipalExtractor.noMatching was guessed using DaoX509AuthoritiesPopulator.noMatching
   SwitchUserFilter.noCurrentUser was guessed using SwitchUserProcessingFilter.noCurrentUser
   SwitchUserFilter.noOriginalAuthentication was guessed using SwitchUserProcessingFilter.noOriginalAuthentication

----------../core/src/main/resources/org/springframework/security/messages_ko_KR.properties----------
   AccountStatusUserDetailsChecker.credentialsExpired was guessed using UserDetailsService.credentialsExpired
   AccountStatusUserDetailsChecker.disabled was guessed using UserDetailsService.disabled
   AccountStatusUserDetailsChecker.expired was guessed using SwitchUserProcessingFilter.expired
   AccountStatusUserDetailsChecker.locked was guessed using AbstractUserDetailsAuthenticationProvider.locked
   AclEntryAfterInvocationProvider.noPermission was guessed using BasicAclEntryAfterInvocationProvider.noPermission
   BindAuthenticator.emptyPassword was guessed using LdapAuthenticationProvider.emptyPassword
   ConcurrentSessionControlStrategy.exceededAllowed was guessed using ConcurrentSessionControllerImpl.exceededAllowed
   DigestAuthenticationFilter.incorrectRealm was guessed using DigestProcessingFilter.incorrectRealm
   DigestAuthenticationFilter.incorrectResponse was guessed using DigestProcessingFilter.incorrectResponse
   DigestAuthenticationFilter.missingAuth was guessed using DigestProcessingFilter.missingAuth
   DigestAuthenticationFilter.missingMandatory was guessed using DigestProcessingFilter.missingMandatory
   DigestAuthenticationFilter.nonceCompromised was guessed using DigestProcessingFilter.nonceCompromised
   DigestAuthenticationFilter.nonceEncoding was guessed using DigestProcessingFilter.nonceEncoding
   DigestAuthenticationFilter.nonceExpired was guessed using DigestProcessingFilter.nonceExpired
   DigestAuthenticationFilter.nonceNotNumeric was guessed using DigestProcessingFilter.nonceNotNumeric
   DigestAuthenticationFilter.nonceNotTwoTokens was guessed using DigestProcessingFilter.nonceNotTwoTokens
   DigestAuthenticationFilter.usernameNotFound was guessed using DigestProcessingFilter.usernameNotFound
   LdapAuthenticationProvider.badCredentials was guessed using PasswordComparisonAuthenticator.badCredentials
   LdapAuthenticationProvider.onlySupports was guessed using AbstractUserDetailsAuthenticationProvider.onlySupports
   SubjectDnX509PrincipalExtractor.noMatching was guessed using DaoX509AuthoritiesPopulator.noMatching
   SwitchUserFilter.noCurrentUser was guessed using SwitchUserProcessingFilter.noCurrentUser
   SwitchUserFilter.noOriginalAuthentication was guessed using SwitchUserProcessingFilter.noOriginalAuthentication

----------../core/src/main/resources/org/springframework/security/messages_pl.properties----------
   AccountStatusUserDetailsChecker.credentialsExpired was guessed using UserDetailsService.credentialsExpired
   AccountStatusUserDetailsChecker.disabled was guessed using UserDetailsService.disabled
   AccountStatusUserDetailsChecker.expired was guessed using SwitchUserProcessingFilter.expired
   AccountStatusUserDetailsChecker.locked was guessed using AbstractUserDetailsAuthenticationProvider.locked
   AclEntryAfterInvocationProvider.noPermission was guessed using BasicAclEntryAfterInvocationProvider.noPermission
   BindAuthenticator.emptyPassword was guessed using LdapAuthenticationProvider.emptyPassword
   ConcurrentSessionControlStrategy.exceededAllowed was guessed using ConcurrentSessionControllerImpl.exceededAllowed
   DigestAuthenticationFilter.incorrectRealm was guessed using DigestProcessingFilter.incorrectRealm
   DigestAuthenticationFilter.incorrectResponse was guessed using DigestProcessingFilter.incorrectResponse
   DigestAuthenticationFilter.missingAuth was guessed using DigestProcessingFilter.missingAuth
   DigestAuthenticationFilter.missingMandatory was guessed using DigestProcessingFilter.missingMandatory
   DigestAuthenticationFilter.nonceCompromised was guessed using DigestProcessingFilter.nonceCompromised
   DigestAuthenticationFilter.nonceEncoding was guessed using DigestProcessingFilter.nonceEncoding
   DigestAuthenticationFilter.nonceExpired was guessed using DigestProcessingFilter.nonceExpired
   DigestAuthenticationFilter.nonceNotNumeric was guessed using DigestProcessingFilter.nonceNotNumeric
   DigestAuthenticationFilter.nonceNotTwoTokens was guessed using DigestProcessingFilter.nonceNotTwoTokens
   DigestAuthenticationFilter.usernameNotFound was guessed using DigestProcessingFilter.usernameNotFound
   LdapAuthenticationProvider.badCredentials was guessed using PasswordComparisonAuthenticator.badCredentials
   LdapAuthenticationProvider.onlySupports was guessed using AbstractUserDetailsAuthenticationProvider.onlySupports
   SubjectDnX509PrincipalExtractor.noMatching was guessed using DaoX509AuthoritiesPopulator.noMatching
   SwitchUserFilter.noCurrentUser was guessed using SwitchUserProcessingFilter.noCurrentUser
   SwitchUserFilter.noOriginalAuthentication was guessed using SwitchUserProcessingFilter.noOriginalAuthentication

----------../core/src/main/resources/org/springframework/security/messages_pt_BR.properties----------
   AccountStatusUserDetailsChecker.credentialsExpired was guessed using UserDetailsService.credentialsExpired
   AccountStatusUserDetailsChecker.disabled was guessed using UserDetailsService.disabled
   AccountStatusUserDetailsChecker.expired was guessed using SwitchUserProcessingFilter.expired
   AccountStatusUserDetailsChecker.locked was guessed using AbstractUserDetailsAuthenticationProvider.locked
   AclEntryAfterInvocationProvider.noPermission was guessed using BasicAclEntryAfterInvocationProvider.noPermission
   BindAuthenticator.emptyPassword was guessed using LdapAuthenticationProvider.emptyPassword
   ConcurrentSessionControlStrategy.exceededAllowed was guessed using ConcurrentSessionControllerImpl.exceededAllowed
   DigestAuthenticationFilter.incorrectRealm was guessed using DigestProcessingFilter.incorrectRealm
   DigestAuthenticationFilter.incorrectResponse was guessed using DigestProcessingFilter.incorrectResponse
   DigestAuthenticationFilter.missingAuth was guessed using DigestProcessingFilter.missingAuth
   DigestAuthenticationFilter.missingMandatory was guessed using DigestProcessingFilter.missingMandatory
   DigestAuthenticationFilter.nonceCompromised was guessed using DigestProcessingFilter.nonceCompromised
   DigestAuthenticationFilter.nonceEncoding was guessed using DigestProcessingFilter.nonceEncoding
   DigestAuthenticationFilter.nonceExpired was guessed using DigestProcessingFilter.nonceExpired
   DigestAuthenticationFilter.nonceNotNumeric was guessed using DigestProcessingFilter.nonceNotNumeric
   DigestAuthenticationFilter.nonceNotTwoTokens was guessed using DigestProcessingFilter.nonceNotTwoTokens
   DigestAuthenticationFilter.usernameNotFound was guessed using DigestProcessingFilter.usernameNotFound
   LdapAuthenticationProvider.badCredentials was guessed using PasswordComparisonAuthenticator.badCredentials
   LdapAuthenticationProvider.onlySupports was guessed using AbstractUserDetailsAuthenticationProvider.onlySupports
   SubjectDnX509PrincipalExtractor.noMatching was guessed using DaoX509AuthoritiesPopulator.noMatching
   SwitchUserFilter.noCurrentUser was guessed using SwitchUserProcessingFilter.noCurrentUser
   SwitchUserFilter.noOriginalAuthentication was guessed using SwitchUserProcessingFilter.noOriginalAuthentication

----------../core/src/main/resources/org/springframework/security/messages_pt_PT.properties----------
   AccountStatusUserDetailsChecker.credentialsExpired was guessed using UserDetailsService.credentialsExpired
   AccountStatusUserDetailsChecker.disabled was guessed using UserDetailsService.disabled
   AccountStatusUserDetailsChecker.expired was guessed using SwitchUserProcessingFilter.expired
   AccountStatusUserDetailsChecker.locked was guessed using AbstractUserDetailsAuthenticationProvider.locked
   AclEntryAfterInvocationProvider.noPermission was guessed using BasicAclEntryAfterInvocationProvider.noPermission
   BindAuthenticator.emptyPassword was guessed using LdapAuthenticationProvider.emptyPassword
   ConcurrentSessionControlStrategy.exceededAllowed was guessed using ConcurrentSessionControllerImpl.exceededAllowed
   DigestAuthenticationFilter.incorrectRealm was guessed using DigestProcessingFilter.incorrectRealm
   DigestAuthenticationFilter.incorrectResponse was guessed using DigestProcessingFilter.incorrectResponse
   DigestAuthenticationFilter.missingAuth was guessed using DigestProcessingFilter.missingAuth
   DigestAuthenticationFilter.missingMandatory was guessed using DigestProcessingFilter.missingMandatory
   DigestAuthenticationFilter.nonceCompromised was guessed using DigestProcessingFilter.nonceCompromised
   DigestAuthenticationFilter.nonceEncoding was guessed using DigestProcessingFilter.nonceEncoding
   DigestAuthenticationFilter.nonceExpired was guessed using DigestProcessingFilter.nonceExpired
   DigestAuthenticationFilter.nonceNotNumeric was guessed using DigestProcessingFilter.nonceNotNumeric
   DigestAuthenticationFilter.nonceNotTwoTokens was guessed using DigestProcessingFilter.nonceNotTwoTokens
   DigestAuthenticationFilter.usernameNotFound was guessed using DigestProcessingFilter.usernameNotFound
   LdapAuthenticationProvider.badCredentials was guessed using PasswordComparisonAuthenticator.badCredentials
   LdapAuthenticationProvider.onlySupports was guessed using AbstractUserDetailsAuthenticationProvider.onlySupports
   SubjectDnX509PrincipalExtractor.noMatching was guessed using DaoX509AuthoritiesPopulator.noMatching
   SwitchUserFilter.noCurrentUser was guessed using SwitchUserProcessingFilter.noCurrentUser
   SwitchUserFilter.noOriginalAuthentication was guessed using SwitchUserProcessingFilter.noOriginalAuthentication

----------../core/src/main/resources/org/springframework/security/messages_uk_UA.properties----------
   AccountStatusUserDetailsChecker.credentialsExpired was guessed using UserDetailsService.credentialsExpired
   AccountStatusUserDetailsChecker.disabled was guessed using UserDetailsService.disabled
   AccountStatusUserDetailsChecker.expired was guessed using SwitchUserProcessingFilter.expired
   AccountStatusUserDetailsChecker.locked was guessed using AbstractUserDetailsAuthenticationProvider.locked
   AclEntryAfterInvocationProvider.noPermission was guessed using BasicAclEntryAfterInvocationProvider.noPermission
   BindAuthenticator.emptyPassword was guessed using LdapAuthenticationProvider.emptyPassword
   ConcurrentSessionControlStrategy.exceededAllowed was guessed using ConcurrentSessionControllerImpl.exceededAllowed
   DigestAuthenticationFilter.incorrectRealm was guessed using DigestProcessingFilter.incorrectRealm
   DigestAuthenticationFilter.incorrectResponse was guessed using DigestProcessingFilter.incorrectResponse
   DigestAuthenticationFilter.missingAuth was guessed using DigestProcessingFilter.missingAuth
   DigestAuthenticationFilter.missingMandatory was guessed using DigestProcessingFilter.missingMandatory
   DigestAuthenticationFilter.nonceCompromised was guessed using DigestProcessingFilter.nonceCompromised
   DigestAuthenticationFilter.nonceEncoding was guessed using DigestProcessingFilter.nonceEncoding
   DigestAuthenticationFilter.nonceExpired was guessed using DigestProcessingFilter.nonceExpired
   DigestAuthenticationFilter.nonceNotNumeric was guessed using DigestProcessingFilter.nonceNotNumeric
   DigestAuthenticationFilter.nonceNotTwoTokens was guessed using DigestProcessingFilter.nonceNotTwoTokens
   DigestAuthenticationFilter.usernameNotFound was guessed using DigestProcessingFilter.usernameNotFound
   LdapAuthenticationProvider.badCredentials was guessed using PasswordComparisonAuthenticator.badCredentials
   LdapAuthenticationProvider.onlySupports was guessed using AbstractUserDetailsAuthenticationProvider.onlySupports
   SubjectDnX509PrincipalExtractor.noMatching was guessed using DaoX509AuthoritiesPopulator.noMatching
   SwitchUserFilter.noCurrentUser was guessed using SwitchUserProcessingFilter.noCurrentUser
   SwitchUserFilter.noOriginalAuthentication was guessed using SwitchUserProcessingFilter.noOriginalAuthentication

----------../core/src/main/resources/org/springframework/security/messages_zh_CN.properties----------
   AccountStatusUserDetailsChecker.credentialsExpired was guessed using UserDetailsService.credentialsExpired
   AccountStatusUserDetailsChecker.disabled was guessed using UserDetailsService.disabled
   AccountStatusUserDetailsChecker.expired was guessed using SwitchUserProcessingFilter.expired
   AccountStatusUserDetailsChecker.locked was guessed using AbstractUserDetailsAuthenticationProvider.locked
   AclEntryAfterInvocationProvider.noPermission was guessed using BasicAclEntryAfterInvocationProvider.noPermission
   BindAuthenticator.emptyPassword was guessed using LdapAuthenticationProvider.emptyPassword
   ConcurrentSessionControlStrategy.exceededAllowed was guessed using ConcurrentSessionControllerImpl.exceededAllowed
   DigestAuthenticationFilter.incorrectRealm was guessed using DigestProcessingFilter.incorrectRealm
   DigestAuthenticationFilter.incorrectResponse was guessed using DigestProcessingFilter.incorrectResponse
   DigestAuthenticationFilter.missingAuth was guessed using DigestProcessingFilter.missingAuth
   DigestAuthenticationFilter.missingMandatory was guessed using DigestProcessingFilter.missingMandatory
   DigestAuthenticationFilter.nonceCompromised was guessed using DigestProcessingFilter.nonceCompromised
   DigestAuthenticationFilter.nonceEncoding was guessed using DigestProcessingFilter.nonceEncoding
   DigestAuthenticationFilter.nonceExpired was guessed using DigestProcessingFilter.nonceExpired
   DigestAuthenticationFilter.nonceNotNumeric was guessed using DigestProcessingFilter.nonceNotNumeric
   DigestAuthenticationFilter.nonceNotTwoTokens was guessed using DigestProcessingFilter.nonceNotTwoTokens
   DigestAuthenticationFilter.usernameNotFound was guessed using DigestProcessingFilter.usernameNotFound
   LdapAuthenticationProvider.badCredentials was guessed using PasswordComparisonAuthenticator.badCredentials
   LdapAuthenticationProvider.onlySupports was guessed using AbstractUserDetailsAuthenticationProvider.onlySupports
   SubjectDnX509PrincipalExtractor.noMatching was guessed using DaoX509AuthoritiesPopulator.noMatching
   SwitchUserFilter.noCurrentUser was guessed using SwitchUserProcessingFilter.noCurrentUser
   SwitchUserFilter.noOriginalAuthentication was guessed using SwitchUserProcessingFilter.noOriginalAuthentication
2011-01-21 10:24:07 -06:00
Luke Taylor 537d8f108a SEC-1654: Correct debug output in DigestAuthenticationFilter. 2011-01-11 14:27:45 +00:00
Luke Taylor d0bada2bad SEC-1641: Correct code and test for null groupSearchBase. 2010-12-20 16:50:11 +00:00
Luke Taylor 952af853ac SEC-1641: Remove the private setGroupSearchBase method and allowed a null value to be set for the group search base in the constructor. 2010-12-19 16:18:30 +00:00
Rob Winch 4dea140331 SEC-1639: FirewalledRequest is now called on the specific FirewalledRequest instance rather that looping through ServletRequestWrappers.
VirtualFilterChain now accepts the FirewalledRequest in the constructor. The reset method is called directly on the instance passed in instead of looping through the ServletRequestWrappers.

Conflicts:

	web/src/main/java/org/springframework/security/web/FilterChainProxy.java
	web/src/test/java/org/springframework/security/web/FilterChainProxyTests.java
2010-12-16 23:53:15 -06:00
Luke Taylor bb3a973fcb SEC-1636: Add optimizations for universal match cases in AntUrlPathMatcher (using "/**" and "**" equality checks on the path). 2010-12-11 20:57:49 +00:00
Luke Taylor 522e8db5da Javadoc fix 2010-12-09 12:39:23 +00:00
Luke Taylor 8f71f6febf SEC-1557: Added getter to DelegatingMethodSecurityMetadataSource. 2010-12-01 21:57:16 +00:00
Luke Taylor 69a1fb76d3 SEC-1615: Changed key generation for anonymous provider to only use SecureRandom on demand. 2010-12-01 20:51:13 +00:00
Luke Taylor 156a6924fa Move docs on request matching to correct file and delete unused one 2010-11-24 00:31:09 +00:00
Luke Taylor d53db3ba13 Update version to 3.0.6.CI-SNAPSHOT. 2010-11-18 12:39:19 +00:00
Luke Taylor 90304f64c6 Update version for 3.0.5 release 2010-11-18 12:36:08 +00:00
Luke Taylor 6349359b77 Enable aspectj module in 3.0.x build. 2010-11-18 12:35:49 +00:00
Luke Taylor e80853b698 SEC-1412: DefaultSavedRequest should ignore "If-Modified-Since" headers to prevent re-displaying the login form (the cached result of the original request). 2010-11-15 16:48:15 +00:00
Luke Taylor 82d105cbc3 SEC-1587: Add explicit call to removeAttribute() to remove the context from the session if the current context is empty or anonymous.
Allows for the situation where a user is logged out without invalidating the session.
2010-11-10 13:01:49 +00:00
Luke Taylor e88f47a96a SEC-1561: Add check on whether the security context attribute is set in the current session to make sure it is stored when a new session has been created during the request. 2010-11-10 12:53:56 +00:00
Luke Taylor 979ea63980 SEC-1613: Corrected preauth docs. 2010-11-04 14:34:02 +00:00
Rob Winch 0bdc9c176b SEC-1606: Added a FirewalledRequestAwareRequestDispatcher that will call FirewalledRequest.reset() before a forward 2010-11-03 14:25:52 -05:00
Luke Taylor 80fd238c3a Backport updates to TarUpload for easier uploading of docs to website. 2010-11-02 16:38:19 +00:00
Luke Taylor 5c597c8cde Update doc version number to 3.0.4 2010-11-02 16:31:01 +00:00
Luke Taylor ec7b9703a6 Expand message on incorrect Spring version to suggest checking the classpath for unwanted jars. 2010-11-02 12:31:14 +00:00
Luke Taylor 71b2af31ee SEC-1608: Make sure FirewalledRequest.reset() is called when filter="none" 2010-11-02 12:19:22 +00:00
Luke Taylor fc75b69ab8 SEC-1607: Report correct version for Spring Security (not Spring version). 2010-11-02 11:18:49 +00:00
Luke Taylor 6141ef79b3 Remove use of @Override with an interface method 2010-10-28 16:10:48 +01:00
Luke Taylor 3cfe23f60d Update versions to 3.0.5.CI-SNAPSHOT 2010-10-26 15:32:22 +01:00
Luke Taylor 82d140ffb1 Version 3.0.4.RELEASE 2010-10-26 15:32:22 +01:00
Luke Taylor 1563491322 SEC-1600: Added Implementation-Version and Implementation-Title to manifest templates and checking of version numbers in namespace config module and core. Config checks the version of core it is running against and core checks the Spring version, reporting any mismatches or situations where the app is running with less than the recommended Spring version. 2010-10-26 15:32:21 +01:00
Luke Taylor b688bb69ee SEC-1543: Change IpAddressMatcher to return false when comparing an Inet6Address with an Inet4Address rather than raising an exception. 2010-10-26 15:32:21 +01:00
Luke Taylor 36f008643d SEC-1598: Removed invalid properties from SessionFixationProtectionStrategy bean declaration in Session Management chapter docbook. 2010-10-26 15:32:21 +01:00
Luke Taylor cbdf77e991 SEC-1597: Corrected bean class name for RememberMeAuthenticationProvider in docbook source. 2010-10-26 15:32:21 +01:00
Luke Taylor 399e921d14 SEC-1599: Corrected docbook source. 2010-10-26 15:32:21 +01:00
Luke Taylor c458311d2d SEC-1548: Added extra logging to Dao-authentication classes to clarify reasons for authentication failure (missing user vs wrong password etc.). 2010-10-26 15:32:21 +01:00
Luke Taylor d6f408e8bf SEC-1583: Added hasAuthority and hasAnyAuthority imlementations to SecurityExpressionRoot. 2010-10-26 15:32:21 +01:00
Luke Taylor 1739628e6a SEC-1589: Add support for property placeholder in intercept-methods access attribute. 2010-10-26 15:32:21 +01:00
Luke Taylor 8e68fa1334 SEC-1584: Added namespace support for injecting custom HttpFirewall instance into FilterChainProxy. 2010-10-26 15:32:21 +01:00
Luke Taylor 82cd72768d doc updates to be merged with orgininal sec-1584 doc changes 2010-10-26 15:32:20 +01:00
Luke Taylor 161710cc87 SEC-1584: Doc updates to explain request matching process. 2010-10-26 15:32:20 +01:00
Luke Taylor dc1b652512 SEC-1584: Additional integration tests. 2010-10-26 15:32:20 +01:00
Luke Taylor ed9411c660 SEC-1584: Addition of HttpFirewall strategy to FilterChainProxy to reject un-normalized requests and wrap the incoming request object before processing by the security filter chain to provide a more consistent representation of paths than is guaranteed by the servlet spec. The wrapper strips path parameters from pathInfo and servletPath to provide consistency of URL matching across servlet containers and protect against bypassing security constraints by the malicious addition of such parameters to the URL. The paths are canonicalized further by replacing of multiple sequences of "/" characters with a single "/". 2010-10-26 15:31:33 +01:00
Luke Taylor e58f982351 Updating gitignore and removing unnecessary casts from FilterChainProxyConfigTests. 2010-10-05 13:31:49 +01:00
Luke Taylor 072b73354f Update namespace handler message to account for later schema versions being used by mistake. 2010-10-05 13:31:49 +01:00
Rob Winch 443231d1e8 SEC-1578: Use ThreadLocal.remove() instead of ThreadLocal.set(null) 2010-10-04 21:10:21 -05:00
Luke Taylor 45674a16ea SEC-1540: Apply patch to support HTTP method matching for requires-channel namespace attribute. 2010-08-18 13:17:21 +01:00
Luke Taylor a1b124def5 SEC-1532: Add cache of previously matched beans to ProtectPointcutPostProcessor to ensure that it doesn't perform pointcut matching every time a new prototype bean is created. 2010-08-11 18:29:21 +01:00
Luke Taylor f6abc24ed6 SEC-1529: More user-friendly expression @PreAuthorize expression in EL chapter. 2010-08-05 18:17:25 +01:00
Luke Taylor 1a9b7e1b6f SEC-1520: Close NamingEnumeration in LDAP compare implementation. 2010-07-21 16:55:09 +01:00
Luke Taylor 8b5c70951d SEC-1518: Fix element ordering in security.tld 2010-07-21 16:16:46 +01:00
Luke Taylor c891ab45ec Remove optional qualifier from apacheds dependencies in LDAP sample. 2010-07-13 02:08:44 +01:00
Luke Taylor 657a69b906 Minor doc/javadoc updates to clarify use of UserDetailsContextapper. 2010-07-04 15:10:08 +01:00
Luke Taylor 3b8fbe8bee Minor doc updates. 2010-07-03 19:43:01 +01:00
Luke Taylor 4ad85cdfdf SEC-1508: Update docbook processing to use Docbook 5 namespaces. 2010-07-03 13:12:08 +01:00
Luke Taylor 845c50a1c3 SEC-1507: Applied patch to return empty authority list rather than null from RoleHierarchyImpl. 2010-07-02 19:51:36 +01:00
Luke Taylor 25d222208d Switch version to 3.0.4-CI-SNAPSHOT. 2010-07-01 00:37:55 +01:00
Luke Taylor 9b0c21dfef 3.0.3 release. Update version in build files. 2010-07-01 00:37:29 +01:00
Luke Taylor 8301bd6276 Added that config jar is required to use the namespace. 2010-06-30 20:47:35 +01:00
Luke Taylor 1872d94aa1 Porting gradle changes from master 2010-06-30 20:45:03 +01:00
Luke Taylor 46611872db Updated version in manual for 3.0.3 release 2010-06-30 15:59:34 +01:00
Luke Taylor b6cbdde0cb Minor doc xref link corrections. 2010-06-26 13:14:15 +01:00
Luke Taylor 71e1702224 SEC-1493: Documentation of support for erasing credentials. 2010-06-26 12:34:20 +01:00
Luke Taylor 80ccd2b285 SEC-1501: Fix bean classname in Javadoc for SwitchUserFilter. 2010-06-25 13:36:52 +01:00
Luke Taylor 02c1f02f2a SEC-1493: Fix broken tests in 3.0.x branch 2010-06-25 13:36:08 +01:00
Luke Taylor 21a664b2eb Deprecation warning suppression for UserMap. 2010-06-25 12:50:58 +01:00
Luke Taylor 9a2d0c2cb5 SEC-1493: Added namespace support. 2010-06-20 21:11:49 +01:00
Luke Taylor 73b62497a3 SEC-1493: Added CredentialsContainer interface and implemented it in User, AbstractAuthenticationToken and UsernamePasswordAuthenticationToken. ProviderManager makes use of this to erase the credentials of the returned Authentication object (and its contents) if configured to do so by setting the 'eraseCredentialsAfterAuthentication' property. 2010-06-20 21:11:40 +01:00
Luke Taylor 09aba3906c SEC-1496: Added support for use of any non-standard URL schemes in DefaultRedirectStrategy. 2010-06-18 03:34:13 +01:00
Luke Taylor 57cfff6f5c SEC-1500: Convert AbstractRetryEntryPoint to use requestURI to correctly encode URLs. 2010-06-18 01:33:38 +01:00
Luke Taylor b7b6b2bac7 Update to Spring 3.0.3.RELEASE 2010-06-18 01:27:32 +01:00
Luke Taylor 8602ae3863 Upgrade maven build to Spring 3.0.3.BUILD-SNAPSHOT 2010-06-15 00:16:41 +01:00
Luke Taylor 8737fe3acb SEC-1495: Convert User class equals and hashcode methods to only use the "username" property.
This prevents situations where other data may have changed when a User object is reloaded (during a subsequent authentication attempt, in which case and Set.contains()/Map.containsKey() will return false even though the collection in question contains a principal representing the same user.
2010-06-10 22:28:12 +01:00
Luke Taylor 27faad3402 SEC-1488: Remove commons-logging dependencies from maven poms and use slf4j in all samples. 2010-05-28 13:10:08 +01:00
Luke Taylor aaa7bd90b2 SEC-1481: Updated constructors of Authentication types to use a generic wildcard for authorities collection. 2010-05-21 16:02:25 +01:00
Luke Taylor 295e0ded18 SEC-1483: Change User constructor to use a generic wildcard for authorities collection. 2010-05-21 16:02:07 +01:00
Luke Taylor 304f12fb63 SEC-1455: Load namespace parsers when required, rather than on init() call, to avoid classloaded issue with dmServer failing to resolve web classes when the namespace handler is first used. 2010-05-21 15:42:11 +01:00
Luke Taylor 8cbe232fbf SEC-1480: Add simple equals and hashcode methods based on DN value to LdapUserDetailsImpl to allow its use as a map key (in SessionRegistry, for example). 2010-05-15 02:29:56 +01:00
Luke Taylor 5ac106808e Remove outdated scm information from pom.xml. 2010-04-28 20:16:40 +01:00
Luke Taylor 8c605516b3 SEC-1463: Change namespace user-service parser to store username in lower-case when building map for in-memory UserDetailsService. Lookups are supposed to be case-insensitive with this class. 2010-04-24 16:42:00 +01:00
Luke Taylor e6e168f127 SEC-1456: Set rtexprvalue=true for "url" attribute in access tag to allow dynamic values (such as URL of current page). 2010-04-21 17:29:27 +01:00
Luke Taylor 6d6c2d31ef SEC-1462: Only apply session fixation protection strategy if request.isRequestedSessionIdValid() returns true. We don't need to create a new session if the current one already has a different Id from the client. 2010-04-20 18:04:56 +01:00
Luke Taylor 8f6aecac9b Clarify that multiple authentication-provider elements can be used in combination. 2010-04-17 15:25:37 +01:00
Luke Taylor 0760bb947b SEC-1458: Remove logger field in HttpSessionEventPublisher in favour of direct lookup. Prevents early initialization of logging system when listener is initialized. 2010-04-16 16:13:41 +01:00
Luke Taylor 9d2e2ca11d SEC-1232: Add config dependency to maven build for aspectj sample. 2010-03-31 19:59:19 +01:00
Luke Taylor 6354c7e052 SEC-1232: GlobalMethodSecurityBeanDefinitionParser support for mode='aspectj'
AspectJ sample application context also updated to use this syntax.
2010-03-31 17:41:23 +01:00
Luke Taylor 42cdaa0ce2 Latest gradle syntax updates. 2010-03-31 17:12:00 +01:00
Luke Taylor eda60b72b1 SEC-1448: Fixed failure to resolve generic method argument names in MethodSecurityEvaluationContext.
Changed to use AopUtils.getMostSpecificMethod() when obtaining the method on which the parameter resolution should be performed. Also added better error handling and log warning when parameter names cannot be resolved. The exception will then be a SpEL one, rather than a NPE.
2010-03-27 17:22:38 +00:00
Luke Taylor 0d198d42ae SEC-1444: Fix JNDI escaping problems in LDAP authentication.
CompositeName adds quotes to names which contain a forward slash ("/") character. These are automatically removed by Spring LDAP's DistinguishedName, but only if they are at the ends of the String. Since we were preprending the base to the (quoted) DN, resulting in something like ["cn=joe/b",ou=people], this was causing problems with the DN value returned from the search. Additionally, the bind succeeds when a DN is used with a slash, but the subsequent call to getAttributes() fails. This call now passes in a DistinguishedName for the user DN instance instead of a String.
2010-03-27 15:30:45 +00:00
Luke Taylor f000aaa7e8 SEC-1440: Implement support for separate entry-point-ref on htt-basic namespace element. Changes ported from master branch. 2010-03-26 14:06:12 +00:00
Luke Taylor 634e340d80 Update schema version to 3.0.3 2010-03-26 13:53:56 +00:00
Luke Taylor 4c8e9e2d7e SEC-1450: Replace use of ClassUtils.getMostSpecificMethod() in AbstractFallbackMethodDefinitionSource with AopUtils.getMostSpecificMethod() equivalent.
Ensures protect-pointcut expressions match methods with generic parameters.
2010-03-24 21:03:45 +00:00
Luke Taylor e518adbef1 SEC-1443: Modify Jsr250Voter to handle multiple "RolesAllowed" roles.
It now votes to abstain if there are no Jsr250 attributes present. If any are found, it will either deny or grant access. For multiple "RoleAllowed" attributes, access will be granted if any user authority matches or denied if no match is found.
2010-03-22 16:26:49 +00:00
Luke Taylor 59b69f6f48 SEC-1434: Remove use of BeanDefinition of type java.lang.String which causes problems in Google App Engine.
This results in the method BeanUtils.findEditorByConvention attempting to get hold of the system classloader which isn't allowed by the security manager in GAE.
2010-03-16 02:22:36 +00:00
Luke Taylor b8e50c0933 SEC-1439: Make getters and setters public on HttpRequestResponseHolder.
Necessary to allow use of custom SecurityContextRepository.(cherry picked from commit d5df53f1db)
2010-03-12 15:54:12 +00:00
Luke Taylor 677576ea8b SEC-1429: Fix test. Wasn't setting allowSessionCreation=false on failure handler. 2010-03-11 02:30:37 +00:00
Luke Taylor 91153df78d SEC-1262: Added new (replacement) AspectJ interceptor which wraps the JoinPoint in a MethodInvocation adapter to provide compatibility with classes which only support MethodInvocation instances.
Also deprecated the existing AspectJ interceptors. This will also allow future simplification of the AbstractMethodSecurityMetadataSource, as it no longer needs to support JoinPoints.
2010-03-11 02:15:35 +00:00
Luke Taylor 1b0ac9c785 Porting of gradle changes from master. 2010-03-11 02:15:02 +00:00
Luke Taylor 8c9159f273 Added repo for aws-maen 3.0.0 dep 2010-03-06 01:41:38 +00:00
Luke Taylor 4c8b0faa88 Upgrade aws-maven to 3.0.0.RELEASE (mvn 2.2.x compatible) 2010-03-05 18:03:59 +00:00
Luke Taylor 5a5b62e2cb SEC-1429: Removed cached authentication from session after successful authentication.(cherry picked from commit 43f0e11106) 2010-03-05 00:11:08 +00:00
Luke Taylor 6ac8588144 Fix to Javadoc for AbstractAuthenticationProcessingFilter.(cherry picked from commit a3263753d9) 2010-03-04 22:07:30 +00:00
Luke Taylor 5690f1c581 SEC-1428: Check if response has been committed before redirecting to target URL in AbstractAuthenticationTargetUrlRequestHandler. 2010-03-04 22:00:37 +00:00
Luke Taylor 87cf27ab7c SEC-1429: Move logic for saving of AuthenticationException into the SimpleUrlAuthenticationFailurehandler from AbstractAuthenticationProcessingFilter. It will also now use request scope if configured to do a forward instead of a redirect. 2010-03-04 21:49:38 +00:00
Luke Taylor 41e06152b3 SEC-1420: JSP for itest of authentication tags with and without escaping. 2010-03-04 01:44:54 +00:00
Luke Taylor a7e21318bf SEC-1425: Replace use of Java 1.6 String.isEmpty(). 2010-03-04 00:52:54 +00:00
Luke Taylor bc6aae132b SEC-1420: Add htmlEscape attribute to authentication JSP tag.
This allows HTML escaping to be disabled if required.
2010-03-04 00:47:59 +00:00
Luke Taylor b46ae6ac62 SEC-1425: Add check for empty cookie in AbstractRememberMeServices.
Prevents ArrayOutOfBoundsException later when processing the tokeniszed cookie.
2010-02-28 14:00:43 +00:00
Luke Taylor 317da55cd0 SEC-1423: Cache PointcutExpression instances in ProtectPointcutPostProcessor for more efficient startup. 2010-02-26 17:50:45 +00:00
Luke Taylor 9e751e22c8 Refactoring to remove remaining circular dependencies indicated by structure101. 2010-02-26 17:50:14 +00:00
Luke Taylor 4d65b35827 Minor gradle 0.9 syntax change. 2010-02-26 17:49:32 +00:00
Luke Taylor 9831980bc2 Update versions to 3.0.3.CI-SNAPSHOT. 2010-02-26 15:04:43 +00:00
388 changed files with 11750 additions and 4475 deletions
+14 -1
View File
@@ -1,8 +1,21 @@
target/
*/src/*/java/META-INF
*/src/META-INF/
*/src/*/java/META-INF/
.classpath
.springBeans
.project
.DS_Store
.settings/
.idea/
out/
bin/
intellij/
build/
*.log
*.log.*
*.iml
*.ipr
*.iws
.gradle/
gradle.properties
atlassian-ide-plugin.xml
-1
View File
@@ -5,7 +5,6 @@ dependencies {
"net.sf.ehcache:ehcache:$ehcacheVersion",
"org.springframework:spring-aop:$springVersion",
"org.springframework:spring-context:$springVersion",
"org.springframework:spring-core:$springVersion",
"org.springframework:spring-tx:$springVersion",
"org.springframework:spring-jdbc:$springVersion"
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>spring-security-parent</artifactId>
<groupId>org.springframework.security</groupId>
<version>3.0.2.RELEASE</version>
<version>@pomVersion@</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
@@ -108,7 +108,7 @@ public class AclEntryAfterInvocationProvider extends AbstractAclProvider impleme
logger.debug("Denying access");
throw new AccessDeniedException(messages.getMessage("BasicAclEntryAfterInvocationProvider.noPermission",
throw new AccessDeniedException(messages.getMessage("AclEntryAfterInvocationProvider.noPermission",
new Object[] {authentication.getName(), returnedObject},
"Authentication {0} has NO permissions to the domain object {1}"));
}
@@ -379,15 +379,15 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
if (obj instanceof AclImpl) {
AclImpl rhs = (AclImpl) obj;
if (this.aces.equals(rhs.aces)) {
if ((this.parentAcl == null && rhs.parentAcl == null) || (this.parentAcl.equals(rhs.parentAcl))) {
if ((this.objectIdentity == null && rhs.objectIdentity == null) || (this.objectIdentity.equals(rhs.objectIdentity))) {
if ((this.id == null && rhs.id == null) || (this.id.equals(rhs.id))) {
if ((this.owner == null && rhs.owner == null) || this.owner.equals(rhs.owner)) {
if ((this.parentAcl == null && rhs.parentAcl == null) || (this.parentAcl !=null && this.parentAcl.equals(rhs.parentAcl))) {
if ((this.objectIdentity == null && rhs.objectIdentity == null) || (this.objectIdentity != null && this.objectIdentity.equals(rhs.objectIdentity))) {
if ((this.id == null && rhs.id == null) || (this.id != null && this.id.equals(rhs.id))) {
if ((this.owner == null && rhs.owner == null) || (this.owner != null && this.owner.equals(rhs.owner))) {
if (this.entriesInheriting == rhs.entriesInheriting) {
if ((this.loadedSids == null && rhs.loadedSids == null)) {
return true;
}
if (this.loadedSids.size() == rhs.loadedSids.size()) {
if (this.loadedSids != null && (this.loadedSids.size() == rhs.loadedSids.size())) {
for (int i = 0; i < this.loadedSids.size(); i++) {
if (!this.loadedSids.get(i).equals(rhs.loadedSids.get(i))) {
return false;
@@ -504,6 +504,16 @@ public class AclImplTests {
acl.deleteAce(1);
}
// SEC-1795
@Test
public void changingParentIsSuccessful() throws Exception {
AclImpl parentAcl = new AclImpl(objectIdentity, 1L, mockAuthzStrategy, mockAuditLogger);
AclImpl childAcl = new AclImpl(objectIdentity, 2L, mockAuthzStrategy, mockAuditLogger);
AclImpl changeParentAcl = new AclImpl(objectIdentity, 3L, mockAuthzStrategy, mockAuditLogger);
childAcl.setParent(parentAcl);
childAcl.setParent(changeParentAcl);
}
//~ Inner Classes ==================================================================================================
+14 -12
View File
@@ -1,3 +1,5 @@
Implementation-Title: org.springframework.security.acls
Implementation-Version: ${version}
Bundle-SymbolicName: org.springframework.security.acls
Bundle-Name: Spring Security Acls
Bundle-Vendor: SpringSource
@@ -7,15 +9,15 @@ Ignored-Existing-Headers:
Import-Package,
Export-Package
Import-Template:
org.apache.commons.logging.*;version="[1.0.4, 2.0.0)",
org.springframework.security.core.*;version="[${version}, 3.1.0)",
org.springframework.security.access.*;version="[${version}, 3.1.0)",
org.springframework.security.util.*;version="[${version}, 3.1.0)",
org.springframework.context.*;version="[${spring.version}, 3.1.0)";resolution:=optional,
org.springframework.dao.*;version="[${spring.version}, 3.1.0)";resolution:=optional,
org.springframework.jdbc.core.*;version="[${spring.version}, 3.1.0)";resolution:=optional,
org.springframework.transaction.support.*;version="[${spring.version}, 3.1.0)";resolution:=optional,
org.springframework.util.*;version="[${spring.version}, 3.1.0)";resolution:=optional,
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
javax.sql.*;version="0";resolution:=optional
org.aopalliance.*;version="${aopAllianceRange}",
org.apache.commons.logging.*;version="${cloggingRange}",
org.springframework.security.core.*;version="${secRange}",
org.springframework.security.access.*;version="${secRange}",
org.springframework.security.util.*;version="${secRange}",
org.springframework.context.*;version="${springRange}";resolution:=optional,
org.springframework.dao.*;version="${springRange}";resolution:=optional,
org.springframework.jdbc.core.*;version="${springRange}";resolution:=optional,
org.springframework.transaction.support.*;version="${springRange}";resolution:=optional,
org.springframework.util.*;version="${springRange}";resolution:=optional,
net.sf.ehcache.*;version="${ehcacheRange}";resolution:=optional,
javax.sql.*;version="0";resolution:=optional
+6
View File
@@ -0,0 +1,6 @@
dependencies {
compile project(':spring-security-core'),
"org.springframework:spring-beans:$springVersion",
"org.springframework:spring-context:$springVersion"
}
+4 -8
View File
@@ -5,16 +5,12 @@
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-parent</artifactId>
<version>3.0.2.RELEASE</version>
<version>@pomVersion@</version>
</parent>
<packaging>jar</packaging>
<artifactId>spring-security-aspects</artifactId>
<name>Spring Security - Aspects</name>
<dependencies>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
@@ -22,7 +18,7 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.0.2.RELEASE</version>
<version>@pomVersion@</version>
</dependency>
</dependencies>
<build>
@@ -39,12 +35,12 @@
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.5</version>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.6.5</version>
<version>1.6.8</version>
</dependency>
</dependencies>
<executions>
@@ -2,11 +2,12 @@ package org.springframework.security.access.intercept.aspectj.aspect;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.*;
import org.springframework.security.access.intercept.aspectj.AspectJCallback;
import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor;
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
/**
* Concrete AspectJ transaction aspect using Spring Security @Secured annotation
* Concrete AspectJ aspect using Spring Security @Secured annotation
* for JDK 1.5+.
*
* <p>
@@ -16,8 +17,8 @@ import org.springframework.security.access.intercept.aspectj.AspectJSecurityInte
* interfaces are <i>not</i> inherited. This will vary from Spring AOP.
*
* @author Mike Wiesner
* @since 1.0
* @version $Id$
* @author Luke Taylor
* @since 3.1
*/
public aspect AnnotationSecurityAspect implements InitializingBean {
@@ -34,11 +35,19 @@ public aspect AnnotationSecurityAspect implements InitializingBean {
private pointcut executionOfSecuredMethod() :
execution(* *(..)) && @annotation(Secured);
/**
* Matches the execution of any method with Pre/Post annotations.
*/
private pointcut executionOfPrePostAnnotatedMethod() :
execution(* *(..)) && (@annotation(PreAuthorize) || @annotation(PreFilter)
|| @annotation(PostAuthorize) || @annotation(PostFilter));
private pointcut securedMethodExecution() :
executionOfAnyPublicMethodInAtSecuredType() ||
executionOfSecuredMethod();
executionOfSecuredMethod() ||
executionOfPrePostAnnotatedMethod();
private AspectJSecurityInterceptor securityInterceptor;
private AspectJMethodSecurityInterceptor securityInterceptor;
Object around(): securedMethodExecution() {
if (this.securityInterceptor == null) {
@@ -54,13 +63,14 @@ public aspect AnnotationSecurityAspect implements InitializingBean {
return this.securityInterceptor.invoke(thisJoinPoint, callback);
}
public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) {
public void setSecurityInterceptor(AspectJMethodSecurityInterceptor securityInterceptor) {
this.securityInterceptor = securityInterceptor;
}
public void afterPropertiesSet() throws Exception {
if (this.securityInterceptor == null)
if (this.securityInterceptor == null) {
throw new IllegalArgumentException("securityInterceptor required");
}
}
}
@@ -0,0 +1,110 @@
package org.springframework.security.access.intercept.aspectj.aspect;
import java.util.Arrays;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.ExpressionBasedAnnotationAttributeFactory;
import org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice;
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
import org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
/**
*
* @author Luke Taylor
* @since 3.0.3
*/
public class AnnotationSecurityAspectTests {
private @Mock AccessDecisionManager adm;
private @Mock AuthenticationManager authman;
private TestingAuthenticationToken anne = new TestingAuthenticationToken("anne", "", "ROLE_A");
// private TestingAuthenticationToken bob = new TestingAuthenticationToken("bob", "", "ROLE_B");
private AspectJMethodSecurityInterceptor interceptor;
private SecuredImpl secured = new SecuredImpl();
private PrePostSecured prePostSecured = new PrePostSecured();
@Before
public final void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
interceptor = new AspectJMethodSecurityInterceptor();
interceptor.setAccessDecisionManager(adm);
interceptor.setAuthenticationManager(authman);
interceptor.setSecurityMetadataSource(new SecuredAnnotationSecurityMetadataSource());
AnnotationSecurityAspect secAspect = AnnotationSecurityAspect.aspectOf();
secAspect.setSecurityInterceptor(interceptor);
}
@After
public void clearContext() {
SecurityContextHolder.clearContext();
}
@Test
public void securedInterfaceMethodAllowsAllAccess() throws Exception {
secured.securedMethod();
}
@Test(expected=AuthenticationCredentialsNotFoundException.class)
public void securedClassMethodDeniesUnauthenticatedAccess() throws Exception {
secured.securedClassMethod();
}
@Test
public void securedClassMethodAllowsAccessToRoleA() throws Exception {
SecurityContextHolder.getContext().setAuthentication(anne);
secured.securedClassMethod();
}
// SEC-1262
@Test(expected=AccessDeniedException.class)
public void denyAllPreAuthorizeDeniesAccess() throws Exception {
SecurityContextHolder.getContext().setAuthentication(anne);
interceptor.setSecurityMetadataSource(new PrePostAnnotationSecurityMetadataSource(
new ExpressionBasedAnnotationAttributeFactory(new DefaultMethodSecurityExpressionHandler())));
AffirmativeBased adm = new AffirmativeBased();
AccessDecisionVoter[] voters = new AccessDecisionVoter[]
{new PreInvocationAuthorizationAdviceVoter(new ExpressionBasedPreInvocationAdvice())};
adm.setDecisionVoters(Arrays.asList(voters));
interceptor.setAccessDecisionManager(adm);
prePostSecured.denyAllMethod();
}
}
interface SecuredInterface {
@Secured("ROLE_X")
void securedMethod();
}
class SecuredImpl implements SecuredInterface {
// Not really secured because AspectJ doesn't inherit annotations from interfaces
public void securedMethod() {
}
@Secured("ROLE_A")
public void securedClassMethod() {
}
}
class PrePostSecured {
@PreAuthorize("denyAll")
public void denyAllMethod() {
}
}
+16
View File
@@ -0,0 +1,16 @@
Implementation-Title: org.springframework.security.aspects
Implementation-Version: ${version}
Bundle-SymbolicName: org.springframework.security.aspects
Bundle-Name: Spring Security Aspects
Bundle-Vendor: SpringSource
Bundle-ManifestVersion: 2
Bundle-Version: ${version}
Ignored-Existing-Headers:
Import-Package,
Export-Package
Import-Template:
org.aspectj.*;version="${aspectjRange}";resolution:=optional,
org.apache.commons.logging.*;version="${cloggingRange}",
org.springframework.security.core.*;version="${secRange}",
org.springframework.security.access.intercept.aspectj;version="${secRange}",
org.springframework.beans.factory;version="${springRange}"
+41 -232
View File
@@ -1,266 +1,75 @@
import java.util.jar.Manifest
import org.gradle.api.tasks.bundling.GradleManifest
apply id: 'base'
apply plugin: 'base'
description = 'Spring Security'
allprojects {
version = '3.0.2.RELEASE'
releaseBuild = version.endsWith('RELEASE')
snapshotBuild = version.endsWith('SNAPSHOT')
ext.releaseBuild = version.endsWith('RELEASE')
ext.snapshotBuild = version.endsWith('SNAPSHOT')
group = 'org.springframework.security'
repositories {
mavenRepo name:'Local', urls:'file:///Users/luke/.m2/repository'
mavenCentral()
// mavenRepo name:'SpringSource Milestone Repo', urls:'http://repository.springsource.com/maven/bundles/milestone'
}
}
configure(javaProjects()) {
apply id: 'java'
springVersion = '3.0.1.RELEASE'
springLdapVersion = '1.3.0.RELEASE'
ehcacheVersion = '1.6.2'
aspectjVersion = '1.6.8'
apacheDsVersion = '1.5.5'
jstlVersion = '1.1.2'
jettyVersion = '6.1.22'
configurations {
bundlor
provided
}
dependencies {
compile 'commons-logging:commons-logging:1.1.1'
testCompile 'junit:junit:4.7',
'org.mockito:mockito-core:1.7',
'org.jmock:jmock:2.5.1',
'org.jmock:jmock-junit4:2.5.1',
'org.hamcrest:hamcrest-core:1.1',
'org.hamcrest:hamcrest-library:1.1',
"org.springframework:spring-test:$springVersion"
bundlor 'com.springsource.bundlor:com.springsource.bundlor.ant:1.0.0.RC1',
'com.springsource.bundlor:com.springsource.bundlor:1.0.0.RC1',
'com.springsource.bundlor:com.springsource.bundlor.blint:1.0.0.RC1'
}
sourceSets {
main {
compileClasspath = compileClasspath + configurations.provided
}
test {
compileClasspath = compileClasspath + configurations.provided
runtimeClasspath = runtimeClasspath + configurations.provided
}
}
test {
options.fork(forkMode: ForkMode.ONCE, jvmArgs: ["-ea", '-Xms128m', '-Xmx500m', '-XX:MaxPermSize=128m', '-XX:+HeapDumpOnOutOfMemoryError'])
}
task bundlor (dependsOn: compileJava) << {
if (!dependsOnTaskDidWork()) {
return
}
ant.taskdef(resource: 'com/springsource/bundlor/ant/antlib.xml', classpath: configurations.bundlor.asPath)
File template = new File(projectDir, 'template.mf')
mkdir(buildDir, 'bundlor')
if (template.exists()) {
ant.bundlor(inputPath: sourceSets.main.classesDir, outputPath: "$buildDir/bundlor", manifestTemplatePath: template) {
property(name: 'version', value: "$version")
property(name: 'spring.version', value: "$springVersion")
}
// See GRADLE-395 for support for using an existing manifest
jar.manifest = new GradleManifest(new Manifest(new File("$buildDir/bundlor/META-INF/MANIFEST.MF").newInputStream()))
}
}
jar.dependsOn bundlor
// Set up different subproject lists for individual configuration
ext.javaProjects = subprojects.findAll { project -> project.name != 'docs' && project.name != 'faq' && project.name != 'manual' }
ext.sampleProjects = subprojects.findAll { project -> project.name.startsWith('spring-security-samples') }
ext.itestProjects = subprojects.findAll { project -> project.name.startsWith('itest') }
ext.coreModuleProjects = javaProjects - sampleProjects - itestProjects
ext.aspectjProjects = [project(':spring-security-aspects'), project(':spring-security-samples-aspectj')]
configure(javaProjects) {
apply from: "$rootDir/gradle/javaprojects.gradle"
}
configure(javaProjects()) {
apply id: 'maven'
// Create a source jar for uploading
task sourceJar(type: Jar) {
classifier = 'sources'
from sourceSets.main.java
}
configurations {
deployerJars
}
artifacts {
archives sourceJar
}
dependencies {
deployerJars "org.springframework.build.aws:org.springframework.build.aws.maven:2.0.1.BUILD-SNAPSHOT"
}
uploadArchives {
repositories.mavenDeployer {
configuration = configurations.deployerJars
if (releaseBuild) {
// "mavenSyncRepoDir" should be set in properties
repository(url: mavenSyncRepoDir)
} else {
s3credentials = [userName: s3AccessKey, passphrase: s3SecretAccessKey]
repository(url: "s3://maven.springframework.org/milestone") {
authentication(s3credentials)
}
snapshotRepository(url: "s3://maven.springframework.org/snapshot") {
authentication(s3credentials)
}
}
}
}
conf2ScopeMappings.addMapping(1, configurations.provided, "provided")
}
configure(coreModuleProjects()) {
configure(coreModuleProjects) {
// Gives better names in structure101 jar diagram
sourceSets.main.classesDir = new File(buildDir, "classes/" + project.name.substring("spring-security".length() + 1))
sourceSets.main.output.classesDir = new File(buildDir, "classes/" + project.name.substring("spring-security".length() + 1))
apply plugin: 'bundlor'
bundlor.expansions = bundlorProperties
apply from: "$rootDir/gradle/maven-deployment.gradle"
apply plugin: 'emma'
}
repositories {
// Required for ant s3 task
mavenRepo name: "s2.com release", urls: "http://repository.springsource.com/maven/bundles/release"
task coreBuild {
dependsOn coreModuleProjects*.tasks*.matching { task -> task.name == 'build' }
}
configurations {
antlibs
configure (aspectjProjects) {
apply plugin: 'aspectj'
}
dependencies {
antlibs "org.springframework.build:org.springframework.build.aws.ant:3.0.3.RELEASE",
"net.java.dev.jets3t:jets3t:0.6.1"
}
// Task for creating the distro zip
def docsDir = new File(project(':manual').buildDir, 'docs')
task apidocs(type: Javadoc) {
destinationDir = new File(buildDir, 'apidocs')
title = "Spring Security $version API"
optionsFile = file("$buildDir/tmp/javadoc.options")
source coreModuleProjects().collect { project ->
project.sourceSets.main.allJava
}
classpath = files(coreModuleProjects().collect { project ->
project.sourceSets.main.compileClasspath })
}
task apitar(type: Tar, dependsOn: apidocs) {
compression = Compression.BZIP2
classifier = 'apidocs'
into('apidocs') {
from apidocs.destinationDir
}
}
task doctar(type: Tar, dependsOn: ':manual:doc') {
compression = Compression.BZIP2
classifier = 'doc'
into('reference') {
from docsDir
}
}
def username;
def password;
task login << {
ant.input("Please enter the ssh username for host '$sshHost'", addproperty: "ssh.username")
ant.input("Please enter the ssh password '$sshHost'", addproperty: "ssh.password")
username = ant.properties['ssh.username']
password = ant.properties['ssh.password']
}
task uploadApidocs (dependsOn: login) << {
ant.scp(file: apitar.archivePath, todir: "$username@$sshHost:$remoteDocsDir", password: password)
ant.sshexec(host: sshHost, username: username, password: password, command: "cd $remoteDocsDir && tar -xjf ${apitar.archiveName}")
ant.sshexec(host: sshHost, username: username, password: password, command: "rm $remoteDocsDir/${apitar.archiveName}")
}
task uploadManual (dependsOn: login) << {
ant.scp(file: doctar.archivePath, todir: "$username@$sshHost:$remoteDocsDir", password: password)
ant.sshexec(host: sshHost, username: username, password: password, command: "cd $remoteDocsDir && tar -xjf ${doctar.archiveName}")
ant.sshexec(host: sshHost, username: username, password: password, command: "rm $remoteDocsDir/${doctar.archiveName}")
}
task dist (type: Zip) {
task dist(type: Zip) {
dependsOn subprojects*.tasks*.matching { task -> task.name == 'assemble' || task.name.endsWith('Zip') }
classifier = 'dist'
evaluationDependsOn(':docs')
def zipRootDir = "${project.name}-$version"
into (zipRootDir) {
into('docs/apidocs') {
from apidocs.destinationDir
into(zipRootDir) {
from(rootDir) {
include '*.txt'
}
into('docs/reference') {
from docsDir
into('docs') {
with(project(':docs').apiSpec)
with(project(':docs:manual').spec)
}
into('dist') {
from coreModuleProjects().collect { project -> project.libsDir }
from coreModuleProjects.collect {project -> project.libsDir }
from project(':spring-security-samples-tutorial').libsDir
from project(':spring-security-samples-contacts').libsDir
}
}
}
dist.dependsOn apidocs, ':manual:doc'
dist.dependsOn subprojects.collect { "$it.path:assemble" }
dist.doLast {
ant.checksum(file: archivePath, algorithm: 'SHA1', fileext: '.sha1')
artifacts {
archives dist
archives project(':docs').docsZip
archives project(':docs').schemaZip
}
task uploadDist << {
def shaFile = file("${dist.archivePath}.sha1")
assert dist.archivePath.isFile()
assert shaFile.isFile()
ant.taskdef(resource: 'org/springframework/build/aws/ant/antlib.xml', classpath: configurations.antlibs.asPath)
ant.s3(accessKey: s3AccessKey, secretKey: s3SecretAccessKey) {
upload(bucketName: 'dist.springframework.org', file: dist.archivePath,
toFile: releaseType() + "/SEC/${dist.archiveName}", publicRead: 'true') {
metadata(name: 'project.name', value: 'Spring Security')
metadata(name: 'release.type', value: releaseType())
metadata(name: 'bundle.version', value: version)
metadata(name: 'package.file.name', value: dist.archiveName)
}
upload(bucketName: 'dist.springframework.org', file: shaFile,
toFile: releaseType() + "/SEC/${dist.archiveName}.sha1", publicRead: 'true')
}
}
apply from: "$rootDir/gradle/ide-integration.gradle"
def javaProjects() {
subprojects.findAll { project -> project.name != 'faq' && project.name != 'manual' }
task wrapper(type: Wrapper) {
gradleVersion = '1.1'
}
def sampleProjects() {
subprojects.findAll { project -> project.name.startsWith('spring-security-samples') }
}
def itestProjects() {
subprojects.findAll { project -> project.name.startsWith('itest') }
}
def coreModuleProjects() {
javaProjects() - sampleProjects() - itestProjects()
}
def releaseType() {
if (releaseBuild) {
'release'
} else if (snapshotBuild) {
'snapshot'
} else {
'milestone'
}
}
+55
View File
@@ -0,0 +1,55 @@
apply plugin: 'groovy'
repositories {
mavenCentral()
maven {
name = 'SpringSource Enterprise Release'
url = 'http://repository.springsource.com/maven/bundles/release'
}
maven {
name = 'SpringSource Enterprise External'
url = 'http://repository.springsource.com/maven/bundles/external'
}
}
// Docbook Plugin
dependencies {
def fopDeps = [ 'org.apache.xmlgraphics:fop:0.95-1@jar',
'org.apache.xmlgraphics:xmlgraphics-commons:1.3',
'org.apache.xmlgraphics:batik-bridge:1.7@jar',
'org.apache.xmlgraphics:batik-util:1.7@jar',
'org.apache.xmlgraphics:batik-css:1.7@jar',
'org.apache.xmlgraphics:batik-dom:1.7',
'org.apache.xmlgraphics:batik-svg-dom:1.7@jar',
'org.apache.avalon.framework:avalon-framework-api:4.3.1']
groovy localGroovy()
compile gradleApi(),
'xml-resolver:xml-resolver:1.2',
'xerces:xercesImpl:2.9.1',
'saxon:saxon:6.5.3',
'net.java.dev.jets3t:jets3t:0.6.1',
fopDeps
runtime 'net.sf.xslthl:xslthl:2.0.1',
'net.sf.docbook:docbook-xsl:1.75.2:ns-resources@zip'
}
// GAE
dependencies {
compile 'com.google.appengine:appengine-tools-sdk:1.4.2'
}
dependencies{
compile "emma:emma:2.0.5312"
}
// Bundlor
dependencies {
compile 'com.springsource.bundlor:com.springsource.bundlor:1.0.0.RELEASE',
'com.springsource.bundlor:com.springsource.bundlor.blint:1.0.0.RELEASE'
}
task ide(type: Copy) {
from configurations.runtime
into 'ide'
}
@@ -0,0 +1,108 @@
package aspectj
import org.gradle.api.Project
import org.gradle.api.Plugin
import org.gradle.api.tasks.TaskAction
import org.gradle.api.logging.LogLevel
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.SourceSet
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.plugins.ide.eclipse.GenerateEclipseProject
import org.gradle.plugins.ide.eclipse.GenerateEclipseClasspath
import org.gradle.plugins.ide.eclipse.EclipsePlugin
import org.gradle.plugins.ide.eclipse.model.BuildCommand
import org.gradle.plugins.ide.eclipse.model.ProjectDependency
/**
*
* @author Luke Taylor
*/
class AspectJPlugin implements Plugin<Project> {
void apply(Project project) {
if (!project.hasProperty('aspectjVersion')) {
throw new GradleException("You must set the property 'aspectjVersion' before applying the aspectj plugin")
}
if (project.configurations.findByName('ajtools') == null) {
project.configurations.add('ajtools')
project.dependencies {
ajtools "org.aspectj:aspectjtools:${project.aspectjVersion}"
compile "org.aspectj:aspectjrt:${project.aspectjVersion}"
}
}
if (project.configurations.findByName('aspectpath') == null) {
project.configurations.add('aspectpath')
}
project.tasks.add(name: 'compileJava', overwrite: true, description: 'Compiles AspectJ Source', type: Ajc) {
dependsOn project.processResources
sourceSet = project.sourceSets.main
inputs.files(sourceSet.java.srcDirs)
outputs.dir(sourceSet.output.classesDir)
aspectPath = project.configurations.aspectpath
}
project.tasks.add(name: 'compileTestJava', overwrite: true, description: 'Compiles AspectJ Test Source', type: Ajc) {
dependsOn project.processTestResources, project.compileJava, project.jar
sourceSet = project.sourceSets.test
inputs.files(sourceSet.java.srcDirs)
outputs.dir(sourceSet.output.classesDir)
aspectPath = project.files(project.configurations.aspectpath, project.jar.archivePath)
}
project.tasks.withType(GenerateEclipseProject) {
project.eclipse.project.file.whenMerged { p ->
p.natures.add(0, 'org.eclipse.ajdt.ui.ajnature')
p.buildCommands = [new BuildCommand('org.eclipse.ajdt.core.ajbuilder')]
}
}
project.tasks.withType(GenerateEclipseClasspath) {
project.eclipse.classpath.file.whenMerged { classpath ->
def entries = classpath.entries.findAll { it instanceof ProjectDependency}.findAll { entry ->
def projectPath = entry.path.replaceAll('/',':')
println projectPath
project.rootProject.allprojects.find{ p->
if(p.plugins.findPlugin(EclipsePlugin)) {
println " checking " + p.eclipse.project.name
return p.eclipse.project.name == projectPath && p.plugins.findPlugin(AspectJPlugin)
}
false
}
}
entries.each { entry->
entry.entryAttributes.put('org.eclipse.ajdt.aspectpath','org.eclipse.ajdt.aspectpath')
}
}
}
}
}
class Ajc extends DefaultTask {
SourceSet sourceSet
FileCollection aspectPath
Ajc() {
logging.captureStandardOutput(LogLevel.INFO)
}
@TaskAction
def compile() {
logger.info("Running ajc ...")
ant.taskdef(resource: "org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties", classpath: project.configurations.ajtools.asPath)
ant.iajc(classpath: sourceSet.compileClasspath.asPath, fork: 'true', destDir: sourceSet.output.classesDir.absolutePath,
source: project.convention.plugins.java.sourceCompatibility,
target: project.convention.plugins.java.targetCompatibility,
aspectPath: aspectPath.asPath, sourceRootCopyFilter: '**/*.java', showWeaveInfo: 'true') {
sourceroots {
sourceSet.java.srcDirs.each {
pathelement(location: it.absolutePath)
}
}
}
}
}
@@ -0,0 +1,150 @@
package bundlor
import com.springsource.bundlor.ClassPath
import com.springsource.bundlor.ManifestGenerator
import com.springsource.bundlor.ManifestWriter
import com.springsource.bundlor.blint.ManifestValidator
import com.springsource.bundlor.blint.support.DefaultManifestValidatorContributorsFactory
import com.springsource.bundlor.blint.support.StandardManifestValidator
import com.springsource.bundlor.support.DefaultManifestGeneratorContributorsFactory
import com.springsource.bundlor.support.StandardManifestGenerator
import com.springsource.bundlor.support.classpath.FileSystemClassPath
import com.springsource.bundlor.support.manifestwriter.FileSystemManifestWriter
import com.springsource.bundlor.support.properties.EmptyPropertiesSource
import com.springsource.bundlor.support.properties.FileSystemPropertiesSource
import com.springsource.bundlor.support.properties.PropertiesPropertiesSource
import com.springsource.bundlor.support.properties.PropertiesSource
import com.springsource.bundlor.util.BundleManifestUtils
import com.springsource.util.parser.manifest.ManifestContents
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.FileCollection
import org.gradle.api.logging.LogLevel
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
/**
* @author Luke Taylor
*/
class BundlorPlugin implements Plugin<Project> {
void apply(Project project) {
Task bundlor = project.tasks.add('bundlor', Bundlor.class)
bundlor.setDescription('Generates OSGi manifest using bundlor tool')
bundlor.dependsOn(project.classes)
project.jar.dependsOn bundlor
}
}
public class Bundlor extends DefaultTask {
@InputFile
@Optional
File manifestTemplate
@OutputDirectory
File bundlorDir = new File("${project.buildDir}/bundlor")
@OutputFile
File manifest = project.file("${bundlorDir}/META-INF/MANIFEST.MF")
@Input
Map<String,String> expansions = [:]
@InputFile
@Optional
File osgiProfile
@InputFiles
@Optional
FileCollection inputPaths
@Input
boolean failOnWarnings = false
Bundlor() {
manifestTemplate = new File(project.projectDir, 'template.mf')
if (!manifestTemplate.exists()) {
logger.info("No bundlor template for project " + project.name)
manifestTemplate = null
}
inputPaths = project.files(project.sourceSets.main.output.classesDir)
if (manifestTemplate != null) {
project.jar.manifest.from manifest
project.jar.inputs.files manifest
}
}
@TaskAction
void createManifest() {
if (manifestTemplate == null) {
return;
}
logging.captureStandardOutput(LogLevel.INFO)
project.mkdir(bundlorDir)
//String inputPath = project.sourceSets.main.classesDir
List<ClassPath> inputClassPath = [] as List;
ManifestWriter manifestWriter = new FileSystemManifestWriter(project.file(bundlorDir.absolutePath));
ManifestContents mfTemplate = BundleManifestUtils.getManifest(manifestTemplate);
inputPaths.each {f ->
inputClassPath.add(new FileSystemClassPath(f))
}
// Must be a better way of doing this...
Properties p = new Properties()
expansions.each {entry ->
p.setProperty(entry.key, entry.value as String)
}
PropertiesSource expansionProps = new PropertiesPropertiesSource(p)
PropertiesSource osgiProfileProps = osgiProfile == null ? new EmptyPropertiesSource() :
new FileSystemPropertiesSource(osgiProfile);
ManifestGenerator manifestGenerator = new StandardManifestGenerator(
DefaultManifestGeneratorContributorsFactory.create(expansionProps, osgiProfileProps));
ManifestContents mf = manifestGenerator.generate(mfTemplate, inputClassPath.toArray(new ClassPath[inputClassPath.size()]));
try {
manifestWriter.write(mf);
} finally {
manifestWriter.close();
}
ManifestValidator manifestValidator = new StandardManifestValidator(DefaultManifestValidatorContributorsFactory.create());
List<String> warnings = manifestValidator.validate(mf);
if (warnings.isEmpty()) {
return
}
logger.warn("Bundlor Warnings:");
for (String warning : warnings) {
logger.warn(" " + warning);
}
if (failOnWarnings) {
throw new GradleException("Bundlor returned warnings. Please fix manifest template at " + manifestTemplate.absolutePath + " and try again.")
}
}
def inputPath(FileCollection paths) {
inputPaths = project.files(inputPaths, paths)
}
}
@@ -0,0 +1,301 @@
package docbook;
import org.gradle.api.Plugin;
import org.gradle.api.GradleException;
import org.gradle.api.DefaultTask;
import org.gradle.api.Task;
import org.gradle.api.Project;
import org.gradle.api.Action;
import org.gradle.api.tasks.*;
import org.gradle.api.file.FileCollection;
import org.xml.sax.XMLReader;
import org.xml.sax.InputSource;
import org.apache.xml.resolver.CatalogManager;
import org.apache.xml.resolver.tools.CatalogResolver;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.*;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.util.*;
import java.util.zip.*;
import java.net.*;
import org.apache.fop.apps.*;
import com.icl.saxon.TransformerFactoryImpl;
/**
* Gradle Docbook plugin implementation.
* <p>
* Creates three tasks: docbookHtml, docbookHtmlSingle and docbookPdf. Each task takes a single File on
* which it operates.
*/
class DocbookPlugin implements Plugin<Project> {
public void apply(Project project) {
// Add the plugin tasks to the project
Task docbookHtml = project.tasks.add('docbookHtml', DocbookHtml.class);
docbookHtml.setDescription('Generates chunked docbook html output');
Task docbookHtmlSingle = project.tasks.add('docbookHtmlSingle', Docbook.class);
docbookHtmlSingle.setDescription('Generates single page docbook html output')
docbookHtmlSingle.suffix = '-single'
Task docbookFoPdf = project.tasks.add("docbookFoPdf", DocbookFoPdf.class);
docbookFoPdf.setDescription('Generates PDF output');
docbookFoPdf.extension = 'fo'
Task docbook = project.tasks.add("docbook", DefaultTask.class);
docbook.dependsOn (docbookHtml, docbookHtmlSingle, docbookFoPdf)
}
}
/**
*/
public class Docbook extends DefaultTask {
@Input
String extension = 'html';
@Input
String suffix = '';
@Input
boolean XIncludeAware = true;
@Input
boolean highlightingEnabled = true;
String admonGraphicsPath;
String imgSrcPath;
@InputDirectory
File sourceDirectory = new File(project.getProjectDir(), "src/docbook");
@Input
String sourceFileName;
@InputFile
File stylesheet;
@OutputDirectory
File docsDir = new File(project.getBuildDir(), "docs");
@TaskAction
public final void transform() {
SAXParserFactory factory = new org.apache.xerces.jaxp.SAXParserFactoryImpl();
factory.setXIncludeAware(XIncludeAware);
docsDir.mkdirs();
File srcFile = new File(filterDocbookSources(sourceDirectory), sourceFileName);
String outputFilename = srcFile.getName().substring(0, srcFile.getName().length() - 4) + suffix + '.' + extension;
File outputFile = new File(getDocsDir(), outputFilename);
Result result = new StreamResult(outputFile.getAbsolutePath());
CatalogResolver resolver = new CatalogResolver(createCatalogManager());
InputSource inputSource = new InputSource(srcFile.getAbsolutePath());
XMLReader reader = factory.newSAXParser().getXMLReader();
reader.setEntityResolver(resolver);
TransformerFactory transformerFactory = new TransformerFactoryImpl();
transformerFactory.setURIResolver(resolver);
URL url = stylesheet.toURL();
Source source = new StreamSource(url.openStream(), url.toExternalForm());
Transformer transformer = transformerFactory.newTransformer(source);
if (highlightingEnabled) {
File highlightingDir = new File(getProject().getBuildDir(), "highlighting");
if (!highlightingDir.exists()) {
highlightingDir.mkdirs();
extractHighlightFiles(highlightingDir);
}
transformer.setParameter("highlight.xslthl.config", new File(highlightingDir, "xslthl-config.xml").toURI().toURL());
}
if (admonGraphicsPath != null) {
transformer.setParameter("admon.graphics", "1");
transformer.setParameter("admon.graphics.path", admonGraphicsPath);
}
if (imgSrcPath != null) {
transformer.setParameter("img.src.path", imgSrcPath);
}
preTransform(transformer, srcFile, outputFile);
transformer.transform(new SAXSource(reader, inputSource), result);
postTransform(outputFile);
}
/**
* @param sourceDir directory of unfiltered sources
* @return directory of filtered sources
* @author Chris Beams
*/
private File filterDocbookSources(File sourceDir) {
def docbookWorkDir = new File("${project.buildDir}/reference-work")
docbookWorkDir.mkdirs()
// copy everything but springsecurity.xml
project.copy {
into(docbookWorkDir)
from(sourceDir) { exclude '**/springsecurity.xml' }
}
// copy index.xml and expand ${...} variables along the way
// e.g.: ${version} needs to be replaced in the header
project.copy {
into(docbookWorkDir)
from(sourceDir) { include '**/springsecurity.xml' }
expand(version: "${project.version}")
}
return docbookWorkDir
}
private void extractHighlightFiles(File toDir) {
URLClassLoader cl = (URLClassLoader) getClass().getClassLoader();
URL[] urls = cl.getURLs();
URL docbookZip = null;
for (URL url : urls) {
if (url.toString().contains("docbook-xsl-")) {
docbookZip = url;
break;
}
}
if (docbookZip == null) {
throw new GradleException("Docbook zip file not found");
}
ZipFile zipFile = new ZipFile(new File(docbookZip.toURI()));
Enumeration e = zipFile.entries();
while (e.hasMoreElements()) {
ZipEntry ze = (ZipEntry) e.nextElement();
if (ze.getName().matches(".*/highlighting/.*\\.xml")) {
String filename = ze.getName().substring(ze.getName().lastIndexOf("/highlighting/") + 14);
copyFile(zipFile.getInputStream(ze), new File(toDir, filename));
}
}
}
private void copyFile(InputStream source, File destFile) {
destFile.createNewFile();
FileOutputStream to = null;
try {
to = new FileOutputStream(destFile);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = source.read(buffer)) > 0) {
to.write(buffer, 0, bytesRead);
}
} finally {
if (source != null) {
source.close();
}
if (to != null) {
to.close();
}
}
}
protected void preTransform(Transformer transformer, File sourceFile, File outputFile) {
}
protected void postTransform(File outputFile) {
}
private CatalogManager createCatalogManager() {
CatalogManager manager = new CatalogManager();
manager.setIgnoreMissingProperties(true);
ClassLoader classLoader = this.getClass().getClassLoader();
StringBuilder builder = new StringBuilder();
String docbookCatalogName = "docbook/catalog.xml";
URL docbookCatalog = classLoader.getResource(docbookCatalogName);
if (docbookCatalog == null) {
throw new IllegalStateException("Docbook catalog " + docbookCatalogName + " could not be found in " + classLoader);
}
builder.append(docbookCatalog.toExternalForm());
Enumeration enumeration = classLoader.getResources("/catalog.xml");
while (enumeration.hasMoreElements()) {
builder.append(';');
URL resource = (URL) enumeration.nextElement();
builder.append(resource.toExternalForm());
}
String catalogFiles = builder.toString();
manager.setCatalogFiles(catalogFiles);
return manager;
}
}
/**
*/
class DocbookHtml extends Docbook {
@Override
protected void preTransform(Transformer transformer, File sourceFile, File outputFile) {
String rootFilename = outputFile.getName();
rootFilename = rootFilename.substring(0, rootFilename.lastIndexOf('.'));
transformer.setParameter("root.filename", rootFilename);
transformer.setParameter("base.dir", outputFile.getParent() + File.separator);
}
}
/**
*/
class DocbookFoPdf extends Docbook {
/**
* <a href="http://xmlgraphics.apache.org/fop/0.95/embedding.html#render">From the FOP usage guide</a>
*/
@Override
protected void postTransform(File foFile) {
FopFactory fopFactory = FopFactory.newInstance();
OutputStream out = null;
final File pdfFile = getPdfOutputFile(foFile);
logger.debug("Transforming 'fo' file "+ foFile + " to PDF: " + pdfFile);
try {
out = new BufferedOutputStream(new FileOutputStream(pdfFile));
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, out);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
Source src = new StreamSource(foFile);
Result res = new SAXResult(fop.getDefaultHandler());
transformer.transform(src, res);
} finally {
if (out != null) {
out.close();
}
}
/* if (!foFile.delete()) {
logger.warn("Failed to delete 'fo' file " + foFile);
}*/
}
private File getPdfOutputFile(File foFile) {
String name = foFile.getAbsolutePath();
return new File(name.substring(0, name.length() - 2) + "pdf");
}
}
@@ -0,0 +1,114 @@
package emma;
import org.gradle.api.*
import org.gradle.api.tasks.testing.Test
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.Input
import com.vladium.emma.instr.InstrProcessor
import com.vladium.emma.report.ReportProcessor
import org.gradle.api.tasks.InputFiles
import com.vladium.util.XProperties;
/**
*
* @author Luke Taylor
*/
class EmmaPlugin implements Plugin<Project> {
void apply(Project project) {
Project rootProject = project.rootProject
def emmaMetaDataFile = "${rootProject.buildDir}/emma/emma.em"
def emmaCoverageFile = "${rootProject.buildDir}/emma/emma.ec"
if (project.configurations.findByName('emma_rt') == null) {
project.configurations.add('emma_rt')
project.dependencies {
emma_rt 'emma:emma:2.0.5312'
}
}
project.task('emmaInstrument') {
dependsOn project.classes
doFirst {
InstrProcessor processor = InstrProcessor.create ();
String[] classesDirPath = [project.sourceSets.main.output.classesDir.absolutePath]
processor.setInstrPath(classesDirPath, false);
processor.setOutMode(InstrProcessor.OutMode.OUT_MODE_COPY);
processor.setInstrOutDir("${project.buildDir}/emma/classes");
processor.setMetaOutFile(emmaMetaDataFile);
processor.setMetaOutMerge(true);
//processor.setInclExclFilter (null);
processor.run();
}
}
// Modify test tasks in the project to generate coverage data
project.afterEvaluate {
if (project.hasProperty('coverage') && ['on','true'].contains(project.properties.coverage)) {
project.tasks.withType(Test.class).each { task ->
task.dependsOn project.emmaInstrument
task.configure() {
jvmArgs '-Dsec.log.level=DEBUG', "-Demma.coverage.out.file=$emmaCoverageFile"
jvmArgs '-Demma.verbosity.level=quiet'
}
task.doFirst {
classpath = project.files("${project.buildDir}/emma/classes") + project.configurations.emma_rt + classpath
}
}
}
}
List<Task> reportTasks = rootProject.getTasksByName('coverageReport', false) as List;
CoverageReport task;
if (reportTasks.isEmpty()) {
task = rootProject.tasks.add('coverageReport', CoverageReport.class);
task.dataPath = [emmaMetaDataFile, emmaCoverageFile];
} else {
task = reportTasks[0];
}
task.modules.add(project);
}
}
class CoverageReport extends DefaultTask {
@Input
List<Project> modules = [];
@Input
String[] dataPath;
@TaskAction
void generateReport() {
def buildDir = project.rootProject.buildDir
if (!buildDir.exists()) {
throw new GradleException("No coverage data. Run gradle with -Pcoverage=on if using coverageReport");
}
ReportProcessor processor = ReportProcessor.create ();
processor.setDataPath(dataPath)
def srcPath = []
modules.each {module->
module.sourceSets.main.java.srcDirs.each {
srcPath.add(it.absolutePath)
}
}
processor.setSourcePath(srcPath as String[]);
def types = ['txt', 'html']
processor.setReportTypes(types as String[]);
XProperties properties = new XProperties();
properties.setProperty('report.html.out.file', "$buildDir/emma/coverage.html");
properties.setProperty('report.txt.out.file', "$buildDir/emma/coverage.txt");
processor.setPropertyOverrides(properties)
processor.run()
}
}
@@ -0,0 +1,26 @@
package gae;
import com.google.appengine.tools.admin.AppCfg
import org.gradle.api.*;
class GaePlugin implements Plugin<Project> {
public void apply(Project project) {
if (!project.hasProperty('appEngineSdkRoot')) {
println "'appEngineSdkRoot' must be set in gradle.properties"
} else {
System.setProperty('appengine.sdk.root', project.property('appEngineSdkRoot'))
}
File explodedWar = new File(project.buildDir, "gae-exploded")
project.task('gaeDeploy') << {
AppCfg.main("update", explodedWar.toString())
}
project.gaeDeploy.dependsOn project.war
project.war.doLast {
ant.unzip(src: project.war.archivePath, dest: explodedWar)
}
}
}
@@ -0,0 +1 @@
implementation-class=aspectj.AspectJPlugin
@@ -0,0 +1 @@
implementation-class=bundlor.BundlorPlugin
@@ -0,0 +1 @@
implementation-class=docbook.DocbookPlugin
@@ -0,0 +1 @@
implementation-class=emma.EmmaPlugin
@@ -0,0 +1 @@
implementation-class=gae.GaePlugin
+5 -5
View File
@@ -2,12 +2,12 @@
dependencies {
compile project(':spring-security-core'),
project(':spring-security-web'),
"javax.servlet:servlet-api:2.5",
"org.springframework:spring-core:$springVersion",
"org.springframework:spring-context:$springVersion",
"org.springframework:spring-context:$springVersion",
"org.springframework:spring-beans:$springVersion",
"org.springframework:spring-tx:$springVersion",
"org.springframework:spring-web:$springVersion",
"org.springframework:spring-web:$springVersion",
"org.jasig.cas:cas-client-core:3.1.9",
"net.sf.ehcache:ehcache:$ehcacheVersion"
}
provided 'javax.servlet:servlet-api:2.5'
}
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-parent</artifactId>
<version>3.0.2.RELEASE</version>
<version>@pomVersion@</version>
</parent>
<artifactId>spring-security-cas-client</artifactId>
<name>Spring Security - CAS support</name>
@@ -59,7 +59,7 @@ public class CasAuthenticationToken extends AbstractAuthenticationToken implemen
* @throws IllegalArgumentException if a <code>null</code> was passed
*/
public CasAuthenticationToken(final String key, final Object principal, final Object credentials,
final Collection<GrantedAuthority> authorities, final UserDetails userDetails, final Assertion assertion) {
final Collection<? extends GrantedAuthority> authorities, final UserDetails userDetails, final Assertion assertion) {
super(authorities);
if ((key == null) || ("".equals(key)) || (principal == null) || "".equals(principal) || (credentials == null)
@@ -54,6 +54,7 @@ import org.springframework.security.web.authentication.AbstractAuthenticationPro
* By default this filter processes the URL <tt>/j_spring_cas_security_check</tt>.
*
* @author Ben Alex
* @author Rob Winch
*/
public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
//~ Static fields/initializers =====================================================================================
@@ -89,7 +90,13 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
//~ Methods ========================================================================================================
public Authentication attemptAuthentication(final HttpServletRequest request, final HttpServletResponse response)
throws AuthenticationException {
throws AuthenticationException, IOException {
// if the request is a proxy request process it and return null to indicate the request has been processed
if(isProxyRequest(request)) {
CommonUtils.readAndRespondToProxyReceptorRequest(request, response, this.proxyGrantingTicketStorage);
return null;
}
final String username = CAS_STATEFUL_IDENTIFIER;
String password = request.getParameter(this.artifactParameter);
@@ -108,18 +115,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
* 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);
}
return isProxyRequest(request) || super.requiresAuthentication(request, response);
}
public final void setProxyReceptorUrl(final String proxyReceptorUrl) {
@@ -134,4 +130,14 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
public final void setServiceProperties(final ServiceProperties serviceProperties) {
this.artifactParameter = serviceProperties.getArtifactParameter();
}
/**
* Indicates if the request is eligible to be processed as a proxy request.
* @param request
* @return
*/
private boolean isProxyRequest(final HttpServletRequest request) {
final String requestUri = request.getRequestURI();
return this.proxyGrantingTicketStorage != null && !CommonUtils.isEmpty(this.proxyReceptorUrl) && requestUri.endsWith(this.proxyReceptorUrl);
}
}
@@ -16,7 +16,11 @@
package org.springframework.security.cas.web;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import javax.servlet.FilterChain;
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
@@ -30,6 +34,7 @@ import org.springframework.security.core.AuthenticationException;
* Tests {@link CasAuthenticationFilter}.
*
* @author Ben Alex
* @author Rob Winch
*/
public class CasAuthenticationFilterTests {
//~ Methods ========================================================================================================
@@ -67,4 +72,58 @@ public class CasAuthenticationFilterTests {
filter.attemptAuthentication(new MockHttpServletRequest(), new MockHttpServletResponse());
}
@Test
public void testRequiresAuthenticationFilterProcessUrl() {
CasAuthenticationFilter filter = new CasAuthenticationFilter();
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
request.setRequestURI(filter.getFilterProcessesUrl());
assertTrue(filter.requiresAuthentication(request, response));
}
@Test
public void testRequiresAuthenticationProxyRequest() {
CasAuthenticationFilter filter = new CasAuthenticationFilter();
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
request.setRequestURI("/pgtCallback");
assertFalse(filter.requiresAuthentication(request, response));
filter.setProxyReceptorUrl(request.getRequestURI());
assertFalse(filter.requiresAuthentication(request, response));
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
assertTrue(filter.requiresAuthentication(request, response));
request.setRequestURI("/other");
assertFalse(filter.requiresAuthentication(request, response));
}
@Test
public void testAuthenticateProxyUrl() throws Exception {
CasAuthenticationFilter filter = new CasAuthenticationFilter();
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
request.setRequestURI("/pgtCallback");
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
filter.setProxyReceptorUrl(request.getRequestURI());
assertNull(filter.attemptAuthentication(request, response));
}
// SEC-1592
@Test
public void testChainNotInvokedForProxy() throws Exception {
CasAuthenticationFilter filter = new CasAuthenticationFilter();
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain chain = mock(FilterChain.class);
request.setRequestURI("/pgtCallback");
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
filter.setProxyReceptorUrl(request.getRequestURI());
filter.doFilter(request,response,chain);
verifyZeroInteractions(chain);
}
}
+14 -13
View File
@@ -1,21 +1,22 @@
Implementation-Title: org.springframework.security.cas
Implementation-Version: ${version}
Bundle-SymbolicName: org.springframework.security.cas
Bundle-Name: Spring Security CAS
Bundle-Vendor: SpringSource
Bundle-Version: ${version}
Bundle-ManifestVersion: 2
Ignored-Existing-Headers:
Ignored-Existing-Headers:
Import-Package,
Export-Package
Import-Template:
org.apache.commons.logging.*;version="[1.0.4, 2.0.0)",
org.jasig.cas.client.*;version="[3.1.1,3.2)",
org.springframework.security.core.*;version="[${version}, 3.1.0)",
org.springframework.security.authentication.*;version="[${version}, 3.1.0)",
org.springframework.security.web.*;version="[${version}, 3.1.0)",
org.springframework.beans.factory;version="[${spring.version}, 3.1.0)",
org.springframework.context.*;version="[${spring.version}, 3.1.0)",
org.springframework.dao;version="[${spring.version}, 3.1.0)",
org.springframework.util;version="[${spring.version}, 3.1.0)",
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
Import-Template:
org.apache.commons.logging.*;version="${cloggingRange}",
org.jasig.cas.client.*;version="${casRange}",
org.springframework.security.core.*;version="${secRange}",
org.springframework.security.authentication.*;version="${secRange}",
org.springframework.security.web.*;version="${secRange}",
org.springframework.beans.factory;version="${springRange}",
org.springframework.context.*;version="${springRange}",
org.springframework.dao;version="${springRange}",
org.springframework.util;version="${springRange}",
net.sf.ehcache.*;version="${ehcacheRange}";resolution:=optional,
javax.servlet.*;version="0"
+20 -9
View File
@@ -5,24 +5,35 @@ compileTestJava.dependsOn(':spring-security-core:compileTestJava')
dependencies {
compile project(':spring-security-core'),
project(':spring-security-web'),
"javax.servlet:servlet-api:2.5",
'aopalliance:aopalliance:1.0',
"org.aspectj:aspectjweaver:$aspectjVersion",
"org.springframework:spring-aop:$springVersion",
"org.springframework:spring-core:$springVersion",
"org.springframework:spring-context:$springVersion",
"org.springframework:spring-web:$springVersion",
"org.springframework:spring-web:$springVersion",
"org.springframework:spring-beans:$springVersion",
"org.springframework:spring-tx:$springVersion"
provided "javax.servlet:servlet-api:2.5"
testCompile project(':spring-security-ldap'),
project(':spring-security-openid'),
files(this.project(':spring-security-core').sourceSets.test.classesDir),
project(':spring-security-core').sourceSets.test.output,
'javax.annotation:jsr250-api:1.0',
'aopalliance:aopalliance:1.0',
"org.springframework.ldap:spring-ldap-core:$springLdapVersion",
"org.springframework:spring-jdbc:$springVersion"
"org.springframework:spring-expression:$springVersion",
"org.springframework:spring-jdbc:$springVersion",
"org.springframework:spring-tx:$springVersion",
'org.spockframework:spock-core:0.6-groovy-1.8',
"org.slf4j:jcl-over-slf4j:$slf4jVersion"
testCompile('org.openid4java:openid4java-nodeps:0.9.6') {
exclude group: 'com.google.code.guice', module: 'guice'
}
testRuntime "hsqldb:hsqldb:$hsqlVersion",
"cglib:cglib-nodep:2.2"
}
task show << {
println dependencies
}
integrationTest {
systemProperties['apacheDSWorkDir'] = "${buildDir}/apacheDSWork"
}
+2 -2
View File
@@ -3,9 +3,9 @@
pushd src/main/resources/org/springframework/security/config/
echo "Converting rnc file to xsd ..."
java -jar ~/bin/trang.jar spring-security-3.0.rnc spring-security-3.0.xsd
java -jar ~/bin/trang.jar spring-security-3.0.4.rnc spring-security-3.0.4.xsd
echo "Applying XSL transformation to xsd ..."
xsltproc --output spring-security-3.0.xsd spring-security.xsl spring-security-3.0.xsd
xsltproc --output spring-security-3.0.4.xsd spring-security.xsl spring-security-3.0.4.xsd
popd
+2 -6
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-parent</artifactId>
<version>3.0.2.RELEASE</version>
<version>@pomVersion@</version>
</parent>
<packaging>jar</packaging>
<artifactId>spring-security-config</artifactId>
@@ -41,10 +41,6 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
@@ -76,7 +72,7 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.10</version>
<version>1.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -1,14 +1,31 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.springframework.security.config.ldap;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Test;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.ldap.server.ApacheDSContainer;
import org.springframework.test.util.ReflectionTestUtils;
/**
* @author Luke Taylor
* @author Rob Winch
*/
public class LdapServerBeanDefinitionParserTests {
InMemoryXmlApplicationContext appCtx;
@@ -23,7 +40,7 @@ public class LdapServerBeanDefinitionParserTests {
@Test
public void embeddedServerCreationContainsExpectedContextSourceAndData() {
appCtx = new InMemoryXmlApplicationContext("<ldap-server />");
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif'/>");
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) appCtx.getBean(BeanIds.CONTEXT_SOURCE);
@@ -35,8 +52,8 @@ public class LdapServerBeanDefinitionParserTests {
@Test
public void useOfUrlAttributeCreatesCorrectContextSource() {
// Create second "server" with a url pointing at embedded one
appCtx = new InMemoryXmlApplicationContext("<ldap-server port='33388'/>" +
"<ldap-server id='blah' url='ldap://127.0.0.1:33388/dc=springframework,dc=org' />");
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='33388'/>" +
"<ldap-server ldif='classpath:test-server.ldif' id='blah' url='ldap://127.0.0.1:33388/dc=springframework,dc=org' />");
// Check the default context source is still there.
appCtx.getBean(BeanIds.CONTEXT_SOURCE);
@@ -58,6 +75,12 @@ public class LdapServerBeanDefinitionParserTests {
template.lookup("uid=pg,ou=gorillas");
}
@Test
public void defaultLdifFileIsSuccessful() {
appCtx = new InMemoryXmlApplicationContext(
"<ldap-server/>");
ApacheDSContainer dsContainer = appCtx.getBean(ApacheDSContainer.class);
assertEquals("classpath*:*.ldif", ReflectionTestUtils.getField(dsContainer, "ldifResources"));
}
}
@@ -1,17 +1,24 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.springframework.security.config.ldap;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.*;
import static org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser.*;
import java.util.Set;
import org.junit.After;
import org.junit.Test;
import org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser;
import org.junit.*;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
@@ -24,8 +31,11 @@ import org.springframework.security.ldap.userdetails.Person;
import org.springframework.security.ldap.userdetails.PersonContextMapper;
import org.w3c.dom.Element;
import java.util.*;
/**
* @author Luke Taylor
* @author Rob Winch
*/
public class LdapUserServiceBeanDefinitionParserTests {
private InMemoryXmlApplicationContext appCtx;
@@ -50,12 +60,12 @@ public class LdapUserServiceBeanDefinitionParserTests {
@Test
public void minimalConfigurationIsParsedOk() throws Exception {
setContext("<ldap-user-service user-search-filter='(uid={0})' /><ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org' />");
setContext("<ldap-user-service user-search-filter='(uid={0})' /><ldap-server ldif='classpath:test-server.ldif' url='ldap://127.0.0.1:343/dc=springframework,dc=org' />");
}
@Test
public void userServiceReturnsExpectedData() throws Exception {
setContext("<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-search-filter='member={0}' /><ldap-server />");
setContext("<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-search-filter='member={0}' /><ldap-server ldif='classpath:test-server.ldif'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
@@ -70,7 +80,7 @@ public class LdapUserServiceBeanDefinitionParserTests {
setContext("<ldap-user-service id='ldapUDS' " +
" user-search-base='ou=otherpeople' " +
" user-search-filter='(cn={0})' " +
" group-search-filter='member={0}' /><ldap-server />");
" group-search-filter='member={0}' /><ldap-server ldif='classpath:test-server.ldif'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetails joe = uds.loadUserByUsername("Joe Smeth");
@@ -86,7 +96,7 @@ public class LdapUserServiceBeanDefinitionParserTests {
" group-search-filter='member={0}' role-prefix='PREFIX_'/>" +
"<ldap-user-service id='ldapUDSNoPrefix' " +
" user-search-filter='(uid={0})' " +
" group-search-filter='member={0}' role-prefix='none'/><ldap-server />");
" group-search-filter='member={0}' role-prefix='none'/><ldap-server ldif='classpath:test-server.ldif'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
@@ -101,21 +111,21 @@ public class LdapUserServiceBeanDefinitionParserTests {
@Test
public void differentGroupRoleAttributeWorksAsExpected() throws Exception {
setContext("<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-role-attribute='ou' group-search-filter='member={0}' /><ldap-server />");
setContext("<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-role-attribute='ou' group-search-filter='member={0}' /><ldap-server ldif='classpath:test-server.ldif'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
Set<String> authorities = AuthorityUtils.authorityListToSet(ben.getAuthorities());
assertEquals(3, authorities.size());
assertTrue(authorities.contains(new GrantedAuthorityImpl("ROLE_DEVELOPER")));
assertTrue(authorities.contains("ROLE_DEVELOPER"));
}
@Test
public void isSupportedByAuthenticationProviderElement() {
setContext(
"<ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org'/>" +
"<ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org' ldif='classpath:test-server.ldif'/>" +
"<authentication-manager>" +
" <authentication-provider>" +
" <ldap-user-service user-search-filter='(uid={0})' />" +
@@ -126,7 +136,7 @@ public class LdapUserServiceBeanDefinitionParserTests {
@Test
public void personContextMapperIsSupported() {
setContext(
"<ldap-server />" +
"<ldap-server ldif='classpath:test-server.ldif'/>" +
"<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' user-details-class='person'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
@@ -136,7 +146,7 @@ public class LdapUserServiceBeanDefinitionParserTests {
@Test
public void inetOrgContextMapperIsSupported() {
setContext(
"<ldap-server id='someServer'/>" +
"<ldap-server id='someServer' ldif='classpath:test-server.ldif'/>" +
"<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' user-details-class='inetOrgPerson'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
@@ -146,7 +156,7 @@ public class LdapUserServiceBeanDefinitionParserTests {
@Test
public void externalContextMapperIsSupported() {
setContext(
"<ldap-server id='someServer'/>" +
"<ldap-server id='someServer' ldif='classpath:test-server.ldif'/>" +
"<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' user-context-mapper-ref='mapper'/>" +
"<b:bean id='mapper' class='"+ InetOrgPersonContextMapper.class.getName() +"'/>");
@@ -50,4 +50,5 @@ public abstract class Elements {
@Deprecated
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
public static final String HTTP_FIREWALL = "http-firewall";
}
@@ -3,6 +3,8 @@ package org.springframework.security.config;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
@@ -15,12 +17,14 @@ import org.springframework.security.config.authentication.JdbcUserServiceBeanDef
import org.springframework.security.config.authentication.UserServiceBeanDefinitionParser;
import org.springframework.security.config.http.FilterChainMapBeanDefinitionDecorator;
import org.springframework.security.config.http.FilterInvocationSecurityMetadataSourceParser;
import org.springframework.security.config.http.HttpFirewallBeanDefinitionParser;
import org.springframework.security.config.http.HttpSecurityBeanDefinitionParser;
import org.springframework.security.config.ldap.LdapProviderBeanDefinitionParser;
import org.springframework.security.config.ldap.LdapServerBeanDefinitionParser;
import org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser;
import org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParser;
import org.springframework.security.config.method.InterceptMethodsBeanDefinitionDecorator;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.util.ClassUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@@ -33,18 +37,44 @@ import org.w3c.dom.Node;
* @since 2.0
*/
public final class SecurityNamespaceHandler implements NamespaceHandler {
private final Log logger = LogFactory.getLog(getClass());
private final Map<String, BeanDefinitionParser> parsers = new HashMap<String, BeanDefinitionParser>();
private final BeanDefinitionDecorator interceptMethodsBDD = new InterceptMethodsBeanDefinitionDecorator();
private BeanDefinitionDecorator filterChainMapBDD;
public SecurityNamespaceHandler() {
String coreVersion = SpringSecurityCoreVersion.getVersion();
Package pkg = SpringSecurityCoreVersion.class.getPackage();
if (pkg == null || coreVersion == null) {
logger.info("Couldn't determine package version information.");
return;
}
String version = pkg.getImplementationVersion();
logger.info("Spring Security 'config' module version is " + version);
if (version.compareTo(coreVersion) != 0) {
logger.error("You are running with different versions of the Spring Security 'core' and 'config' modules");
}
}
public BeanDefinition parse(Element element, ParserContext pc) {
if (!namespaceMatchesVersion(element)) {
pc.getReaderContext().fatal("You cannot use a spring-security-2.0.xsd schema with Spring Security 3.0." +
" Please update your schema declarations to the 3.0 schema.", element);
pc.getReaderContext().fatal("You must use a 3.0 schema with Spring Security 3.0." +
"(2.0 or 3.1 versions are not valid)" +
" Please update your schema declarations to the 3.0.3 schema (spring-security-3.0.3.xsd).", element);
}
String name = pc.getDelegate().getLocalName(element);
BeanDefinitionParser parser = parsers.get(name);
if (parser == null) {
// SEC-1455. Load parsers when required, not just on init().
loadParsers();
}
if (parser == null) {
if (Elements.HTTP.equals(name) || Elements.FILTER_SECURITY_METADATA_SOURCE.equals(name)) {
reportMissingWebClasses(name, pc, element);
@@ -67,6 +97,9 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
}
if (Elements.FILTER_CHAIN_MAP.equals(name)) {
if (filterChainMapBDD == null) {
loadParsers();
}
if (filterChainMapBDD == null) {
reportMissingWebClasses(name, pc, node);
}
@@ -91,8 +124,12 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
"You need these to use <" + Elements.FILTER_CHAIN_MAP + ">", node);
}
@SuppressWarnings("deprecation")
public void init() {
loadParsers();
}
@SuppressWarnings("deprecation")
private void loadParsers() {
// Parsers
parsers.put(Elements.LDAP_PROVIDER, new LdapProviderBeanDefinitionParser());
parsers.put(Elements.LDAP_SERVER, new LdapServerBeanDefinitionParser());
@@ -102,15 +139,14 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
parsers.put(Elements.AUTHENTICATION_PROVIDER, new AuthenticationProviderBeanDefinitionParser());
parsers.put(Elements.GLOBAL_METHOD_SECURITY, new GlobalMethodSecurityBeanDefinitionParser());
parsers.put(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser());
// registerBeanDefinitionDecorator(Elements.INTERCEPT_METHODS, new InterceptMethodsBeanDefinitionDecorator());
// Only load the web-namespace parsers if the web classes are available
if (ClassUtils.isPresent("org.springframework.security.web.FilterChainProxy", getClass().getClassLoader())) {
parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
parsers.put(Elements.HTTP_FIREWALL, new HttpFirewallBeanDefinitionParser());
parsers.put(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
//registerBeanDefinitionDecorator(Elements.FILTER_CHAIN_MAP, new FilterChainMapBeanDefinitionDecorator());
}
}
@@ -129,8 +165,8 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
private boolean matchesVersionInternal(Element element) {
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
return schemaLocation.matches("(?m).*spring-security-3.0.xsd.*")
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
return schemaLocation.matches("(?m).*spring-security-3\\.0.*xsd.*")
|| schemaLocation.matches("(?m).*spring-security\\.xsd.*")
|| !schemaLocation.matches("(?m).*spring-security.*");
}
@@ -1,18 +1,16 @@
package org.springframework.security.config.authentication;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.Elements;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
@@ -22,9 +20,6 @@ public abstract class AbstractUserDetailsServiceBeanDefinitionParser implements
static final String CACHE_REF = "cache-ref";
public static final String CACHING_SUFFIX = ".caching";
/** UserDetailsService bean Id. For use in a stateful context (i.e. in AuthenticationProviderBDP) */
private String id;
protected abstract String getBeanClassName(Element element);
protected abstract void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder);
@@ -51,34 +46,33 @@ public abstract class AbstractUserDetailsServiceBeanDefinitionParser implements
parserContext.registerBeanComponent(new BeanComponentDefinition(cachingUserService, beanId + CACHING_SUFFIX));
}
id = beanId;
return null;
}
private String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
private String resolveId(Element element, AbstractBeanDefinition definition, ParserContext pc)
throws BeanDefinitionStoreException {
String id = element.getAttribute("id");
if (pc.isNested()) {
// We're inside an <authentication-provider> element
if (!StringUtils.hasText(id)) {
id = pc.getReaderContext().generateBeanName(definition);
}
BeanDefinition container = pc.getContainingBeanDefinition();
container.getPropertyValues().add("userDetailsService", new RuntimeBeanReference(id));
}
if (StringUtils.hasText(id)) {
return id;
}
if(Elements.AUTHENTICATION_PROVIDER.equals(element.getParentNode().getNodeName())) {
return parserContext.getReaderContext().generateBeanName(definition);
}
// If top level, use the default name or throw an exception if already used
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.USER_DETAILS_SERVICE)) {
if (pc.getRegistry().containsBeanDefinition(BeanIds.USER_DETAILS_SERVICE)) {
throw new BeanDefinitionStoreException("No id supplied and another " +
"bean is already registered as " + BeanIds.USER_DETAILS_SERVICE);
}
return BeanIds.USER_DETAILS_SERVICE;
}
String getId() {
return id;
}
}
@@ -35,6 +35,7 @@ import org.w3c.dom.NodeList;
public class AuthenticationManagerBeanDefinitionParser implements BeanDefinitionParser {
private static final String ATT_ALIAS = "alias";
private static final String ATT_REF = "ref";
private static final String ATT_ERASE_CREDENTIALS = "erase-credentials";
public BeanDefinition parse(Element element, ParserContext pc) {
Assert.state(!pc.getRegistry().containsBeanDefinition(BeanIds.AUTHENTICATION_MANAGER),
@@ -72,6 +73,11 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
}
providerManagerBldr.addPropertyValue("providers", providers);
if ("true".equals(element.getAttribute(ATT_ERASE_CREDENTIALS))) {
providerManagerBldr.addPropertyValue("eraseCredentialsAfterAuthentication", true);
}
// Add the default event publisher
BeanDefinition publisher = new RootBeanDefinition(DefaultAuthenticationEventPublisher.class);
String id = pc.getReaderContext().generateBeanName(publisher);
@@ -7,7 +7,6 @@ import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Elements;
import org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
@@ -21,14 +20,14 @@ import org.w3c.dom.Element;
public class AuthenticationProviderBeanDefinitionParser implements BeanDefinitionParser {
private static String ATT_USER_DETAILS_REF = "user-service-ref";
public BeanDefinition parse(Element element, ParserContext parserContext) {
public BeanDefinition parse(Element element, ParserContext pc) {
RootBeanDefinition authProvider = new RootBeanDefinition(DaoAuthenticationProvider.class);
authProvider.setSource(parserContext.extractSource(element));
authProvider.setSource(pc.extractSource(element));
Element passwordEncoderElt = DomUtils.getChildElementByTagName(element, Elements.PASSWORD_ENCODER);
if (passwordEncoderElt != null) {
PasswordEncoderParser pep = new PasswordEncoderParser(passwordEncoderElt, parserContext);
PasswordEncoderParser pep = new PasswordEncoderParser(passwordEncoderElt, pc);
authProvider.getPropertyValues().addPropertyValue("passwordEncoder", pep.getPasswordEncoder());
if (pep.getSaltSource() != null) {
@@ -37,98 +36,39 @@ public class AuthenticationProviderBeanDefinitionParser implements BeanDefinitio
}
Element userServiceElt = DomUtils.getChildElementByTagName(element, Elements.USER_SERVICE);
Element jdbcUserServiceElt = DomUtils.getChildElementByTagName(element, Elements.JDBC_USER_SERVICE);
Element ldapUserServiceElt = DomUtils.getChildElementByTagName(element, Elements.LDAP_USER_SERVICE);
if (userServiceElt == null) {
userServiceElt = DomUtils.getChildElementByTagName(element, Elements.JDBC_USER_SERVICE);
}
if (userServiceElt == null) {
userServiceElt = DomUtils.getChildElementByTagName(element, Elements.LDAP_USER_SERVICE);
}
String ref = element.getAttribute(ATT_USER_DETAILS_REF);
if (StringUtils.hasText(ref)) {
if (userServiceElt != null || jdbcUserServiceElt != null || ldapUserServiceElt != null) {
parserContext.getReaderContext().error("The " + ATT_USER_DETAILS_REF + " attribute cannot be used in combination with child" +
if (userServiceElt != null) {
pc.getReaderContext().error("The " + ATT_USER_DETAILS_REF + " attribute cannot be used in combination with child" +
"elements '" + Elements.USER_SERVICE + "', '" + Elements.JDBC_USER_SERVICE + "' or '" +
Elements.LDAP_USER_SERVICE + "'", element);
}
authProvider.getPropertyValues().add("userDetailsService", new RuntimeBeanReference(ref));
} else {
// Use the child elements to create the UserDetailsService
AbstractUserDetailsServiceBeanDefinitionParser parser = null;
Element elt = null;
if (userServiceElt != null) {
elt = userServiceElt;
parser = new UserServiceBeanDefinitionParser();
} else if (jdbcUserServiceElt != null) {
elt = jdbcUserServiceElt;
parser = new JdbcUserServiceBeanDefinitionParser();
} else if (ldapUserServiceElt != null) {
elt = ldapUserServiceElt;
parser = new LdapUserServiceBeanDefinitionParser();
pc.getDelegate().parseCustomElement(userServiceElt, authProvider);
} else {
parserContext.getReaderContext().error("A user-service is required", element);
pc.getReaderContext().error("A user-service is required", element);
}
parser.parse(elt, parserContext);
ref = parser.getId();
// Pinch the cache-ref from the UserDetailService element, if set.
String cacheRef = elt.getAttribute(AbstractUserDetailsServiceBeanDefinitionParser.CACHE_REF);
String cacheRef = userServiceElt.getAttribute(AbstractUserDetailsServiceBeanDefinitionParser.CACHE_REF);
if (StringUtils.hasText(cacheRef)) {
authProvider.getPropertyValues().addPropertyValue("userCache", new RuntimeBeanReference(cacheRef));
}
}
authProvider.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(ref));
// We need to register the provider to access it in the post processor to check if it has a cache
// final String id = parserContext.getReaderContext().generateBeanName(authProvider);
// parserContext.getRegistry().registerBeanDefinition(id, authProvider);
// parserContext.registerComponent(new BeanComponentDefinition(authProvider, id));
// BeanDefinitionBuilder cacheResolverBldr = BeanDefinitionBuilder.rootBeanDefinition(AuthenticationProviderCacheResolver.class);
// cacheResolverBldr.addConstructorArgValue(id);
// cacheResolverBldr.addConstructorArgValue(ref);
// cacheResolverBldr.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// BeanDefinition cacheResolver = cacheResolverBldr.getBeanDefinition();
//
// String name = parserContext.getReaderContext().generateBeanName(cacheResolver);
// parserContext.getRegistry().registerBeanDefinition(name , cacheResolver);
// parserContext.registerComponent(new BeanComponentDefinition(cacheResolver, name));
// ConfigUtils.addAuthenticationProvider(parserContext, id, element);
return authProvider;
}
/**
* Checks whether the registered user service bean has an associated cache and, if so, sets it on the
* authentication provider.
*/
// static class AuthenticationProviderCacheResolver implements BeanFactoryPostProcessor, Ordered {
// private String providerId;
// private String userServiceId;
//
// public AuthenticationProviderCacheResolver(String providerId, String userServiceId) {
// this.providerId = providerId;
// this.userServiceId = userServiceId;
// }
//
// public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// RootBeanDefinition provider = (RootBeanDefinition) beanFactory.getBeanDefinition(providerId);
//
// String cachingId = userServiceId + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX;
//
// if (beanFactory.containsBeanDefinition(cachingId)) {
// RootBeanDefinition cachingUserService = (RootBeanDefinition) beanFactory.getBeanDefinition(cachingId);
//
// PropertyValue userCacheProperty = cachingUserService.getPropertyValues().getPropertyValue("userCache");
//
// provider.getPropertyValues().addPropertyValue(userCacheProperty);
// }
// }
//
// public int getOrder() {
// return HIGHEST_PRECEDENCE;
// }
// }
}
@@ -24,6 +24,7 @@ import org.w3c.dom.Element;
* @author Luke Taylor
* @author Ben Alex
*/
@SuppressWarnings("deprecation")
public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceBeanDefinitionParser {
static final String ATT_PASSWORD = "password";
@@ -90,7 +91,7 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
user.addConstructorArgValue(!locked);
user.addConstructorArgValue(authorities.getBeanDefinition());
users.put(userName, user.getBeanDefinition());
users.put(userName.toLowerCase(), user.getBeanDefinition());
}
userMap.getPropertyValues().addPropertyValue("users", users);
@@ -2,11 +2,6 @@ package org.springframework.security.config.http;
import static org.springframework.security.config.http.SecurityFilters.*;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanMetadataElement;
@@ -33,13 +28,16 @@ import org.springframework.security.web.authentication.preauth.PreAuthenticatedA
import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor;
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
import java.security.SecureRandom;
import java.util.*;
/**
* Handles creation of authentication mechanism filters and related beans for &lt;http&gt; parsing.
*
@@ -68,6 +66,8 @@ final class AuthenticationConfigBuilder {
private static final String ATT_REF = "ref";
private static final String ATT_KEY = "key";
private Element httpElt;
private ParserContext pc;
@@ -81,10 +81,8 @@ final class AuthenticationConfigBuilder {
private String rememberMeServicesId;
private BeanReference rememberMeProviderRef;
private BeanDefinition basicFilter;
private BeanDefinition basicEntryPoint;
private RootBeanDefinition formFilter;
private RuntimeBeanReference basicEntryPoint;
private BeanDefinition formEntryPoint;
private RootBeanDefinition openIDFilter;
private BeanDefinition openIDEntryPoint;
private BeanReference openIDProviderRef;
private String openIDProviderId;
@@ -99,8 +97,6 @@ final class AuthenticationConfigBuilder {
private BeanDefinition etf;
private BeanReference requestCache;
final SecureRandom random;
public AuthenticationConfigBuilder(Element element, ParserContext pc, boolean allowSessionCreation,
String portMapperName) {
this.httpElt = element;
@@ -108,18 +104,9 @@ final class AuthenticationConfigBuilder {
this.portMapperName = portMapperName;
autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
this.allowSessionCreation = allowSessionCreation;
try {
random = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
// Shouldn't happen...
throw new RuntimeException("Failed find SHA1PRNG algorithm!");
}
}
void createRememberMeFilter(BeanReference authenticationManager) {
final String ATT_KEY = "key";
final String DEF_KEY = "SpringSecured";
// Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation.
Element rememberMeElt = DomUtils.getChildElementByTagName(httpElt, Elements.REMEMBER_ME);
@@ -127,10 +114,10 @@ final class AuthenticationConfigBuilder {
String key = rememberMeElt.getAttribute(ATT_KEY);
if (!StringUtils.hasText(key)) {
key = DEF_KEY;
key = createKey();
}
rememberMeFilter = (RootBeanDefinition) new RememberMeBeanDefinitionParser(key).parse(rememberMeElt, pc);
rememberMeFilter = new RememberMeBeanDefinitionParser(key).parse(rememberMeElt, pc);
rememberMeFilter.getPropertyValues().addPropertyValue("authenticationManager", authenticationManager);
rememberMeServicesId = ((RuntimeBeanReference) rememberMeFilter.getPropertyValues().getPropertyValue("rememberMeServices").getValue()).getBeanName();
createRememberMeProvider(key);
@@ -152,10 +139,11 @@ final class AuthenticationConfigBuilder {
void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
Element formLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.FORM_LOGIN);
RootBeanDefinition formFilter = null;
if (formLoginElt != null || autoConfig) {
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy);
AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation);
parser.parse(formLoginElt, pc);
formFilter = parser.getFilterBean();
@@ -163,7 +151,7 @@ final class AuthenticationConfigBuilder {
}
if (formFilter != null) {
formFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
formFilter.getPropertyValues().addPropertyValue("allowSessionCreation", allowSessionCreation);
formFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
@@ -176,10 +164,11 @@ final class AuthenticationConfigBuilder {
void createOpenIDLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
Element openIDLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.OPENID_LOGIN);
RootBeanDefinition openIDFilter = null;
if (openIDLoginElt != null) {
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy);
OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation);
parser.parse(openIDLoginElt, pc);
openIDFilter = parser.getFilterBean();
@@ -214,7 +203,7 @@ final class AuthenticationConfigBuilder {
}
if (openIDFilter != null) {
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", new Boolean(allowSessionCreation));
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation", allowSessionCreation);
openIDFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
// Required by login page filter
openIDFilterId = pc.getReaderContext().generateBeanName(openIDFilter);
@@ -256,25 +245,29 @@ final class AuthenticationConfigBuilder {
}
RootBeanDefinition filter = null;
RootBeanDefinition entryPoint = null;
if (basicAuthElt != null || autoConfig) {
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicAuthenticationFilter.class);
entryPoint = new RootBeanDefinition(BasicAuthenticationEntryPoint.class);
entryPoint.setSource(pc.extractSource(httpElt));
entryPoint.getPropertyValues().addPropertyValue("realmName", realm);
String entryPointId;
String entryPointId = pc.getReaderContext().generateBeanName(entryPoint);
pc.registerBeanComponent(new BeanComponentDefinition(entryPoint, entryPointId));
if (basicAuthElt != null && StringUtils.hasText(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF))) {
basicEntryPoint = new RuntimeBeanReference(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF));
} else {
RootBeanDefinition entryPoint = new RootBeanDefinition(BasicAuthenticationEntryPoint.class);
entryPoint.setSource(pc.extractSource(httpElt));
entryPoint.getPropertyValues().addPropertyValue("realmName", realm);
entryPointId = pc.getReaderContext().generateBeanName(entryPoint);
pc.registerBeanComponent(new BeanComponentDefinition(entryPoint, entryPointId));
basicEntryPoint = new RuntimeBeanReference(entryPointId);
}
filterBuilder.addPropertyValue("authenticationManager", authManager);
filterBuilder.addPropertyValue("authenticationEntryPoint", new RuntimeBeanReference(entryPointId));
filterBuilder.addPropertyValue("authenticationEntryPoint", basicEntryPoint);
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
}
basicFilter = filter;
basicEntryPoint = entryPoint;
}
void createX509Filter(BeanReference authManager) {
@@ -325,7 +318,7 @@ final class AuthenticationConfigBuilder {
void createLoginPageFilterIfNeeded() {
boolean needLoginPage = formFilter != null || openIDFilter != null;
boolean needLoginPage = formFilterId != null || openIDFilterId != null;
String formLoginPage = getLoginFormUrl(formEntryPoint);
String openIDLoginPage = getLoginFormUrl(openIDEntryPoint);
@@ -336,11 +329,11 @@ final class AuthenticationConfigBuilder {
BeanDefinitionBuilder loginPageFilter =
BeanDefinitionBuilder.rootBeanDefinition(DefaultLoginPageGeneratingFilter.class);
if (formFilter != null) {
if (formFilterId != null) {
loginPageFilter.addConstructorArgReference(formFilterId);
}
if (openIDFilter != null) {
if (openIDFilterId != null) {
loginPageFilter.addConstructorArgReference(openIDFilterId);
}
@@ -370,7 +363,7 @@ final class AuthenticationConfigBuilder {
if (anonymousElt != null) {
grantedAuthority = anonymousElt.getAttribute("granted-authority");
username = anonymousElt.getAttribute("username");
key = anonymousElt.getAttribute("key");
key = anonymousElt.getAttribute(ATT_KEY);
source = pc.extractSource(anonymousElt);
}
@@ -384,7 +377,7 @@ final class AuthenticationConfigBuilder {
if (!StringUtils.hasText(key)) {
// Generate a random key for the Anonymous provider
key = Long.toString(random.nextLong());
key = createKey();
}
anonymousFilter = new RootBeanDefinition(AnonymousAuthenticationFilter.class);
@@ -404,6 +397,11 @@ final class AuthenticationConfigBuilder {
}
private String createKey() {
SecureRandom random = new SecureRandom();
return Long.toString(random.nextLong());
}
void createExceptionTranslationFilter() {
BeanDefinitionBuilder etfBuilder = BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
etfBuilder.addPropertyValue("accessDeniedHandler", createAccessDeniedHandler(httpElt, pc));
@@ -499,12 +497,12 @@ final class AuthenticationConfigBuilder {
"but not both.", pc.extractSource(openIDLoginElt));
}
if (formFilter != null && openIDLoginPage == null) {
if (formFilterId != null && openIDLoginPage == null) {
return formEntryPoint;
}
// Otherwise use OpenID if enabled
if (openIDFilter != null) {
if (openIDFilterId != null) {
return openIDEntryPoint;
}
@@ -540,7 +538,8 @@ final class AuthenticationConfigBuilder {
}
void createUserServiceInjector() {
BeanDefinitionBuilder userServiceInjector = BeanDefinitionBuilder.rootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
BeanDefinitionBuilder userServiceInjector =
BeanDefinitionBuilder.rootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
userServiceInjector.addConstructorArgValue(x509ProviderId);
userServiceInjector.addConstructorArgValue(rememberMeServicesId);
userServiceInjector.addConstructorArgValue(openIDProviderId);
@@ -567,12 +566,12 @@ final class AuthenticationConfigBuilder {
filters.add(new OrderDecorator(x509Filter, X509_FILTER));
}
if (formFilter != null) {
filters.add(new OrderDecorator(formFilter, FORM_LOGIN_FILTER));
if (formFilterId != null) {
filters.add(new OrderDecorator(new RuntimeBeanReference(formFilterId), FORM_LOGIN_FILTER));
}
if (openIDFilter != null) {
filters.add(new OrderDecorator(openIDFilter, OPENID_FILTER));
if (openIDFilterId != null) {
filters.add(new OrderDecorator(new RuntimeBeanReference(openIDFilterId), OPENID_FILTER));
}
if (loginPageGenerationFilter != null) {
@@ -1,5 +1,8 @@
package org.springframework.security.config.http;
import static org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.*;
import static org.springframework.security.config.Elements.*;
import java.util.List;
import org.apache.commons.logging.Log;
@@ -112,6 +115,13 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
if (!StringUtils.hasText(access)) {
continue;
}
String filters = urlElt.getAttribute(ATT_FILTERS);
if(OPT_FILTERS_NONE.equals(filters)) {
parserContext.getReaderContext().error(
"Ambiguous configuration. Cannot contain " + INTERCEPT_URL+"@" + ATT_FILTERS +
"=\"" + OPT_FILTERS_NONE + "\" and " + INTERCEPT_URL + "@" + ATT_ACCESS,
parserContext.extractSource(urlElt));
}
String path = urlElt.getAttribute(ATT_PATTERN);
@@ -31,7 +31,8 @@ public class FormLoginBeanDefinitionParser {
private static final String DEF_FORM_LOGIN_TARGET_URL = "/";
private static final String ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = "authentication-failure-url";
private static final String DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL + "?" + DefaultLoginPageGeneratingFilter.ERROR_PARAMETER_NAME;
private static final String DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL =
DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL + "?" + DefaultLoginPageGeneratingFilter.ERROR_PARAMETER_NAME;
private static final String ATT_SUCCESS_HANDLER_REF = "authentication-success-handler-ref";
private static final String ATT_FAILURE_HANDLER_REF = "authentication-failure-handler-ref";
@@ -40,17 +41,19 @@ public class FormLoginBeanDefinitionParser {
private final String filterClassName;
private final BeanReference requestCache;
private final BeanReference sessionStrategy;
private final boolean allowSessionCreation;
private RootBeanDefinition filterBean;
private RootBeanDefinition entryPointBean;
private String loginPage;
FormLoginBeanDefinitionParser(String defaultLoginProcessingUrl, String filterClassName,
BeanReference requestCache, BeanReference sessionStrategy) {
BeanReference requestCache, BeanReference sessionStrategy, boolean allowSessionCreation) {
this.defaultLoginProcessingUrl = defaultLoginProcessingUrl;
this.filterClassName = filterClassName;
this.requestCache = requestCache;
this.sessionStrategy = sessionStrategy;
this.allowSessionCreation = allowSessionCreation;
}
public BeanDefinition parse(Element elt, ParserContext pc) {
@@ -135,6 +138,7 @@ public class FormLoginBeanDefinitionParser {
}
}
failureHandler.addPropertyValue("defaultFailureUrl", authenticationFailureUrl);
failureHandler.addPropertyValue("allowSessionCreation", allowSessionCreation);
filterBuilder.addPropertyValue("authenticationFailureHandler", failureHandler.getBeanDefinition());
}
@@ -2,6 +2,7 @@ package org.springframework.security.config.http;
import static org.springframework.security.config.http.SecurityFilters.*;
import static org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.*;
import static org.springframework.security.config.Elements.*;
import java.util.ArrayList;
import java.util.Collections;
@@ -83,7 +84,7 @@ class HttpConfigurationBuilder {
private final List<Element> interceptUrls;
// Use ManagedMap to allow placeholder resolution
private ManagedMap<BeanDefinition, List<BeanMetadataElement>> filterChainMap;
private ManagedMap<Object, List<BeanMetadataElement>> filterChainMap;
private BeanDefinition cpf;
private BeanDefinition securityContextPersistenceFilter;
@@ -109,7 +110,7 @@ class HttpConfigurationBuilder {
}
void parseInterceptUrlsForEmptyFilterChains() {
filterChainMap = new ManagedMap<BeanDefinition, List<BeanMetadataElement>>();
filterChainMap = new ManagedMap<Object, List<BeanMetadataElement>>();
for (Element urlElt : interceptUrls) {
String path = urlElt.getAttribute(ATT_PATH_PATTERN);
@@ -393,9 +394,21 @@ class HttpConfigurationBuilder {
String requiredChannel = urlElt.getAttribute(ATT_REQUIRES_CHANNEL);
if (StringUtils.hasText(requiredChannel)) {
String filters = urlElt.getAttribute(ATT_FILTERS);
if(OPT_FILTERS_NONE.equals(filters)) {
pc.getReaderContext().error(
"Ambiguous configuration. Cannot contain " + INTERCEPT_URL+"@" + ATT_FILTERS +
"=\"" + OPT_FILTERS_NONE + "\" and " + INTERCEPT_URL + "@" + ATT_REQUIRES_CHANNEL,
pc.extractSource(urlElt));
}
BeanDefinition requestKey = new RootBeanDefinition(RequestKey.class);
requestKey.getConstructorArgumentValues().addGenericArgumentValue(path);
String method = urlElt.getAttribute(ATT_HTTP_METHOD);
if(StringUtils.hasText(method)) {
requestKey.getConstructorArgumentValues().addGenericArgumentValue(method);
}
RootBeanDefinition channelAttributes = new RootBeanDefinition(ChannelAttributeFactory.class);
channelAttributes.getConstructorArgumentValues().addGenericArgumentValue(requiredChannel);
channelAttributes.setFactoryMethodName("createChannelAttributes");
@@ -464,7 +477,7 @@ class HttpConfigurationBuilder {
return allowSessionCreation;
}
public ManagedMap<BeanDefinition, List<BeanMetadataElement>> getFilterChainMap() {
public ManagedMap<Object, List<BeanMetadataElement>> getFilterChainMap() {
return filterChainMap;
}
@@ -0,0 +1,38 @@
package org.springframework.security.config.http;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.config.BeanIds;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import java.util.*;
/**
* Injects the supplied {@code HttpFirewall} bean reference into the {@code FilterChainProxy}.
*
* @author Luke Taylor
*/
public class HttpFirewallBeanDefinitionParser implements BeanDefinitionParser {
public BeanDefinition parse(Element element, ParserContext pc) {
String ref = element.getAttribute("ref");
if (!StringUtils.hasText(ref)) {
pc.getReaderContext().error("ref attribute is required", pc.extractSource(element));
}
BeanDefinitionBuilder injector = BeanDefinitionBuilder.rootBeanDefinition(HttpFirewallInjectionBeanPostProcessor.class);
injector.addConstructorArgValue(ref);
pc.getReaderContext().registerWithGeneratedName(injector.getBeanDefinition());
return null;
}
}
@@ -0,0 +1,40 @@
package org.springframework.security.config.http;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.security.config.BeanIds;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.firewall.HttpFirewall;
/**
* @author Luke Taylor
*/
public class HttpFirewallInjectionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
private ConfigurableListableBeanFactory beanFactory;
private String ref;
public HttpFirewallInjectionBeanPostProcessor(String ref) {
this.ref = ref;
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (BeanIds.FILTER_CHAIN_PROXY.equals(beanName)) {
HttpFirewall fw = (HttpFirewall) beanFactory.getBean(ref);
((FilterChainProxy)bean).setFirewall(fw);
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
}
@@ -12,6 +12,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
@@ -55,6 +56,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
static final String OPT_FILTERS_NONE = "none";
static final String ATT_REQUIRES_CHANNEL = "requires-channel";
static final String ATT_HTTP_METHOD = "method";
private static final String ATT_LOWERCASE_COMPARISONS = "lowercase-comparisons";
@@ -135,10 +137,8 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
filterChain.add(od.bean);
}
ManagedMap<BeanDefinition, List<BeanMetadataElement>> filterChainMap = httpBldr.getFilterChainMap();
BeanDefinition universalMatch = new RootBeanDefinition(String.class);
universalMatch.getConstructorArgumentValues().addGenericArgumentValue(matcher.getUniversalMatchPattern());
filterChainMap.put(universalMatch, filterChain);
ManagedMap<Object, List<BeanMetadataElement>> filterChainMap = httpBldr.getFilterChainMap();
filterChainMap.put(matcher.getUniversalMatchPattern(), filterChain);
registerFilterChainProxy(pc, filterChainMap, matcher, source);
@@ -168,6 +168,10 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
BeanDefinitionBuilder authManager = BeanDefinitionBuilder.rootBeanDefinition(ProviderManager.class);
authManager.addPropertyValue("parent", new RootBeanDefinition(AuthenticationManagerFactoryBean.class));
authManager.addPropertyValue("providers", authenticationProviders);
RootBeanDefinition clearCredentials = new RootBeanDefinition(MethodInvokingFactoryBean.class);
clearCredentials.getPropertyValues().addPropertyValue("targetObject", new RootBeanDefinition(AuthenticationManagerFactoryBean.class));
clearCredentials.getPropertyValues().addPropertyValue("targetMethod", "isEraseCredentialsAfterAuthentication");
authManager.addPropertyValue("eraseCredentialsAfterAuthentication", clearCredentials);
if (concurrencyController != null) {
authManager.addPropertyValue("sessionController", concurrencyController);
@@ -247,7 +251,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
return customFilters;
}
private void registerFilterChainProxy(ParserContext pc, Map<BeanDefinition, List<BeanMetadataElement>> filterChainMap, UrlMatcher matcher, Object source) {
private void registerFilterChainProxy(ParserContext pc, Map<Object, List<BeanMetadataElement>> filterChainMap, UrlMatcher matcher, Object source) {
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
pc.getReaderContext().error("Duplicate <http> element detected", source);
}
@@ -59,7 +59,7 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
if (StringUtils.hasText(successHandlerRef)) {
if (StringUtils.hasText(logoutSuccessUrl)) {
pc.getReaderContext().error("Use " + ATT_LOGOUT_URL + " or " + ATT_LOGOUT_HANDLER + ", but not both",
pc.getReaderContext().error("Use " + ATT_LOGOUT_SUCCESS_URL + " or " + ATT_LOGOUT_HANDLER + ", but not both",
pc.extractSource(element));
}
builder.addConstructorArgReference(successHandlerRef);
@@ -10,8 +10,8 @@ package org.springframework.security.config.http;
enum SecurityFilters {
FIRST (Integer.MIN_VALUE),
CHANNEL_FILTER,
CONCURRENT_SESSION_FILTER,
SECURITY_CONTEXT_FILTER,
CONCURRENT_SESSION_FILTER,
LOGOUT_FILTER,
X509_FILTER,
PRE_AUTH_FILTER,
@@ -36,12 +36,12 @@ class ContextSourceSettingPostProcessor implements BeanFactoryPostProcessor, Ord
"jar file in your application", e);
}
String[] sources = bf.getBeanNamesForType(contextSourceClass);
String[] sources = bf.getBeanNamesForType(contextSourceClass, false, false);
if (sources.length == 0) {
throw new ApplicationContextException("No BaseLdapPathContextSource instances found. Have you " +
"added an <" + Elements.LDAP_SERVER + " /> element to your application context?");
"added an <" + Elements.LDAP_SERVER + " /> element to your application context? If you have " +
"declared an explicit bean, do not use lazy-init");
}
if (!bf.containsBean(BeanIds.CONTEXT_SOURCE) && defaultNameRequired) {
@@ -37,6 +37,7 @@ import org.springframework.security.access.expression.method.ExpressionBasedPreI
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource;
import org.springframework.security.access.method.MapBasedMethodSecurityMetadataSource;
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
@@ -76,6 +77,7 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
private static final String ATT_USE_SECURED = "secured-annotations";
private static final String ATT_USE_PREPOST = "pre-post-annotations";
private static final String ATT_REF = "ref";
private static final String ATT_MODE = "mode";
private static final String ATT_ADVICE_ORDER = "order";
public BeanDefinition parse(Element element, ParserContext pc) {
@@ -90,6 +92,8 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
boolean jsr250Enabled = "enabled".equals(element.getAttribute(ATT_USE_JSR250));
boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED));
boolean prePostAnnotationsEnabled = "enabled".equals(element.getAttribute(ATT_USE_PREPOST));
boolean useAspectJ = "aspectj".equals(element.getAttribute(ATT_MODE));
BeanDefinition preInvocationVoter = null;
ManagedList<BeanMetadataElement> afterInvocationProviders = new ManagedList<BeanMetadataElement>();
@@ -165,6 +169,9 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
DomUtils.getChildElementsByTagName(element, PROTECT_POINTCUT));
if (pointcutMap.size() > 0) {
if (useAspectJ) {
pc.getReaderContext().error("You can't use AspectJ mode with protect-pointcut definitions", source);
}
// Only add it if there are actually any pointcuts defined.
BeanDefinition mapBasedMetadataSource = new RootBeanDefinition(MapBasedMethodSecurityMetadataSource.class);
BeanReference ref = new RuntimeBeanReference(pc.getReaderContext().generateBeanName(mapBasedMetadataSource));
@@ -190,13 +197,22 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
}
String runAsManagerId = element.getAttribute(ATT_RUN_AS_MGR);
BeanReference interceptor = registerMethodSecurityInterceptor(pc, accessManagerId, runAsManagerId,
metadataSource, afterInvocationProviders, source);
metadataSource, afterInvocationProviders, source, useAspectJ);
registerAdvisor(pc, interceptor, metadataSource, source, element.getAttribute(ATT_ADVICE_ORDER));
if (useAspectJ) {
BeanDefinitionBuilder aspect =
BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect");
aspect.setFactoryMethod("aspectOf");
aspect.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
aspect.addPropertyValue("securityInterceptor", interceptor);
String id = pc.getReaderContext().registerWithGeneratedName(aspect.getBeanDefinition());
pc.registerBeanComponent(new BeanComponentDefinition(aspect.getBeanDefinition(), id));
} else {
registerAdvisor(pc, interceptor, metadataSource, source, element.getAttribute(ATT_ADVICE_ORDER));
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(pc, element);
}
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(pc, element);
pc.popAndRegisterContainingComponent();
return null;
@@ -284,12 +300,16 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
}
private BeanReference registerMethodSecurityInterceptor(ParserContext pc, String accessManagerId,
String runAsManagerId, BeanReference metadataSource, List<BeanMetadataElement> afterInvocationProviders, Object source) {
BeanDefinitionBuilder bldr = BeanDefinitionBuilder.rootBeanDefinition(MethodSecurityInterceptor.class);
String runAsManagerId, BeanReference metadataSource,
List<BeanMetadataElement> afterInvocationProviders, Object source, boolean useAspectJ) {
BeanDefinitionBuilder bldr =
BeanDefinitionBuilder.rootBeanDefinition(useAspectJ ?
AspectJMethodSecurityInterceptor.class : MethodSecurityInterceptor.class);
bldr.getRawBeanDefinition().setSource(source);
bldr.addPropertyReference("accessDecisionManager", accessManagerId);
bldr.addPropertyValue("authenticationManager", new RootBeanDefinition(AuthenticationManagerDelegator.class));
bldr.addPropertyValue("securityMetadataSource", metadataSource);
if (StringUtils.hasText(runAsManagerId)) {
bldr.addPropertyReference("runAsManager", runAsManagerId);
}
@@ -9,6 +9,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
import org.springframework.beans.factory.xml.ParserContext;
@@ -64,16 +65,16 @@ class InternalInterceptMethodsBeanDefinitionDecorator extends AbstractIntercepto
interceptor.addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
// Lookup parent bean information
Element parent = (Element) node.getParentNode();
String parentBeanClass = parent.getAttribute("class");
parent = null;
String parentBeanClass = ((Element) node.getParentNode()).getAttribute("class");
// Parse the included methods
List<Element> methods = DomUtils.getChildElementsByTagName(interceptMethodsElt, Elements.PROTECT);
Map<String, List<ConfigAttribute>> mappings = new LinkedHashMap<String, List<ConfigAttribute>>();
Map<String, BeanDefinition> mappings = new ManagedMap<String, BeanDefinition>();
for (Element protectmethodElt : methods) {
String[] tokens = StringUtils.commaDelimitedListToStringArray(protectmethodElt.getAttribute(ATT_ACCESS));
BeanDefinitionBuilder attributeBuilder = BeanDefinitionBuilder.rootBeanDefinition(SecurityConfig.class);
attributeBuilder.setFactoryMethod("createListFromCommaDelimitedString");
attributeBuilder.addConstructorArgValue(protectmethodElt.getAttribute(ATT_ACCESS));
// Support inference of class names
String methodName = protectmethodElt.getAttribute(ATT_METHOD);
@@ -84,7 +85,7 @@ class InternalInterceptMethodsBeanDefinitionDecorator extends AbstractIntercepto
}
}
mappings.put(methodName, SecurityConfig.createList(tokens));
mappings.put(methodName, attributeBuilder.getBeanDefinition());
}
BeanDefinition metadataSource = new RootBeanDefinition(MapBasedMethodSecurityMetadataSource.class);
@@ -1,11 +1,7 @@
package org.springframework.security.config.method;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -44,15 +40,16 @@ import org.springframework.util.StringUtils;
*
* @author Ben Alex
* @since 2.0
*
*/
final class ProtectPointcutPostProcessor implements BeanPostProcessor {
private static final Log logger = LogFactory.getLog(ProtectPointcutPostProcessor.class);
private Map<String,List<ConfigAttribute>> pointcutMap = new LinkedHashMap<String,List<ConfigAttribute>>();
private MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource;
private PointcutParser parser;
private final Map<String,List<ConfigAttribute>> pointcutMap = new LinkedHashMap<String,List<ConfigAttribute>>();
private final MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource;
private final Set<PointcutExpression> pointCutExpressions = new LinkedHashSet<PointcutExpression>();
private final PointcutParser parser;
private final Set<String> processedBeans = new HashSet<String>();
public ProtectPointcutPostProcessor(MapBasedMethodSecurityMetadataSource mapBasedMethodSecurityMetadataSource) {
Assert.notNull(mapBasedMethodSecurityMetadataSource, "MapBasedMethodSecurityMetadataSource to populate is required");
@@ -78,6 +75,11 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (processedBeans.contains(beanName)) {
// We already have the metadata for this bean
return bean;
}
// Obtain methods for the present bean
Method[] methods;
try {
@@ -88,10 +90,7 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
// Check to see if any of those methods are compatible with our pointcut expressions
for (int i = 0; i < methods.length; i++) {
for (String ex : pointcutMap.keySet()) {
// Parse the presented AspectJ pointcut expression
PointcutExpression expression = parser.parsePointcutExpression(ex);
for (PointcutExpression expression : pointCutExpressions) {
// 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
@@ -100,6 +99,8 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
}
}
processedBeans.add(beanName);
return bean;
}
@@ -134,6 +135,8 @@ final class ProtectPointcutPostProcessor implements BeanPostProcessor {
Assert.notNull(definition, "A List of ConfigAttributes is required");
pointcutExpression = replaceBooleanOperators(pointcutExpression);
pointcutMap.put(pointcutExpression, definition);
// Parse the presented AspectJ pointcut expression and add it to the cache
pointCutExpressions.add(parser.parsePointcutExpression(pointcutExpression));
if (logger.isDebugEnabled()) {
logger.debug("AspectJ pointcut expression '" + pointcutExpression + "' registered for security configuration attribute '" + definition + "'");
@@ -1,5 +1,7 @@
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-3.0.xsd
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-3.0.4.xsd
http\://www.springframework.org/schema/security/spring-security-3.0.xsd=org/springframework/security/config/spring-security-3.0.xsd
http\://www.springframework.org/schema/security/spring-security-3.0.4.xsd=org/springframework/security/config/spring-security-3.0.4.xsd
http\://www.springframework.org/schema/security/spring-security-3.0.3.xsd=org/springframework/security/config/spring-security-3.0.3.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
@@ -8,7 +8,7 @@ start = http | ldap-server | authentication-provider | ldap-authentication-provi
hash =
## Defines the hashing algorithm used on user passwords. We recommend strongly against using MD4, as it is a very weak hashing algorithm.
attribute hash {"plaintext" | "sha" | "sha-256" | "md5" | "md4" | "{sha}" | "{ssha}"}
base64 =
base64 =
## Whether a string should be base64 encoded
attribute base64 {"true" | "false"}
path-type =
@@ -20,9 +20,9 @@ port =
url =
## Specifies a URL.
attribute url { xsd:token }
id =
id =
## A bean identifier, used for referring to the bean elsewhere in the context.
attribute id {xsd:ID}
attribute id {xsd:ID}
ref =
## Defines a reference to a Spring bean Id.
attribute ref {xsd:token}
@@ -35,47 +35,47 @@ user-service-ref =
## A reference to a user-service (or UserDetailsService bean) Id
attribute user-service-ref {xsd:token}
data-source-ref =
data-source-ref =
## A reference to a DataSource bean
attribute data-source-ref {xsd:token}
password-encoder =
attribute data-source-ref {xsd:token}
password-encoder =
## element which defines a password encoding strategy. Used by an authentication provider to convert submitted passwords to hashed versions, for example.
element password-encoder {password-encoder.attlist, salt-source?}
element password-encoder {password-encoder.attlist, salt-source?}
password-encoder.attlist &=
ref | (hash? & base64?)
salt-source =
## Password salting strategy. A system-wide constant or a property from the UserDetails object can be used.
element salt-source {user-property | system-wide | ref}
user-property =
## A property of the UserDetails object which will be used as salt by a password encoder. Typically something like "username" might be used.
## A property of the UserDetails object which will be used as salt by a password encoder. Typically something like "username" might be used.
attribute user-property {xsd:token}
system-wide =
## A single value that will be used as the salt for a password encoder.
## A single value that will be used as the salt for a password encoder.
attribute system-wide {xsd:token}
boolean = "true" | "false"
role-prefix =
## A non-empty string prefix that will be added to role strings loaded from persistent storage (e.g. "ROLE_"). Use the value "none" for no prefix in cases where the default is non-empty.
attribute role-prefix {xsd:token}
use-expressions =
## Enables the use of expressions in the 'access' attributes in <intercept-url> elements rather than the traditional list of configuration attributes. Defaults to 'false'. If enabled, each attribute should contain a single boolean expression. If the expression evaluates to 'true', access will be granted.
## Enables the use of expressions in the 'access' attributes in <intercept-url> elements rather than the traditional list of configuration attributes. Defaults to 'false'. If enabled, each attribute should contain a single boolean expression. If the expression evaluates to 'true', access will be granted.
attribute use-expressions {boolean}
ldap-server =
## Defines an LDAP server location or starts an embedded server. The url indicates the location of a remote server. If no url is given, an embedded server will be started, listening on the supplied port number. The port is optional and defaults to 33389. A Spring LDAP ContextSource bean will be registered for the server with the id supplied.
## Defines an LDAP server location or starts an embedded server. The url indicates the location of a remote server. If no url is given, an embedded server will be started, listening on the supplied port number. The port is optional and defaults to 33389. A Spring LDAP ContextSource bean will be registered for the server with the id supplied.
element ldap-server {ldap-server.attlist}
ldap-server.attlist &= id?
ldap-server.attlist &= (url | port)?
ldap-server.attlist &=
## Username (DN) of the "manager" user identity which will be used to authenticate to a (non-embedded) LDAP server. If omitted, anonymous access will be used.
## Username (DN) of the "manager" user identity which will be used to authenticate to a (non-embedded) LDAP server. If omitted, anonymous access will be used.
attribute manager-dn {xsd:string}?
ldap-server.attlist &=
## The password for the manager DN.
attribute manager-password {xsd:string}?
attribute manager-password {xsd:string}?
ldap-server.attlist &=
## Explicitly specifies an ldif file resource to load into an embedded LDAP server
attribute ldif { xsd:string }?
@@ -84,14 +84,14 @@ ldap-server.attlist &=
attribute root { xsd:string }?
ldap-server-ref-attribute =
## The optional server to use. If omitted, and a default LDAP server is registered (using <ldap-server> with no Id), that server will be used.
## The optional server to use. If omitted, and a default LDAP server is registered (using <ldap-server> with no Id), that server will be used.
attribute server-ref {xsd:token}
group-search-filter-attribute =
group-search-filter-attribute =
## Group search filter. Defaults to (uniqueMember={0}). The substituted parameter is the DN of the user.
attribute group-search-filter {xsd:token}
group-search-base-attribute =
group-search-base-attribute =
## Search base for group membership searches. Defaults to "" (searching from the root).
attribute group-search-base {xsd:token}
user-search-filter-attribute =
@@ -103,7 +103,7 @@ user-search-base-attribute =
group-role-attribute-attribute =
## The LDAP attribute name which contains the role name which will be used within Spring Security. Defaults to "cn".
attribute group-role-attribute {xsd:token}
user-details-class-attribute =
user-details-class-attribute =
## Allows the objectClass of the user entry to be specified. If set, the framework will attempt to load standard attributes for the defined class into the returned UserDetails object
attribute user-details-class {"person" | "inetOrgPerson"}
user-context-mapper-attribute =
@@ -113,7 +113,7 @@ user-context-mapper-attribute =
ldap-user-service =
element ldap-user-service {ldap-us.attlist}
ldap-us.attlist &= id?
ldap-us.attlist &= id?
ldap-us.attlist &=
ldap-server-ref-attribute?
ldap-us.attlist &=
@@ -144,7 +144,7 @@ ldap-ap.attlist &=
user-search-filter-attribute?
ldap-ap.attlist &=
group-search-base-attribute?
ldap-ap.attlist &=
ldap-ap.attlist &=
group-search-filter-attribute?
ldap-ap.attlist &=
group-role-attribute-attribute?
@@ -159,7 +159,7 @@ ldap-ap.attlist &=
password-compare-element =
## Specifies that an LDAP provider should use an LDAP compare operation of the user's password to authenticate the user
element password-compare {password-compare.attlist, password-encoder?}
password-compare.attlist &=
## The attribute in the directory which contains the user password. Defaults to "userPassword".
attribute password-attribute {xsd:token}?
@@ -187,7 +187,7 @@ protect.attlist &=
global-method-security =
## Provides method security for all beans registered in the Spring application context. Specifically, beans will be scanned for matches with the ordered list of "protect-pointcut" sub-elements, Spring Security annotations and/or. Where there is a match, the beans will automatically be proxied and security authorization applied to the methods accordingly. If you use and enable all four sources of method security metadata (ie "protect-pointcut" declarations, expression annotations, @Secured and also JSR250 security annotations), the metadata sources will be queried in that order. In practical terms, this enables you to use XML to override method security metadata expressed in annotations. If using annotations, the order of precedence is EL-based (@PreAuthorize etc.), @Secured and finally JSR-250.
element global-method-security {global-method-security.attlist, (pre-post-annotation-handling | expression-handler)?, protect-pointcut*, after-invocation-provider*}
element global-method-security {global-method-security.attlist, (pre-post-annotation-handling | expression-handler)?, protect-pointcut*, after-invocation-provider*}
global-method-security.attlist &=
## Specifies whether the use of Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) should be enabled for this application context. Defaults to "disabled".
attribute pre-post-annotations {"disabled" | "enabled" }?
@@ -208,26 +208,29 @@ global-method-security.attlist &=
attribute order {xsd:token}?
global-method-security.attlist &=
attribute proxy-target-class {boolean}?
global-method-security.attlist &=
## Can be used to specify that AspectJ should be used instead of the default Spring AOP. If set, secured classes must be woven with the AnnotationSecurityAspect from the spring-security-aspects module.
attribute mode {"aspectj"}?
after-invocation-provider =
## Allows addition of extra AfterInvocationProvider beans which should be called by the MethodSecurityInterceptor created by global-method-security.
element after-invocation-provider {ref}
element after-invocation-provider {ref}
pre-post-annotation-handling =
## Allows the default expression-based mechanism for handling Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) to be replace entirely. Only applies if these annotations are enabled.
element pre-post-annotation-handling {invocation-attribute-factory, pre-invocation-advice, post-invocation-advice}
## Allows the default expression-based mechanism for handling Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) to be replace entirely. Only applies if these annotations are enabled.
element pre-post-annotation-handling {invocation-attribute-factory, pre-invocation-advice, post-invocation-advice}
invocation-attribute-factory =
## Defines the PrePostInvocationAttributeFactory instance which is used to generate pre and post invocation metadata from the annotated methods.
## Defines the PrePostInvocationAttributeFactory instance which is used to generate pre and post invocation metadata from the annotated methods.
element invocation-attribute-factory {ref}
pre-invocation-advice =
element pre-invocation-advice {ref}
post-invocation-advice =
element post-invocation-advice {ref}
expression-handler =
## Defines the SecurityExpressionHandler instance which will be used if expression-based access-control is enabled. A default implementation (with no ACL support) will be used if not supplied.
element expression-handler {ref}
@@ -242,6 +245,9 @@ protect-pointcut.attlist &=
## Access configuration attributes list that applies to all methods matching the pointcut, e.g. "ROLE_A,ROLE_B"
attribute access {xsd:token}
http-firewall =
## Allows a custom instance of HttpFirewall to be injected into the FilterChainProxy created by the namespace.
element http-firewall {ref}
http =
## Container element for HTTP security configuration
@@ -254,9 +260,9 @@ http.attlist &=
http.attlist &=
## Controls the eagerness with which an HTTP session is created. If not set, defaults to "ifRequired". Note that if a custom SecurityContextRepository is set using security-context-repository-ref, then the only value which can be set is "always". Otherwise the session creation behaviour will be determined by the repository bean implementation.
attribute create-session {"ifRequired" | "always" | "never" }?
http.attlist &=
http.attlist &=
## A reference to a SecurityContextRepository bean. This can be used to customize how the SecurityContext is stored between requests.
attribute security-context-repository-ref {xsd:token}?
attribute security-context-repository-ref {xsd:token}?
http.attlist &=
## The path format used to define the paths in child elements.
path-type?
@@ -273,7 +279,7 @@ http.attlist &=
## Optional attribute specifying the realm name that will be used for all authentication features that require a realm name (eg BASIC and Digest authentication). If unspecified, defaults to "Spring Security Application".
attribute realm {xsd:token}?
http.attlist &=
## Allows a customized AuthenticationEntryPoint to be used.
## Allows a customized AuthenticationEntryPoint to be set on the ExceptionTranslationFilter.
attribute entry-point-ref {xsd:token}?
http.attlist &=
## Corresponds to the observeOncePerRequest property of FilterSecurityInterceptor. Defaults to "true"
@@ -282,17 +288,17 @@ http.attlist &=
## Deprecated in favour of the access-denied-handler element.
attribute access-denied-page {xsd:token}?
http.attlist &=
##
attribute disable-url-rewriting {boolean}?
##
attribute disable-url-rewriting {boolean}?
access-denied-handler =
## Defines the access-denied strategy that should be used. An access denied page can be defined or a reference to an AccessDeniedHandler instance.
access-denied-handler =
## Defines the access-denied strategy that should be used. An access denied page can be defined or a reference to an AccessDeniedHandler instance.
element access-denied-handler {access-denied-handler.attlist, empty}
access-denied-handler.attlist &= (ref | access-denied-handler-page)
access-denied-handler-page =
## The access denied page that an authenticated user will be redirected to if they request a page which they don't have the authority to access.
## The access denied page that an authenticated user will be redirected to if they request a page which they don't have the authority to access.
attribute error-page {xsd:token}
intercept-url =
@@ -316,16 +322,16 @@ intercept-url.attlist &=
attribute requires-channel {xsd:token}?
logout =
## Incorporates a logout processing filter. Most web applications require a logout filter, although you may not require one if you write a controller to provider similar logic.
## Incorporates a logout processing filter. Most web applications require a logout filter, although you may not require one if you write a controller to provider similar logic.
element logout {logout.attlist, empty}
logout.attlist &=
## Specifies the URL that will cause a logout. Spring Security will initialize a filter that responds to this particular URL. Defaults to /j_spring_security_logout if unspecified.
## Specifies the URL that will cause a logout. Spring Security will initialize a filter that responds to this particular URL. Defaults to /j_spring_security_logout if unspecified.
attribute logout-url {xsd:token}?
logout.attlist &=
## Specifies the URL to display once the user has logged out. If not specified, defaults to /.
## Specifies the URL to display once the user has logged out. If not specified, defaults to /.
attribute logout-success-url {xsd:token}?
logout.attlist &=
## Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true.
## Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true.
attribute invalidate-session {boolean}?
logout.attlist &=
## A reference to a LogoutSuccessHandler implementation which will be used to determine the destination to which the user is taken after logging out.
@@ -346,8 +352,8 @@ form-login.attlist &=
## The URL that will be redirected to after successful authentication, if the user's previous action could not be resumed. This generally happens if the user visits a login page without having first requested a secured operation that triggers authentication. If unspecified, defaults to the root of the application.
attribute default-target-url {xsd:token}?
form-login.attlist &=
## Whether the user should always be redirected to the default-target-url after login.
attribute always-use-default-target {boolean}?
## Whether the user should always be redirected to the default-target-url after login.
attribute always-use-default-target {boolean}?
form-login.attlist &=
## The URL for the login page. If no login URL is specified, Spring Security will automatically create a login URL at /spring_security_login and a corresponding filter to render that login URL when requested.
attribute login-page {xsd:token}?
@@ -362,7 +368,7 @@ form-login.attlist &=
attribute authentication-failure-handler-ref {xsd:token}?
openid-login =
openid-login =
## Sets up form login for authentication with an Open ID identity
element openid-login {form-login.attlist, user-service-ref?, attribute-exchange?}
@@ -380,7 +386,7 @@ openid-attribute.attlist &=
attribute required {boolean}?
openid-attribute.attlist &=
attribute count {xsd:int}?
filter-chain-map =
## Used to explicitly configure a FilterChainProxy instance with a FilterChainMap
@@ -397,7 +403,7 @@ filter-chain.attlist &=
attribute filters {xsd:token}
filter-security-metadata-source =
## Used to explicitly configure a FilterSecurityMetadataSource bean for use with a FilterSecurityInterceptor. Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the <http> element. The intercept-url elements used should only contain pattern, method and access attributes. Any others will result in a configuration error.
## Used to explicitly configure a FilterSecurityMetadataSource bean for use with a FilterSecurityInterceptor. Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the <http> element. The intercept-url elements used should only contain pattern, method and access attributes. Any others will result in a configuration error.
element filter-security-metadata-source {fsmds.attlist, intercept-url+}
fsmds.attlist &=
use-expressions?
@@ -410,15 +416,18 @@ fsmds.attlist &=
## as for http element
path-type?
filter-invocation-definition-source =
filter-invocation-definition-source =
## Deprecated synonym for filter-security-metadata-source
element filter-invocation-definition-source {fsmds.attlist, intercept-url+}
http-basic =
## Adds support for basic authentication (this is an element to permit future expansion, such as supporting an "ignoreFailure" attribute)
element http-basic {empty}
element http-basic {http-basic.attlist, empty}
http-basic.attlist &=
## Sets the AuthenticationEntryPoint which is used by the BasicAuthenticationFilter.
attribute entry-point-ref {xsd:token}?
session-management =
session-management =
element session-management {session-management.attlist, concurrency-control?}
session-management.attlist &=
@@ -431,18 +440,18 @@ session-management.attlist &=
## Allows injection of the SessionAuthenticationStrategy instance used by the SessionManagementFilter
attribute session-authentication-strategy-ref {xsd:token}?
session-management.attlist &=
## Defines the URL of the error page which should be shown when the SessionAuthenticationStrategy raises an exception. If not set, an unauthorized (402) error code will be returned to the client. Note that this attribute doesn't apply if the error occurs during a form-based login, where the URL for authentication failure will take precedence.
## Defines the URL of the error page which should be shown when the SessionAuthenticationStrategy raises an exception. If not set, an unauthorized (402) error code will be returned to the client. Note that this attribute doesn't apply if the error occurs during a form-based login, where the URL for authentication failure will take precedence.
attribute session-authentication-error-url {xsd:token}?
concurrency-control =
concurrency-control =
## Enables concurrent session control, limiting the number of authenticated sessions a user may have at the same time.
element concurrency-control {concurrency-control.attlist, empty}
concurrency-control.attlist &=
## The maximum number of sessions a single authenticated user can have open at the same time. Defaults to "1".
attribute max-sessions {xsd:positiveInteger}?
concurrency-control.attlist &=
concurrency-control.attlist &=
## The URL a user will be redirected to if they attempt to use a session which has been "expired" because they have logged in again.
attribute expired-url {xsd:token}?
concurrency-control.attlist &=
@@ -457,21 +466,21 @@ concurrency-control.attlist &=
remember-me =
## Sets up remember-me authentication. If used with the "key" attribute (or no attributes) the cookie-only implementation will be used. Specifying "token-repository-ref" or "remember-me-data-source-ref" will use the more secure, persisten token approach.
## Sets up remember-me authentication. If used with the "key" attribute (or no attributes) the cookie-only implementation will be used. Specifying "token-repository-ref" or "remember-me-data-source-ref" will use the more secure, persisten token approach.
element remember-me {remember-me.attlist}
remember-me.attlist &=
## The "key" used to identify cookies from a specific token-based remember-me application. You should set this to a unique value for your application.
attribute key {xsd:token}?
remember-me.attlist &=
(token-repository-ref | remember-me-data-source-ref | remember-me-services-ref)
remember-me.attlist &=
user-service-ref?
remember-me.attlist &=
## Exports the internally defined RememberMeServices as a bean alias, allowing it to be used by other beans in the application context.
attribute services-alias {xsd:token}?
attribute services-alias {xsd:token}?
remember-me.attlist &=
## Determines whether the "secure" flag will be set on the remember-me cookie. If set to true, the cookie will only be submitted over HTTPS. Defaults to false.
@@ -480,15 +489,15 @@ remember-me.attlist &=
remember-me.attlist &=
## The period (in seconds) for which the remember-me cookie should be valid.
attribute token-validity-seconds {xsd:integer}?
token-repository-ref =
## Reference to a PersistentTokenRepository bean for use with the persistent token remember-me implementation.
## Reference to a PersistentTokenRepository bean for use with the persistent token remember-me implementation.
attribute token-repository-ref {xsd:token}
remember-me-services-ref =
## Allows a custom implementation of RememberMeServices to be used. Note that this implementation should return RememberMeAuthenticationToken instances with the same "key" value as specified in the remember-me element. Alternatively it should register its own AuthenticationProvider.
remember-me-services-ref =
## Allows a custom implementation of RememberMeServices to be used. Note that this implementation should return RememberMeAuthenticationToken instances with the same "key" value as specified in the remember-me element. Alternatively it should register its own AuthenticationProvider.
attribute services-ref {xsd:token}?
remember-me-data-source-ref =
## DataSource bean for the database that contains the token repository schema.
## DataSource bean for the database that contains the token repository schema.
data-source-ref
anonymous =
@@ -497,56 +506,59 @@ anonymous =
anonymous.attlist &=
## The key shared between the provider and filter. This generally does not need to be set. If unset, it will default to "doesNotMatter".
attribute key {xsd:token}?
anonymous.attlist &=
anonymous.attlist &=
## The username that should be assigned to the anonymous request. This allows the principal to be identified, which may be important for logging and auditing. if unset, defaults to "anonymousUser".
attribute username {xsd:token}?
anonymous.attlist &=
## The granted authority that should be assigned to the anonymous request. Commonly this is used to assign the anonymous request particular roles, which can subsequently be used in authorization decisions. If unset, defaults to "ROLE_ANONYMOUS".
attribute granted-authority {xsd:token}?
anonymous.attlist &=
## With the default namespace setup, the anonymous "authentication" facility is automatically enabled. You can disable it using this property.
## With the default namespace setup, the anonymous "authentication" facility is automatically enabled. You can disable it using this property.
attribute enabled {boolean}?
port-mappings =
port-mappings =
## Defines the list of mappings between http and https ports for use in redirects
element port-mappings {port-mappings.attlist, port-mapping+}
port-mappings.attlist &= empty
port-mapping =
port-mapping =
element port-mapping {http-port, https-port}
http-port = attribute http {xsd:token}
https-port = attribute https {xsd:token}
x509 =
x509 =
## Adds support for X.509 client authentication.
element x509 {x509.attlist}
x509.attlist &=
x509.attlist &=
## The regular expression used to obtain the username from the certificate's subject. Defaults to matching on the common name using the pattern "CN=(.*?),".
attribute subject-principal-regex {xsd:token}?
x509.attlist &=
## Explicitly specifies which user-service should be used to load user data for X.509 authenticated clients. If ommitted, the default user-service will be used.
## Explicitly specifies which user-service should be used to load user data for X.509 authenticated clients. If ommitted, the default user-service will be used.
user-service-ref?
authentication-manager =
## Registers the AuthenticationManager instance and allows its list of AuthenticationProviders to be defined. Also allows you to define an alias to allow you to reference the AuthenticationManager in your own beans.
## Registers the AuthenticationManager instance and allows its list of AuthenticationProviders to be defined. Also allows you to define an alias to allow you to reference the AuthenticationManager in your own beans.
element authentication-manager {authman.attlist & authentication-provider* & ldap-authentication-provider*}
authman.attlist &=
## The alias you wish to use for the AuthenticationManager bean
attribute alias {xsd:ID}?
authman.attlist &=
## If set to true, the AuthenticationManger will attempt to clear any credentials data in the returned Authentication object, once the user has been authenticated. Defaults to false.
attribute erase-credentials {boolean}?
authentication-provider =
## Indicates that the contained user-service should be used as an authentication source.
## Indicates that the contained user-service should be used as an authentication source.
element authentication-provider {ap.attlist & any-user-service & password-encoder?}
ap.attlist &=
## Specifies a reference to a separately configured AuthenticationProvider instance which should be registered within the AuthenticationManager.
ref?
## Specifies a reference to a separately configured AuthenticationProvider instance which should be registered within the AuthenticationManager.
ref?
ap.attlist &=
## Specifies a reference to a separately configured UserDetailsService from which to obtain authentication data.
## Specifies a reference to a separately configured UserDetailsService from which to obtain authentication data.
user-service-ref?
user-service =
@@ -554,31 +566,31 @@ user-service =
element user-service {id? & (properties-file | (user*))}
properties-file =
attribute properties {xsd:token}?
user =
## Represents a user in the application.
## Represents a user in the application.
element user {user.attlist, empty}
user.attlist &=
## The username assigned to the user.
## The username assigned to the user.
attribute name {xsd:token}
user.attlist &=
## The password assigned to the user. This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element). This attribute be omitted in the case where the data will not be used for authentication, but only for accessing authorities. If omitted, the namespace will generate a random value, preventing its accidental use for authentication. Cannot be empty.
## The password assigned to the user. This may be hashed if the corresponding authentication provider supports hashing (remember to set the "hash" attribute of the "user-service" element). This attribute be omitted in the case where the data will not be used for authentication, but only for accessing authorities. If omitted, the namespace will generate a random value, preventing its accidental use for authentication. Cannot be empty.
attribute password {xsd:string}?
user.attlist &=
## One of more authorities granted to the user. Separate authorities with a comma (but no space). For example, "ROLE_USER,ROLE_ADMINISTRATOR"
## One of more authorities granted to the user. Separate authorities with a comma (but no space). For example, "ROLE_USER,ROLE_ADMINISTRATOR"
attribute authorities {xsd:token}
user.attlist &=
## Can be set to "true" to mark an account as locked and unusable.
## Can be set to "true" to mark an account as locked and unusable.
attribute locked {boolean}?
user.attlist &=
## Can be set to "true" to mark an account as disabled and unusable.
## Can be set to "true" to mark an account as disabled and unusable.
attribute disabled {boolean}?
jdbc-user-service =
## Causes creation of a JDBC-based UserDetailsService.
element jdbc-user-service {id? & jdbc-user-service.attlist}
## Causes creation of a JDBC-based UserDetailsService.
element jdbc-user-service {id? & jdbc-user-service.attlist}
jdbc-user-service.attlist &=
## The bean ID of the DataSource which provides the required tables.
## The bean ID of the DataSource which provides the required tables.
attribute data-source-ref {xsd:token}
jdbc-user-service.attlist &=
cache-ref?
@@ -593,12 +605,12 @@ jdbc-user-service.attlist &=
attribute group-authorities-by-username-query {xsd:token}?
jdbc-user-service.attlist &=
role-prefix?
any-user-service = user-service | jdbc-user-service | ldap-user-service
custom-filter =
## Used to indicate that a filter bean declaration should be incorporated into the security filter chain.
## Used to indicate that a filter bean declaration should be incorporated into the security filter chain.
element custom-filter {custom-filter.attlist}
custom-filter.attlist &=
@@ -608,7 +620,7 @@ custom-filter.attlist &=
(after | before | position)
after =
## The filter immediately after which the custom-filter should be placed in the chain. This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. The filter names map to specific Spring Security implementation filters.
## The filter immediately after which the custom-filter should be placed in the chain. This feature will only be needed by advanced users who wish to mix their own filters into the security filter chain and have some knowledge of the standard Spring Security filters. The filter names map to specific Spring Security implementation filters.
attribute after {named-security-filter}
before =
## The filter immediately before which the custom-filter should be placed in the chain
@@ -619,5 +631,3 @@ position =
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "CONCURRENT_SESSION_FILTER" | "SECURITY_CONTEXT_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" |"BASIC_AUTH_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "SESSION_MANAGEMENT_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
@@ -70,40 +70,40 @@ public class FilterChainProxyConfigTests {
@Test
public void normalOperation() throws Exception {
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("filterChain", FilterChainProxy.class);
FilterChainProxy filterChainProxy = appCtx.getBean("filterChain", FilterChainProxy.class);
doNormalOperation(filterChainProxy);
}
@Test
public void normalOperationWithNewConfig() throws Exception {
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxy", FilterChainProxy.class);
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxy", FilterChainProxy.class);
checkPathAndFilterOrder(filterChainProxy);
doNormalOperation(filterChainProxy);
}
@Test
public void normalOperationWithNewConfigRegex() throws Exception {
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyRegex", FilterChainProxy.class);
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyRegex", FilterChainProxy.class);
checkPathAndFilterOrder(filterChainProxy);
doNormalOperation(filterChainProxy);
}
@Test
public void normalOperationWithNewConfigNonNamespace() throws Exception {
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyNonNamespace", FilterChainProxy.class);
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyNonNamespace", FilterChainProxy.class);
checkPathAndFilterOrder(filterChainProxy);
doNormalOperation(filterChainProxy);
}
@Test
public void pathWithNoMatchHasNoFilters() throws Exception {
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
assertEquals(null, filterChainProxy.getFilters("/nomatch"));
}
@Test
public void urlStrippingPropertyIsRespected() throws Exception {
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
// Should only match if we are stripping the query string
String url = "/blah.bar?x=something";
@@ -116,7 +116,7 @@ public class FilterChainProxyConfigTests {
// SEC-1235
@Test
public void mixingPatternsAndPlaceholdersDoesntCauseOrderingIssues() throws Exception {
FilterChainProxy filterChainProxy = (FilterChainProxy) appCtx.getBean("sec1235FilterChainProxy", FilterChainProxy.class);
FilterChainProxy filterChainProxy = appCtx.getBean("sec1235FilterChainProxy", FilterChainProxy.class);
String[] paths = filterChainProxy.getFilterChainMap().keySet().toArray(new String[0]);
assertEquals("/login*", paths[0]);
@@ -23,7 +23,7 @@ public class SecurityNamespacehandlerTests {
);
fail("Expected BeanDefinitionParsingException");
} catch (BeanDefinitionParsingException expected) {
assertTrue(expected.getMessage().contains("You cannot use a spring-security-2.0.xsd schema"));
assertTrue(expected.getMessage().contains("You must use a 3.0 schema with Spring Security 3.0."));
}
}
}
@@ -53,6 +53,20 @@ public class AuthenticationManagerBeanDefinitionParserTests {
assertEquals(1, listener.events.size());
}
@Test
public void credentialsAreNotClearedByDefault() throws Exception {
setContext(CONTEXT, "3.0");
ProviderManager pm = (ProviderManager) appContext.getBeansOfType(ProviderManager.class).values().toArray()[0];
assertFalse(pm.isEraseCredentialsAfterAuthentication());
}
@Test
public void clearCredentialsPropertyIsRespected() throws Exception {
setContext("<authentication-manager erase-credentials='true'/>", "3.0.3");
ProviderManager pm = (ProviderManager) appContext.getBeansOfType(ProviderManager.class).values().toArray()[0];
assertTrue(pm.isEraseCredentialsAfterAuthentication());
}
private void setContext(String context, String version) {
appContext = new InMemoryXmlApplicationContext(context, version, null);
}
@@ -77,12 +77,12 @@ public class UserServiceBeanDefinitionParserTests {
setContext(
"<user-service id='service'>" +
" <user name='joe' password='joespassword' authorities='ROLE_A' locked='true'/>" +
" <user name='bob' password='bobspassword' authorities='ROLE_A' disabled='true'/>" +
" <user name='Bob' password='bobspassword' authorities='ROLE_A' disabled='true'/>" +
"</user-service>");
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
UserDetails joe = userService.loadUserByUsername("joe");
assertFalse(joe.isAccountNonLocked());
UserDetails bob = userService.loadUserByUsername("bob");
UserDetails bob = userService.loadUserByUsername("bOb");
assertFalse(bob.isEnabled());
}
@@ -0,0 +1,101 @@
/*
* Copyright 2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.springframework.security.config.http;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.contains;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.verify;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.internal.util.reflection.Whitebox;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.memory.UserAttribute;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.access.intercept.RequestKey;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.util.AntUrlPathMatcher;
/**
*
* @author Rob Winch
*/
@RunWith(MockitoJUnitRunner.class)
public class DefaultFilterChainValidatorTests {
private DefaultFilterChainValidator validator;
private FilterChainProxy fcp;
@Mock
private Log logger;
@Mock
private AccessDecisionManager accessDecisionManager;
@SuppressWarnings({"unchecked","rawtypes"})
@Before
public void setUp() throws Exception {
AntUrlPathMatcher matcher = new AntUrlPathMatcher();
LinkedHashMap<RequestKey, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestKey, Collection<ConfigAttribute>>();
requestMap.put(new RequestKey("/login"), Collections.<ConfigAttribute>emptyList());
DefaultFilterInvocationSecurityMetadataSource metadataSource = new DefaultFilterInvocationSecurityMetadataSource(matcher,requestMap);
AnonymousAuthenticationFilter aaf = new AnonymousAuthenticationFilter();
aaf.setKey("anonymous");
UserAttribute userAttribute = new UserAttribute();
userAttribute.setAuthorities(AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
userAttribute.setPassword("password");
aaf.setUserAttribute(userAttribute);
FilterSecurityInterceptor fsi = new FilterSecurityInterceptor();
fsi.setAccessDecisionManager(accessDecisionManager);
fsi.setSecurityMetadataSource(metadataSource);
LoginUrlAuthenticationEntryPoint authenticationEntryPoint = new LoginUrlAuthenticationEntryPoint();
authenticationEntryPoint.setLoginFormUrl("/login");
ExceptionTranslationFilter etf = new ExceptionTranslationFilter();
etf.setAuthenticationEntryPoint(authenticationEntryPoint);
Map filterChainMap = new HashMap();
filterChainMap.put("/**",Arrays.asList(aaf,etf,fsi));
fcp = new FilterChainProxy();
fcp.setFilterChainMap(filterChainMap);
fcp.setMatcher(matcher);
validator = new DefaultFilterChainValidator();
Whitebox.setInternalState(validator, "logger", logger);
}
// Ensure SEC-1878 does not occur later
@SuppressWarnings("unchecked")
@Test
public void validateCheckLoginPageIsntProtectedThrowsIllegalArgumentException() {
IllegalArgumentException toBeThrown = new IllegalArgumentException("failed to eval expression");
doThrow(toBeThrown).when(accessDecisionManager).decide(any(Authentication.class), anyObject(), any(Collection.class));
validator.validate(fcp);
verify(logger).warn(contains(toBeThrown.toString()));
}
}
@@ -80,11 +80,13 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationFi
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.security.web.firewall.DefaultHttpFirewall;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.ReflectionUtils;
/**
@@ -183,6 +185,29 @@ public class HttpSecurityBeanDefinitionParserTests {
assertTrue(filters.size() == 0);
}
@Test(expected=BeanDefinitionParsingException.class)
public void filtersEqualsNoneErrorsWithRequiresChannel() throws Exception {
setContext(
" <http auto-config='true'>" +
" <intercept-url pattern='/ambiguousConfig' requires-channel='https' filters='none' />" +
" </http>" + AUTH_PROVIDER_XML);
}
@Test(expected=BeanDefinitionParsingException.class)
public void filtersEqualsNoneErrorsWithAccess() throws Exception {
setContext(
" <http auto-config='true'>" +
" <intercept-url pattern='/ambiguousConfig' access='ROLE_USER' filters='none' />" +
" </http>" + AUTH_PROVIDER_XML);
}
@Test(expected=BeanDefinitionParsingException.class)
public void filtersEqualsNoneErrorsWithRequiresChannelAndAccess() throws Exception {
setContext(
" <http auto-config='true'>" +
" <intercept-url pattern='/ambiguousConfig' requires-channel='https' filters='none' />" +
" </http>" + AUTH_PROVIDER_XML);
}
@Test
public void regexPathsWorkCorrectly() throws Exception {
@@ -407,6 +432,23 @@ public class HttpSecurityBeanDefinitionParserTests {
assertTrue(attrs.contains(new SecurityConfig("ROLE_B")));
}
@Test
public void httpMethodMatchIsSupportedForRequiresChannel() throws Exception {
setContext(
" <http auto-config='true'>" +
" <intercept-url pattern='/anyurl'/>" +
" <intercept-url pattern='/anyurl' method='GET' access='ROLE_ADMIN' requires-channel='https' />" +
" </http>" + AUTH_PROVIDER_XML);
ChannelProcessingFilter filter = getFilter(ChannelProcessingFilter.class);
FilterInvocationSecurityMetadataSource fids = (FilterInvocationSecurityMetadataSource)FieldUtils.getFieldValue(filter,"securityMetadataSource");
Collection<ConfigAttribute> attrs = fids.getAttributes(createFilterinvocation("/anyurl", "GET"));
assertEquals(1, attrs.size());
attrs = fids.getAttributes(createFilterinvocation("/anyurl", "POST"));
assertEquals(null, attrs);
}
@Test
public void oncePerRequestAttributeIsSupported() throws Exception {
setContext("<http once-per-request='false'><http-basic /></http>" + AUTH_PROVIDER_XML);
@@ -416,6 +458,21 @@ public class HttpSecurityBeanDefinitionParserTests {
assertFalse(fsi.isObserveOncePerRequest());
}
@Test
public void httpBasicSupportsSeparateEntryPoint() throws Exception {
setContext("<http><http-basic entry-point-ref='ep' /></http>" +
"<b:bean id='ep' class='org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint'>" +
" <b:property name='realmName' value='whocares'/>" +
"</b:bean>" + AUTH_PROVIDER_XML);
BasicAuthenticationFilter baf = getFilter(BasicAuthenticationFilter.class);
assertSame(appContext.getBean("ep"), FieldUtils.getFieldValue(baf, "authenticationEntryPoint"));
// Since no other authentication system is in use, this should also end up on the ETF
ExceptionTranslationFilter etf = getFilter(ExceptionTranslationFilter.class);
assertSame(appContext.getBean("ep"), FieldUtils.getFieldValue(etf, "authenticationEntryPoint"));
}
@Test
public void accessDeniedPageAttributeIsSupported() throws Exception {
setContext("<http access-denied-page='/access-denied'><http-basic /></http>" + AUTH_PROVIDER_XML);
@@ -730,7 +787,7 @@ public class HttpSecurityBeanDefinitionParserTests {
"</http>" + AUTH_PROVIDER_XML);
List<Filter> filters = getFilters("/someurl");
assertTrue(filters.get(0) instanceof ConcurrentSessionFilter);
assertTrue(filters.get(1) instanceof ConcurrentSessionFilter);
assertNotNull(appContext.getBean("sr"));
SessionManagementFilter smf = getFilter(SessionManagementFilter.class);
assertNotNull(smf);
@@ -1218,6 +1275,18 @@ public class HttpSecurityBeanDefinitionParserTests {
fcp.doFilter(request, new MockHttpServletResponse(), new MockFilterChain());
}
@Test
public void httpFirewallInjectionIsSupported() throws Exception {
setContext(
"<http-firewall ref='fw'/>" +
"<http>" +
" <form-login />" +
"</http>" +
"<b:bean id='fw' class='" + DefaultHttpFirewall.class.getName() +"'/>" +
AUTH_PROVIDER_XML);
FilterChainProxy fcp = (FilterChainProxy) appContext.getBean(BeanIds.FILTER_CHAIN_PROXY);
assertSame(appContext.getBean("fw"), FieldUtils.getFieldValue(fcp, "firewall"));
}
private void setContext(String context) {
appContext = new InMemoryXmlApplicationContext(context);
@@ -16,12 +16,15 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractXmlApplicationContext;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.access.annotation.BusinessService;
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
import org.springframework.security.access.intercept.RunAsManagerImpl;
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
@@ -30,6 +33,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
import org.springframework.security.config.ConfigTestUtils;
import org.springframework.security.config.PostProcessedMockUserDetailsService;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
@@ -40,6 +44,8 @@ import org.springframework.security.util.FieldUtils;
* @author Luke Taylor
*/
public class GlobalMethodSecurityBeanDefinitionParserTests {
private final UsernamePasswordAuthenticationToken bob = new UsernamePasswordAuthenticationToken("bob","bobspassword");
private AbstractXmlApplicationContext appContext;
private BusinessService target;
@@ -166,7 +172,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
" 'execution(* org.springframework.security.access.annotation.BusinessService.*(..)) " +
" and not execution(* org.springframework.security.access.annotation.BusinessService.someOther(String)))' " +
" access='ROLE_USER'/>" +
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
"</global-method-security>" + AUTH_PROVIDER_XML
);
target = (BusinessService) appContext.getBean("target");
// String method should not be protected
@@ -231,7 +237,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
"<global-method-security pre-post-annotations='enabled'/>" +
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
AUTH_PROVIDER_XML);
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
SecurityContextHolder.getContext().setAuthentication(bob);
target = (BusinessService) appContext.getBean("target");
target.someAdminMethod();
}
@@ -242,7 +248,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
"<global-method-security pre-post-annotations='enabled'/>" +
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
AUTH_PROVIDER_XML);
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
SecurityContextHolder.getContext().setAuthentication(bob);
target = (BusinessService) appContext.getBean("target");
List<String> arg = new ArrayList<String>();
arg.add("joe");
@@ -261,7 +267,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
"<global-method-security pre-post-annotations='enabled'/>" +
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
AUTH_PROVIDER_XML);
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
SecurityContextHolder.getContext().setAuthentication(bob);
target = (BusinessService) appContext.getBean("target");
Object[] arg = new String[] {"joe", "bob", "sam"};
Object[] result = target.methodReturningAnArray(arg);
@@ -283,6 +289,33 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
AUTH_PROVIDER_XML);
}
// SEC-1450
@Test(expected=AuthenticationException.class)
@SuppressWarnings("unchecked")
public void genericsAreMatchedByProtectPointcut() throws Exception {
setContext(
"<b:bean id='target' class='org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParserTests$ConcreteFoo'/>" +
"<global-method-security>" +
" <protect-pointcut expression='execution(* org..*Foo.foo(..))' access='ROLE_USER'/>" +
"</global-method-security>" + AUTH_PROVIDER_XML
);
Foo foo = (Foo) appContext.getBean("target");
foo.foo(new SecurityConfig("A"));
}
// SEC-1448
@Test
@SuppressWarnings("unchecked")
public void genericsMethodArgumentNamesAreResolved() throws Exception {
setContext(
"<b:bean id='target' class='" + ConcreteFoo.class.getName() + "'/>" +
"<global-method-security pre-post-annotations='enabled'/>" + AUTH_PROVIDER_XML
);
SecurityContextHolder.getContext().setAuthentication(bob);
Foo foo = (Foo) appContext.getBean("target");
foo.foo(new SecurityConfig("A"));
}
@Test
public void runAsManagerIsSetCorrectly() throws Exception {
StaticApplicationContext parent = new StaticApplicationContext();
@@ -305,6 +338,15 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
private void setContext(String context, ApplicationContext parent) {
appContext = new InMemoryXmlApplicationContext(context, parent);
}
interface Foo<T extends ConfigAttribute> {
void foo(T action);
}
public static class ConcreteFoo implements Foo<SecurityConfig> {
@PreAuthorize("#action.attribute == 'A'")
public void foo(SecurityConfig action) {
}
}
}
@@ -25,6 +25,8 @@ public class InterceptMethodsBeanDefinitionDecoratorTests {
@Before
public void loadContext() {
// Set value for placeholder
System.setProperty("admin.role", "ROLE_ADMIN");
appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/method-security.xml");
target = (TestBusinessBean) appContext.getBean("target");
}
@@ -22,11 +22,11 @@ public class InMemoryXmlApplicationContext extends AbstractXmlApplicationContext
Resource inMemoryXml;
public InMemoryXmlApplicationContext(String xml) {
this(xml, "3.0", null);
this(xml, "3.0.4", null);
}
public InMemoryXmlApplicationContext(String xml, ApplicationContext parent) {
this(xml, "3.0", parent);
this(xml, "3.0.4", parent);
}
public InMemoryXmlApplicationContext(String xml, String secVersion, ApplicationContext parent) {
@@ -6,11 +6,13 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>
<b:bean id="target" class="org.springframework.security.config.TestBusinessBeanImpl">
<!-- This will add a security interceptor to the bean -->
<intercept-methods>
<protect method="org.springframework.security.config.TestBusinessBean.set*" access="ROLE_ADMIN" />
<protect method="get*" access="ROLE_ADMIN,ROLE_USER" />
<protect method="org.springframework.security.config.TestBusinessBean.set*" access="${admin.role}" />
<protect method="get*" access="${admin.role},ROLE_USER" />
<protect method="doSomething" access="ROLE_USER" />
</intercept-methods>
</b:bean>
+19 -15
View File
@@ -1,24 +1,28 @@
Implementation-Title: org.springframework.security.config
Implementation-Version: ${version}
Bundle-SymbolicName: org.springframework.security.config
Bundle-Name: Spring Security Namespace Configuration
Bundle-Vendor: SpringSource
Bundle-Version: ${version}
Bundle-ManifestVersion: 2
Ignored-Existing-Headers:
Ignored-Existing-Headers:
Import-Package,
Export-Package
Import-Template:
org.apache.commons.logging.*;version="[1.0.4, 2.0.0)",
org.aspectj.*;version="[1.6.0, 1.7.0)";resolution:=optional,
org.springframework.security.access.*;version="[${version}, 3.1.0)",
org.springframework.security.authentication.*;version="[${version}, 3.1.0)",
org.springframework.security.core.*;version="[${version}, 3.1.0)",
org.springframework.security.util;version="[${version}, 3.1.0)",
org.springframework.security.web.*;version="[${version}, 3.1.0)";resolution:=optional,
org.springframework.aop.*;version="[${spring.version}, 3.1.0)";resolution:=optional,
org.springframework.beans.*;version="[${spring.version}, 3.1.0)",
org.springframework.context.*;version="[${spring.version}, 3.1.0)",
org.springframework.core.*;version="[${spring.version}, 3.1.0)",
org.springframework.util.*;version="[${spring.version}, 3.1.0)",
javax.servlet;version="0";resolution:=optional,
Import-Template:
org.apache.commons.logging.*;version="${cloggingRange}",
org.aspectj.*;version="${aspectjRange}";resolution:=optional,
org.springframework.security.access.*;version="${secRange}",
org.springframework.security.authentication.*;version="${secRange}",
org.springframework.security.core.*;version="${secRange}",
org.springframework.security.util;version="${secRange}",
org.springframework.security.provisioning;version="${secRange}",
org.springframework.security.web.*;version="${secRange}";resolution:=optional,
org.springframework.aop.*;version="${springRange}";resolution:=optional,
org.springframework.beans.*;version="${springRange}",
org.springframework.context.*;version="${springRange}",
org.springframework.core.*;version="${springRange}",
org.springframework.web.*;version="${springRange}",
org.springframework.util.*;version="${springRange}",
javax.servlet.*;version="0";resolution:=optional,
javax.naming.directory;version="0";resolution:=optional,
org.w3c.dom;version="0";resolution:=optional
+5 -2
View File
@@ -5,7 +5,6 @@ dependencies {
"net.sf.ehcache:ehcache:$ehcacheVersion",
"org.springframework:spring-aop:$springVersion",
"org.springframework:spring-beans:$springVersion",
"org.springframework:spring-core:$springVersion",
"org.springframework:spring-context:$springVersion",
"org.springframework:spring-expression:$springVersion",
"org.springframework:spring-jdbc:$springVersion",
@@ -18,5 +17,9 @@ dependencies {
runtime 'hsqldb:hsqldb:1.8.0.10'
testCompile 'commons-collections:commons-collections:3.2',
"org.springframework:spring-test:$springVersion"
"org.springframework:spring-test:$springVersion",
"org.slf4j:jcl-over-slf4j:$slf4jVersion"
testRuntime "hsqldb:hsqldb:$hsqlVersion",
"cglib:cglib-nodep:$cglibVersion"
}
+1 -5
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-parent</artifactId>
<version>3.0.2.RELEASE</version>
<version>@pomVersion@</version>
</parent>
<packaging>jar</packaging>
<artifactId>spring-security-core</artifactId>
@@ -65,10 +65,6 @@
<artifactId>ehcache</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
@@ -37,6 +37,9 @@ public class Jsr250Voter implements AccessDecisionVoter {
/**
* Votes according to JSR 250.
* <p>
* If no JSR-250 attributes are found, it will abstain, otherwise it will grant or deny access
* based on the attributes that are found.
*
* @param authentication The authentication object.
* @param object The access object.
@@ -44,6 +47,8 @@ public class Jsr250Voter implements AccessDecisionVoter {
* @return The vote.
*/
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> definition) {
boolean jsr250AttributeFound = false;
for (ConfigAttribute attribute : definition) {
if (Jsr250SecurityConfig.PERMIT_ALL_ATTRIBUTE.equals(attribute)) {
return ACCESS_GRANTED;
@@ -54,18 +59,17 @@ public class Jsr250Voter implements AccessDecisionVoter {
}
if (supports(attribute)) {
jsr250AttributeFound = true;
// Attempt to find a matching granted authority
for (GrantedAuthority authority : authentication.getAuthorities()) {
if (attribute.getAttribute().equals(authority.getAuthority())) {
return ACCESS_GRANTED;
}
}
// No match - deny access
return ACCESS_DENIED;
}
}
return ACCESS_ABSTAIN;
return jsr250AttributeFound ? ACCESS_DENIED : ACCESS_ABSTAIN;
}
}
@@ -35,7 +35,7 @@ import org.springframework.security.access.method.AbstractFallbackMethodSecurity
public class SecuredAnnotationSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource {
protected Collection<ConfigAttribute> findAttributes(Class<?> clazz) {
return processAnnotation(clazz.getAnnotation(Secured.class));
return processAnnotation(AnnotationUtils.findAnnotation(clazz, Secured.class));
}
protected Collection<ConfigAttribute> findAttributes(Method method, Class<?> targetClass) {
@@ -36,6 +36,14 @@ public abstract class SecurityExpressionRoot {
this.authentication = a;
}
public final boolean hasAuthority(String authority) {
return hasRole(authority);
}
public final boolean hasAnyAuthority(String... authorities) {
return hasAnyRole(authorities);
}
public final boolean hasRole(String role) {
return getAuthoritySet().contains(role);
}
@@ -3,11 +3,13 @@ package org.springframework.security.access.expression.method;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.security.core.Authentication;
import org.springframework.util.ClassUtils;
/**
* Internal security-specific EvaluationContext implementation which lazily adds the
@@ -18,6 +20,8 @@ import org.springframework.util.ClassUtils;
* @since 3.0
*/
class MethodSecurityEvaluationContext extends StandardEvaluationContext {
private static Log logger = LogFactory.getLog(MethodSecurityEvaluationContext.class);
private ParameterNameDiscoverer parameterNameDiscoverer;
private boolean argumentsAdded;
private MethodInvocation mi;
@@ -58,10 +62,21 @@ class MethodSecurityEvaluationContext extends StandardEvaluationContext {
private void addArgumentsAsVariables() {
Object[] args = mi.getArguments();
if (args.length == 0) {
return;
}
Object targetObject = mi.getThis();
Method method = ClassUtils.getMostSpecificMethod(mi.getMethod(), targetObject.getClass());
Method method = AopUtils.getMostSpecificMethod(mi.getMethod(), targetObject.getClass());
String[] paramNames = parameterNameDiscoverer.getParameterNames(method);
if (paramNames == null) {
logger.warn("Unable to resolve method parameter names for method: " + method
+ ". Debug symbol information is required if you are using parameter names in expressions.");
return;
}
for(int i=0; i < args.length; i++) {
super.setVariable(paramNames[i], args[i]);
}
@@ -29,6 +29,7 @@ import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
/**
@@ -106,7 +107,7 @@ public class RoleHierarchyImpl implements RoleHierarchy {
public Collection<GrantedAuthority> getReachableGrantedAuthorities(Collection<GrantedAuthority> authorities) {
if (authorities == null || authorities.isEmpty()) {
return null;
return AuthorityUtils.NO_AUTHORITIES;
}
Set<GrantedAuthority> reachableRoles = new HashSet<GrantedAuthority>();
@@ -40,6 +40,7 @@ import org.springframework.security.authentication.AuthenticationCredentialsNotF
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.Assert;
@@ -224,16 +225,18 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
}
// no further work post-invocation
return new InterceptorStatusToken(authenticated, false, attributes, object);
return new InterceptorStatusToken(SecurityContextHolder.getContext(), false, attributes, object);
} else {
if (debug) {
logger.debug("Switching to RunAs Authentication: " + runAs);
}
SecurityContext origCtx = SecurityContextHolder.getContext();
SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());
SecurityContextHolder.getContext().setAuthentication(runAs);
// need to revert to token.Authenticated post-invocation
return new InterceptorStatusToken(authenticated, true, attributes, object);
return new InterceptorStatusToken(origCtx, true, attributes, object);
}
}
@@ -253,21 +256,22 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
if (token.isContextHolderRefreshRequired()) {
if (logger.isDebugEnabled()) {
logger.debug("Reverting to original Authentication: " + token.getAuthentication().toString());
logger.debug("Reverting to original Authentication: " + token.getSecurityContext().getAuthentication());
}
SecurityContextHolder.getContext().setAuthentication(token.getAuthentication());
SecurityContextHolder.setContext(token.getSecurityContext());
}
if (afterInvocationManager != null) {
// Attempt after invocation handling
try {
returnedObject = afterInvocationManager.decide(token.getAuthentication(), token.getSecureObject(),
returnedObject = afterInvocationManager.decide(token.getSecurityContext().getAuthentication(),
token.getSecureObject(),
token.getAttributes(), returnedObject);
}
catch (AccessDeniedException accessDeniedException) {
AuthorizationFailureEvent event = new AuthorizationFailureEvent(token.getSecureObject(), token
.getAttributes(), token.getAuthentication(), accessDeniedException);
.getAttributes(), token.getSecurityContext().getAuthentication(), accessDeniedException);
publishEvent(event);
throw accessDeniedException;
@@ -19,6 +19,7 @@ import java.util.Collection;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
/**
@@ -33,16 +34,16 @@ import org.springframework.security.core.Authentication;
public class InterceptorStatusToken {
//~ Instance fields ================================================================================================
private Authentication authentication;
private SecurityContext securityContext;
private Collection<ConfigAttribute> attr;
private Object secureObject;
private boolean contextHolderRefreshRequired;
//~ Constructors ===================================================================================================
public InterceptorStatusToken(Authentication authentication, boolean contextHolderRefreshRequired,
public InterceptorStatusToken(SecurityContext securityContext, boolean contextHolderRefreshRequired,
Collection<ConfigAttribute> attributes, Object secureObject) {
this.authentication = authentication;
this.securityContext = securityContext;
this.contextHolderRefreshRequired = contextHolderRefreshRequired;
this.attr = attributes;
this.secureObject = secureObject;
@@ -54,8 +55,8 @@ public class InterceptorStatusToken {
return attr;
}
public Authentication getAuthentication() {
return authentication;
public SecurityContext getSecurityContext() {
return securityContext;
}
public Object getSecureObject() {
@@ -73,7 +73,8 @@ public class RunAsUserToken extends AbstractAuthenticationToken {
public String toString() {
StringBuilder sb = new StringBuilder(super.toString());
sb.append("; Original Class: ").append(this.originalAuthentication.getName());
String className = this.originalAuthentication == null ? null : this.originalAuthentication.getName();
sb.append("; Original Class: ").append(className);
return sb.toString();
}
@@ -6,8 +6,9 @@ package org.springframework.security.access.intercept.aspectj;
* AspectJ processing to continue.
*
* @author Mike Wiesner
* @deprecated
*/
@Deprecated
public interface AspectJAnnotationCallback {
//~ Methods ========================================================================================================
@@ -11,7 +11,9 @@ import org.aspectj.lang.JoinPoint;
* AspectJ interceptor that supports @Aspect notation.
*
* @author Mike Wiesner
* @deprecated Use AspectJMethodSecurityInterceptor instead
*/
@Deprecated
public class AspectJAnnotationSecurityInterceptor extends AbstractSecurityInterceptor {
//~ Instance fields ================================================================================================
@@ -0,0 +1,51 @@
package org.springframework.security.access.intercept.aspectj;
import org.aspectj.lang.JoinPoint;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
/**
* AspectJ {@code JoinPoint} security interceptor which wraps the {@code JoinPoint} in a {@code MethodInvocation}
* adapter to make it compatible with security infrastructure classes which only support {@code MethodInvocation}s.
* <p>
* One of the {@code invoke} methods should be called from the {@code around()} advice in your aspect.
* Alternatively you can use one of the pre-defined aspects from the aspects module.
*
* @author Luke Taylor
* @since 3.0.3
*/
public final class AspectJMethodSecurityInterceptor extends MethodSecurityInterceptor {
/**
* Method that is suitable for user with @Aspect notation.
*
* @param jp The AspectJ joint point being invoked which requires a security decision
* @return The returned value from the method invocation
* @throws Throwable if the invocation throws one
*/
public Object invoke(JoinPoint jp) throws Throwable {
return super.invoke(new MethodInvocationAdapter(jp));
}
/**
* Method that is suitable for user with traditional AspectJ-code aspects.
*
* @param jp The AspectJ joint point being invoked which requires a security decision
* @param advisorProceed the advice-defined anonymous class that implements {@code AspectJCallback} containing
* a simple {@code return proceed();} statement
*
* @return The returned value from the method invocation
*/
public Object invoke(JoinPoint jp, AspectJCallback advisorProceed) {
Object result = null;
InterceptorStatusToken token = super.beforeInvocation(new MethodInvocationAdapter(jp));
try {
result = advisorProceed.proceedWithObject();
} finally {
result = super.afterInvocation(token, result);
}
return result;
}
}
@@ -37,7 +37,9 @@ import org.aspectj.lang.JoinPoint;
* Refer to {@link AbstractSecurityInterceptor} for details on the workflow.
*
* @author Ben Alex
* @deprecated Use AspectJMethodSecurityInterceptor instead
*/
@Deprecated
public class AspectJSecurityInterceptor extends AbstractSecurityInterceptor {
//~ Instance fields ================================================================================================
@@ -0,0 +1,61 @@
package org.springframework.security.access.intercept.aspectj;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.CodeSignature;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Decorates a JoinPoint to allow it to be used with method-security infrastructure
* classes which support {@code MethodInvocation} instances.
*
* @author Luke Taylor
* @since 3.0.3
*/
public final class MethodInvocationAdapter implements MethodInvocation {
private final ProceedingJoinPoint jp;
private final Method method;
private final Object target;
MethodInvocationAdapter(JoinPoint jp) {
this.jp = (ProceedingJoinPoint)jp;
if (jp.getTarget() != null) {
target = jp.getTarget();
} else {
// SEC-1295: target may be null if an ITD is in use
target = jp.getSignature().getDeclaringType();
}
String targetMethodName = jp.getStaticPart().getSignature().getName();
Class<?>[] types = ((CodeSignature) jp.getStaticPart().getSignature()).getParameterTypes();
Class<?> declaringType = ((CodeSignature) jp.getStaticPart().getSignature()).getDeclaringType();
method = ClassUtils.getMethodIfAvailable(declaringType, targetMethodName, types);
Assert.notNull(method, "Could not obtain target method from JoinPoint: '"+ jp + "'");
}
public Method getMethod() {
return method;
}
public Object[] getArguments() {
return jp.getArgs();
}
public AccessibleObject getStaticPart() {
return method;
}
public Object getThis() {
return target;
}
public Object proceed() throws Throwable {
return jp.proceed();
}
}
@@ -3,8 +3,8 @@ package org.springframework.security.access.method;
import java.lang.reflect.Method;
import java.util.Collection;
import org.springframework.aop.support.AopUtils;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.util.ClassUtils;
/**
* Abstract implementation of {@link MethodSecurityMetadataSource} that supports both Spring AOP and AspectJ and
@@ -29,7 +29,7 @@ public abstract class AbstractFallbackMethodSecurityMetadataSource extends Abstr
public Collection<ConfigAttribute> getAttributes(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);
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// First try is the method in the target class.
Collection<ConfigAttribute> attr = findAttributes(specificMethod, targetClass);
if (attr != null) {
@@ -15,6 +15,7 @@
package org.springframework.security.access.method;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.security.access.ConfigAttribute;
import org.aopalliance.intercept.MethodInvocation;
@@ -49,7 +50,18 @@ public abstract class AbstractMethodSecurityMetadataSource implements MethodSecu
if (object instanceof MethodInvocation) {
MethodInvocation mi = (MethodInvocation) object;
Object target = mi.getThis();
return getAttributes(mi.getMethod(), target == null ? null : target.getClass());
Class<?> targetClass = null;
if (target != null) {
targetClass = target instanceof Class<?> ? (Class<?>)target : AopProxyUtils.ultimateTargetClass(target);
if (targetClass == null) {
// See SPR-7447. TODO: Only required for Spring < 3.0.4
targetClass = target.getClass();
}
}
return getAttributes(mi.getMethod(), targetClass);
}
if (object instanceof JoinPoint) {
@@ -88,6 +88,10 @@ public final class DelegatingMethodSecurityMetadataSource extends AbstractMethod
this.methodSecurityMetadataSources = methodSecurityMetadataSources;
}
public List<MethodSecurityMetadataSource> getMethodSecurityMetadataSources() {
return methodSecurityMetadataSources;
}
//~ Inner Classes ==================================================================================================
private static class DefaultCacheKey {
@@ -25,6 +25,7 @@ import java.util.Map;
import java.util.Set;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -42,7 +43,8 @@ import org.springframework.util.ClassUtils;
* @author Ben Alex
* @since 2.0
*/
public class MapBasedMethodSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource implements BeanClassLoaderAware {
public class MapBasedMethodSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource
implements BeanClassLoaderAware {
//~ Instance fields ================================================================================================
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
@@ -103,7 +105,7 @@ public class MapBasedMethodSecurityMetadataSource extends AbstractFallbackMethod
* for matching multiple methods.
*
* @param name type and method name, separated by a dot
* @param attr required authorities associated with the method
* @param attr the security attributes associated with the method
*/
private void addSecureMethod(String name, List<ConfigAttribute> attr) {
int lastDotIndex = name.lastIndexOf(".");
@@ -175,7 +177,9 @@ public class MapBasedMethodSecurityMetadataSource extends AbstractFallbackMethod
* 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
* it will not override a more specific one which has already been added.
* <p>
* This method should only be called during initialization of the {@code BeanFactory}.
*/
public void addSecureMethod(Class<?> javaType, Method method, List<ConfigAttribute> attr) {
RegisteredMethod key = new RegisteredMethod(method, javaType);
@@ -35,7 +35,7 @@ public class PreInvocationAuthorizationAdviceVoter implements AccessDecisionVote
}
public boolean supports(Class<?> clazz) {
return clazz.isAssignableFrom(MethodInvocation.class);
return MethodInvocation.class.isAssignableFrom(clazz);
}
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
@@ -105,23 +105,13 @@ public class PrePostAnnotationSecurityMetadataSource extends AbstractMethodSecur
}
// Check the class-level (note declaringClass, not targetClass, which may not actually implement the method)
annotation = specificMethod.getDeclaringClass().getAnnotation(annotationClass);
annotation = AnnotationUtils.findAnnotation(specificMethod.getDeclaringClass(), annotationClass);
if (annotation != null) {
logger.debug(annotation + " found on: " + specificMethod.getDeclaringClass().getName());
return annotation;
}
// Check for a possible interface annotation which would not be inherited by the declaring class
if (specificMethod != method) {
annotation = method.getDeclaringClass().getAnnotation(annotationClass);
if (annotation != null) {
logger.debug(annotation + " found on: " + method.getDeclaringClass().getName());
return annotation;
}
}
return null;
}
@@ -36,11 +36,6 @@ public class InterfaceBasedLabelParameterStrategy implements LabelParameterStrat
* Test if the argument is labeled, and if so, downcast to LabeledData and retrieve the domain object's
* labeled value. Otherwise, return an empty string. NOTE: The default for no label is an empty string. If somehow
* the user wants to make that a label itself, he or she must inject an alternate value to the noLabel property.
*
* @param method DOCUMENT ME!
* @param arg DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public String getLabel(Method method, Object arg) {
if (isLabeled(method, arg)) {
@@ -57,11 +52,6 @@ public class InterfaceBasedLabelParameterStrategy implements LabelParameterStrat
/**
* Test if the argument implemented the LabeledData interface. NOTE: The invoking method has no bearing for
* this strategy, only the argument itself.
*
* @param method DOCUMENT ME!
* @param arg DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public boolean isLabeled(Method method, Object arg) {
return (arg instanceof LabeledData);
@@ -77,7 +77,9 @@ public abstract class AbstractAuthenticationManager implements AuthenticationMan
* be serialized to the client. Defaults to 'false'.
*
* @see org.springframework.security.core.AuthenticationException#getExtraInformation()
* @deprecated the {@code extraInformation} property is deprecated
*/
@Deprecated
public void setClearExtraInformation(boolean clearExtraInformation) {
this.clearExtraInformation = clearExtraInformation;
}
@@ -22,6 +22,7 @@ import java.util.Collections;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.CredentialsContainer;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
@@ -34,7 +35,7 @@ import org.springframework.security.core.userdetails.UserDetails;
* @author Ben Alex
* @author Luke Taylor
*/
public abstract class AbstractAuthenticationToken implements Authentication {
public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer {
//~ Instance fields ================================================================================================
private Object details;
@@ -49,7 +50,7 @@ public abstract class AbstractAuthenticationToken implements Authentication {
* @param authorities the collection of <tt>GrantedAuthority</tt>s for the
* principal represented by this authentication object.
*/
public AbstractAuthenticationToken(Collection<GrantedAuthority> authorities) {
public AbstractAuthenticationToken(Collection<? extends GrantedAuthority> authorities) {
if (authorities == null) {
this.authorities = AuthorityUtils.NO_AUTHORITIES;
return;
@@ -67,6 +68,55 @@ public abstract class AbstractAuthenticationToken implements Authentication {
//~ Methods ========================================================================================================
public Collection<GrantedAuthority> getAuthorities() {
return authorities;
}
public String getName() {
if (this.getPrincipal() instanceof UserDetails) {
return ((UserDetails) this.getPrincipal()).getUsername();
}
if (getPrincipal() instanceof Principal) {
return ((Principal)getPrincipal()).getName();
}
return (this.getPrincipal() == null) ? "" : this.getPrincipal().toString();
}
public boolean isAuthenticated() {
return authenticated;
}
public void setAuthenticated(boolean authenticated) {
this.authenticated = authenticated;
}
public Object getDetails() {
return details;
}
public void setDetails(Object details) {
this.details = details;
}
/**
* Checks the {@code credentials}, {@code principal} and {@code details} objects, invoking the
* {@code eraseCredentials} method on any which implement {@link CredentialsContainer}.
*/
public void eraseCredentials() {
eraseSecret(getCredentials());
eraseSecret(getPrincipal());
eraseSecret(details);
}
private void eraseSecret(Object secret) {
if (secret instanceof CredentialsContainer) {
((CredentialsContainer)secret).eraseCredentials();
}
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof AbstractAuthenticationToken)) {
return false;
@@ -109,26 +159,7 @@ public abstract class AbstractAuthenticationToken implements Authentication {
return this.isAuthenticated() == test.isAuthenticated();
}
public Collection<GrantedAuthority> getAuthorities() {
return authorities;
}
public Object getDetails() {
return details;
}
public String getName() {
if (this.getPrincipal() instanceof UserDetails) {
return ((UserDetails) this.getPrincipal()).getUsername();
}
if (getPrincipal() instanceof Principal) {
return ((Principal)getPrincipal()).getName();
}
return (this.getPrincipal() == null) ? "" : this.getPrincipal().toString();
}
@Override
public int hashCode() {
int code = 31;
@@ -155,23 +186,12 @@ public abstract class AbstractAuthenticationToken implements Authentication {
return code;
}
public boolean isAuthenticated() {
return authenticated;
}
public void setAuthenticated(boolean authenticated) {
this.authenticated = authenticated;
}
public void setDetails(Object details) {
this.details = details;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(super.toString()).append(": ");
sb.append("Principal: ").append(this.getPrincipal()).append("; ");
sb.append("Password: [PROTECTED]; ");
sb.append("Credentials: [PROTECTED]; ");
sb.append("Authenticated: ").append(this.isAuthenticated()).append("; ");
sb.append("Details: ").append(this.getDetails()).append("; ");
@@ -17,6 +17,7 @@ public abstract class AccountStatusException extends AuthenticationException {
super(msg, t);
}
@Deprecated
protected AccountStatusException(String msg, Object extraInformation) {
super(msg, extraInformation);
}
@@ -14,20 +14,20 @@ public class AccountStatusUserDetailsChecker implements UserDetailsChecker {
public void check(UserDetails user) {
if (!user.isAccountNonLocked()) {
throw new LockedException(messages.getMessage("UserDetailsService.locked", "User account is locked"), user);
throw new LockedException(messages.getMessage("AccountStatusUserDetailsChecker.locked", "User account is locked"), user);
}
if (!user.isEnabled()) {
throw new DisabledException(messages.getMessage("UserDetailsService.disabled", "User is disabled"), user);
throw new DisabledException(messages.getMessage("AccountStatusUserDetailsChecker.disabled", "User is disabled"), user);
}
if (!user.isAccountNonExpired()) {
throw new AccountExpiredException(messages.getMessage("UserDetailsService.expired",
throw new AccountExpiredException(messages.getMessage("AccountStatusUserDetailsChecker.expired",
"User account has expired"), user);
}
if (!user.isCredentialsNonExpired()) {
throw new CredentialsExpiredException(messages.getMessage("UserDetailsService.credentialsExpired",
throw new CredentialsExpiredException(messages.getMessage("AccountStatusUserDetailsChecker.credentialsExpired",
"User credentials have expired"), user);
}
}
@@ -57,7 +57,7 @@ public interface AuthenticationProvider {
* <p>Selection of an <code>AuthenticationProvider</code> capable of performing authentication is
* conducted at runtime the <code>ProviderManager</code>.</p>
*
* @param authentication DOCUMENT ME!
* @param authentication
*
* @return <code>true</code> if the implementation can more closely evaluate the <code>Authentication</code> class
* presented
@@ -36,6 +36,7 @@ public class BadCredentialsException extends AuthenticationException {
super(msg);
}
@Deprecated
public BadCredentialsException(String msg, Object extraInformation) {
super(msg, extraInformation);
}
@@ -26,6 +26,7 @@ import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.CredentialsContainer;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.util.Assert;
@@ -42,10 +43,17 @@ import org.springframework.util.Assert;
* <code>AuthenticationException</code>, the last <code>AuthenticationException</code> received will be used.
* If no provider returns a non-null response, or indicates it can even process an <code>Authentication</code>,
* the <code>ProviderManager</code> will throw a <code>ProviderNotFoundException</code>.
* A parent {@code AuthenticationManager} can also be set, and this will also be tried if none of the configured
* providers can perform the authentication. This is intended to support namespace configuration options though and
* is not a feature that should normally be required.
* <p>
* The exception to this process is when a provider throws an {@link AccountStatusException}, in which case no
* further providers in the list will be queried.
*
* Post-authentication, the credentials will be cleared from the returned {@code Authentication} object, if it
* implements the {@link CredentialsContainer} interface. This behaviour can be controlled by modifying the
* {@link #setEraseCredentialsAfterAuthentication(boolean) eraseCredentialsAfterAuthentication} property.
*
* <h2>Event Publishing</h2>
* <p>
* Authentication event publishing is delegated to the configured {@link AuthenticationEventPublisher} which defaults
@@ -57,9 +65,10 @@ import org.springframework.util.Assert;
* the <tt>&lt;http&gt;</tt> configuration, so you will receive events from the web part of your application automatically.
* <p>
* Note that the implementation also publishes authentication failure events when it obtains an authentication result
* (or an exception) from the "parent" <tt>AuthenticationManager</tt> if one has been set. So in this situation, the
* (or an exception) from the "parent" {@code AuthenticationManager} if one has been set. So in this situation, the
* parent should not generally be configured to publish events or there will be duplicates.
*
*
* @author Ben Alex
* @author Luke Taylor
*
@@ -76,6 +85,7 @@ public class ProviderManager extends AbstractAuthenticationManager implements Me
private List<AuthenticationProvider> providers = Collections.emptyList();
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
private AuthenticationManager parent;
private boolean eraseCredentialsAfterAuthentication = false;
//~ Methods ========================================================================================================
@@ -145,6 +155,11 @@ public class ProviderManager extends AbstractAuthenticationManager implements Me
}
if (result != null) {
if (eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) {
// Authentication is complete. Remove credentials and other secret data from authentication
((CredentialsContainer)result).eraseCredentials();
}
eventPublisher.publishAuthenticationSuccess(result);
return result;
}
@@ -193,6 +208,22 @@ public class ProviderManager extends AbstractAuthenticationManager implements Me
this.eventPublisher = eventPublisher;
}
/**
* If set to, a resulting {@code Authentication} which implements the {@code CredentialsContainer} interface
* will have its {@link CredentialsContainer#eraseCredentials() eraseCredentials} method called before it is returned
* from the {@code authenticate()} method.
*
* @param eraseSecretData set to {@literal false} to retain the credentials data in memory.
* Defaults to {@literal true}.
*/
public void setEraseCredentialsAfterAuthentication(boolean eraseSecretData) {
this.eraseCredentialsAfterAuthentication = eraseSecretData;
}
public boolean isEraseCredentialsAfterAuthentication() {
return eraseCredentialsAfterAuthentication;
}
/**
* Sets the {@link AuthenticationProvider} objects to be used for authentication.
*
@@ -15,7 +15,6 @@
package org.springframework.security.authentication;
import java.io.Serializable;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
@@ -28,8 +27,9 @@ import org.springframework.security.core.GrantedAuthority;
* <code>GrantedAuthority</code>s that apply.
*
* @author Ben Alex
* @author Luke Taylor
*/
public class RememberMeAuthenticationToken extends AbstractAuthenticationToken implements Serializable {
public class RememberMeAuthenticationToken extends AbstractAuthenticationToken {
//~ Instance fields ================================================================================================
private final Object principal;
@@ -46,7 +46,7 @@ public class RememberMeAuthenticationToken extends AbstractAuthenticationToken i
*
* @throws IllegalArgumentException if a <code>null</code> was passed
*/
public RememberMeAuthenticationToken(String key, Object principal, Collection<GrantedAuthority> authorities) {
public RememberMeAuthenticationToken(String key, Object principal, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
if ((key == null) || ("".equals(key)) || (principal == null) || "".equals(principal)) {
@@ -60,6 +60,23 @@ public class RememberMeAuthenticationToken extends AbstractAuthenticationToken i
//~ Methods ========================================================================================================
/**
* Always returns an empty <code>String</code>
*
* @return an empty String
*/
public Object getCredentials() {
return "";
}
public int getKeyHash() {
return this.keyHash;
}
public Object getPrincipal() {
return this.principal;
}
public boolean equals(Object obj) {
if (!super.equals(obj)) {
return false;
@@ -78,20 +95,4 @@ public class RememberMeAuthenticationToken extends AbstractAuthenticationToken i
return false;
}
/**
* Always returns an empty <code>String</code>
*
* @return an empty String
*/
public Object getCredentials() {
return "";
}
public int getKeyHash() {
return this.keyHash;
}
public Object getPrincipal() {
return this.principal;
}
}

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