1
0
mirror of synced 2026-09-06 09:20:07 +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
855 changed files with 20671 additions and 20787 deletions
+5 -1
View File
@@ -1,4 +1,7 @@
target/
*/src/*/java/META-INF
*/src/META-INF/
*/src/*/java/META-INF/
.classpath
.springBeans
.project
@@ -6,12 +9,13 @@ target/
.settings/
.idea/
out/
bin/
intellij/
build/
*.log
*.log.*
*.iml
*.ipr
*.iws
.gradle/
gradle.properties
atlassian-ide-plugin.xml
-3
View File
@@ -2,7 +2,6 @@
dependencies {
compile project(':spring-security-core'),
'aopalliance:aopalliance:1.0',
"net.sf.ehcache:ehcache:$ehcacheVersion",
"org.springframework:spring-aop:$springVersion",
"org.springframework:spring-context:$springVersion",
@@ -12,6 +11,4 @@ dependencies {
testCompile "org.springframework:spring-beans:$springVersion",
"org.springframework:spring-context-support:$springVersion",
"org.springframework:spring-test:$springVersion"
testRuntime "hsqldb:hsqldb:$hsqlVersion"
}
+68
View File
@@ -0,0 +1,68 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>spring-security-parent</artifactId>
<groupId>org.springframework.security</groupId>
<version>@pomVersion@</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-acl</artifactId>
<name>Spring Security - ACL module</name>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${project.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>8.3-603.jdbc3</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -20,7 +20,6 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.AuthorizationServiceException;
@@ -146,10 +145,14 @@ public class AclEntryVoter extends AbstractAclVoter {
}
public boolean supports(ConfigAttribute attribute) {
return (attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute());
if ((attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute())) {
return true;
} else {
return false;
}
}
public int vote(Authentication authentication, MethodInvocation object, Collection<ConfigAttribute> attributes) {
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
for(ConfigAttribute attr : attributes) {
@@ -174,7 +177,7 @@ public class AclEntryVoter extends AbstractAclVoter {
try {
Class<?> clazz = domainObject.getClass();
Method method = clazz.getMethod(internalMethod, new Class[0]);
domainObject = method.invoke(domainObject);
domainObject = method.invoke(domainObject, new Object[0]);
} catch (NoSuchMethodException nsme) {
throw new AuthorizationServiceException("Object of class '" + domainObject.getClass()
+ "' does not provide the requested internalMethod: " + internalMethod);
@@ -1,66 +0,0 @@
package org.springframework.security.acls;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.PermissionCacheOptimizer;
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
import org.springframework.security.acls.domain.SidRetrievalStrategyImpl;
import org.springframework.security.acls.model.AclService;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy;
import org.springframework.security.acls.model.Sid;
import org.springframework.security.acls.model.SidRetrievalStrategy;
import org.springframework.security.core.Authentication;
/**
* Batch loads ACLs for collections of objects to allow optimised filtering.
*
* @author Luke Taylor
* @since 3.1
*/
public class AclPermissionCacheOptimizer implements PermissionCacheOptimizer {
private final Log logger = LogFactory.getLog(getClass());
private final AclService aclService;
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
private ObjectIdentityRetrievalStrategy oidRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
public AclPermissionCacheOptimizer(AclService aclService) {
this.aclService = aclService;
}
public void cachePermissionsFor(Authentication authentication, Collection<?> objects) {
if (objects.isEmpty()) {
return;
}
List<ObjectIdentity> oidsToCache = new ArrayList<ObjectIdentity>(objects.size());
for (Object domainObject : objects) {
if (domainObject == null) {
continue;
}
ObjectIdentity oid = oidRetrievalStrategy.getObjectIdentity(domainObject);
oidsToCache.add(oid);
}
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
if (logger.isDebugEnabled()) {
logger.debug("Eagerly loading Acls for " + oidsToCache.size() + " objects");
}
aclService.readAclsById(oidsToCache, sids);
}
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
this.oidRetrievalStrategy = objectIdentityRetrievalStrategy;
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
}
@@ -34,7 +34,7 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
private final Log logger = LogFactory.getLog(getClass());
private final AclService aclService;
private AclService aclService;
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
private ObjectIdentityGenerator objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
@@ -70,30 +70,24 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
List<Permission> requiredPermission = resolvePermission(permission);
final boolean debug = logger.isDebugEnabled();
if (debug) {
logger.debug("Checking permission '" + permission + "' for object '" + oid + "'");
}
try {
// Lookup only ACLs for SIDs we're interested in
Acl acl = aclService.readAclById(oid, sids);
if (acl.isGranted(requiredPermission, sids, false)) {
if (debug) {
if (logger.isDebugEnabled()) {
logger.debug("Access is granted");
}
return true;
}
if (debug) {
if (logger.isDebugEnabled()) {
logger.debug("Returning false - ACLs returned, but insufficient permissions for this principal");
}
} catch (NotFoundException nfe) {
if (debug) {
if (logger.isDebugEnabled()) {
logger.debug("Returning false - no ACLs apply for this principal");
}
}
@@ -117,7 +111,7 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
if (permission instanceof String) {
String permString = (String)permission;
Permission p;
Permission p = null;
try {
p = permissionFactory.buildFromName(permString);
@@ -43,12 +43,12 @@ import org.springframework.util.Assert;
public abstract class AbstractAclProvider implements AfterInvocationProvider {
//~ Instance fields ================================================================================================
protected final AclService aclService;
protected AclService aclService;
protected Class<?> processDomainObjectClass = Object.class;
protected ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
protected SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
protected String processConfigAttribute;
protected final List<Permission> requirePermission;
protected List<Permission> requirePermission = Arrays.asList(BasePermission.READ);
//~ Constructors ===================================================================================================
@@ -78,9 +78,11 @@ public abstract class AbstractAclProvider implements AfterInvocationProvider {
// Obtain the SIDs applicable to the principal
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
Acl acl = null;
try {
// Lookup only ACLs for SIDs we're interested in
Acl acl = aclService.readAclById(objectIdentity, sids);
acl = aclService.readAclById(objectIdentity, sids);
return acl.isGranted(requirePermission, sids, false);
} catch (NotFoundException ignore) {
@@ -75,7 +75,9 @@ public class AclEntryAfterInvocationCollectionFilteringProvider extends Abstract
Object returnedObject) throws AccessDeniedException {
if (returnedObject == null) {
logger.debug("Return object is null, skipping");
if (logger.isDebugEnabled()) {
logger.debug("Return object is null, skipping");
}
return null;
}
@@ -65,7 +65,7 @@ public class AclEntryAfterInvocationProvider extends AbstractAclProvider impleme
//~ Constructors ===================================================================================================
public AclEntryAfterInvocationProvider(AclService aclService, List<Permission> requirePermission) {
this(aclService, "AFTER_ACL_READ", requirePermission);
super(aclService, "AFTER_ACL_READ", requirePermission);
}
public AclEntryAfterInvocationProvider(AclService aclService, String processConfigAttribute,
@@ -81,13 +81,17 @@ public class AclEntryAfterInvocationProvider extends AbstractAclProvider impleme
if (returnedObject == null) {
// AclManager interface contract prohibits nulls
// As they have permission to null/nothing, grant access
logger.debug("Return object is null, skipping");
if (logger.isDebugEnabled()) {
logger.debug("Return object is null, skipping");
}
return null;
}
if (!getProcessDomainObjectClass().isAssignableFrom(returnedObject.getClass())) {
logger.debug("Return object is not applicable for this provider, skipping");
if (logger.isDebugEnabled()) {
logger.debug("Return object is not applicable for this provider, skipping");
}
return returnedObject;
}
@@ -104,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}"));
}
@@ -95,7 +95,7 @@ class ArrayFilterer<T> implements Filterer<T> {
}
public T next() {
if (!hasNext()) {
if (hasNext() == false) {
throw new NoSuchElementException();
}
return list[index++];
@@ -37,9 +37,12 @@ class CollectionFilterer<T> implements Filterer<T> {
//~ Instance fields ================================================================================================
private final Collection<T> collection;
private Collection<T> collection;
private final Set<T> removeList;
// collectionIter offers significant performance optimisations (as
// per security-developer mailing list conversation 19/5/05)
private Iterator<T> collectionIter;
private Set<T> removeList;
//~ Constructors ===================================================================================================
@@ -85,7 +88,9 @@ class CollectionFilterer<T> implements Filterer<T> {
* @see org.springframework.security.acls.afterinvocation.Filterer#iterator()
*/
public Iterator<T> iterator() {
return collection.iterator();
collectionIter = collection.iterator();
return collectionIter;
}
/**
@@ -12,7 +12,7 @@ public abstract class AbstractPermission implements Permission {
//~ Instance fields ================================================================================================
protected final char code;
protected char code;
protected int mask;
//~ Constructors ===================================================================================================
@@ -33,13 +33,13 @@ import java.io.Serializable;
public class AccessControlEntryImpl implements AccessControlEntry, AuditableAccessControlEntry {
//~ Instance fields ================================================================================================
private final Acl acl;
private Acl acl;
private Permission permission;
private final Serializable id;
private final Sid sid;
private Serializable id;
private Sid sid;
private boolean auditFailure = false;
private boolean auditSuccess = false;
private final boolean granting;
private boolean granting;
//~ Constructors ===================================================================================================
@@ -41,9 +41,9 @@ import org.springframework.util.Assert;
public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
//~ Instance fields ================================================================================================
private final GrantedAuthority gaGeneralChanges;
private final GrantedAuthority gaModifyAuditing;
private final GrantedAuthority gaTakeOwnership;
private GrantedAuthority gaGeneralChanges;
private GrantedAuthority gaModifyAuditing;
private GrantedAuthority gaTakeOwnership;
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
//~ Constructors ===================================================================================================
@@ -52,23 +52,16 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
* Constructor. The only mandatory parameter relates to the system-wide {@link GrantedAuthority} instances that
* can be held to always permit ACL changes.
*
* @param auths the <code>GrantedAuthority</code>s that have
* @param auths an array of <code>GrantedAuthority</code>s that have
* special permissions (index 0 is the authority needed to change
* ownership, index 1 is the authority needed to modify auditing details,
* index 2 is the authority needed to change other ACL and ACE details) (required)
* <p>
* Alternatively, a single value can be supplied for all three permissions.
*/
public AclAuthorizationStrategyImpl(GrantedAuthority... auths) {
Assert.isTrue(auths != null && (auths.length == 3 || auths.length == 1),
"One or three GrantedAuthority instances required");
if (auths.length == 3) {
gaTakeOwnership = auths[0];
gaModifyAuditing = auths[1];
gaGeneralChanges = auths[2];
} else {
gaTakeOwnership = gaModifyAuditing = gaGeneralChanges = auths[0];
}
public AclAuthorizationStrategyImpl(GrantedAuthority[] auths) {
Assert.isTrue(auths != null && auths.length == 3, "GrantedAuthority[] with three elements required");
this.gaTakeOwnership = auths[0];
this.gaModifyAuditing = auths[1];
this.gaGeneralChanges = auths[2];
}
//~ Methods ========================================================================================================
@@ -91,7 +84,7 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
}
// Not authorized by ACL ownership; try via adminstrative permissions
GrantedAuthority requiredAuthority;
GrantedAuthority requiredAuthority = null;
if (changeType == CHANGE_AUDITING) {
requiredAuthority = this.gaModifyAuditing;
@@ -26,7 +26,6 @@ import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.OwnershipAcl;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.PermissionGrantingStrategy;
import org.springframework.security.acls.model.Sid;
import org.springframework.security.acls.model.UnloadedSidException;
import org.springframework.util.Assert;
@@ -42,8 +41,8 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
private Acl parentAcl;
private transient AclAuthorizationStrategy aclAuthorizationStrategy;
private transient PermissionGrantingStrategy permissionGrantingStrategy;
private final List<AccessControlEntry> aces = new ArrayList<AccessControlEntry>();
private transient AuditLogger auditLogger;
private List<AccessControlEntry> aces = new ArrayList<AccessControlEntry>();
private ObjectIdentity objectIdentity;
private Serializable id;
private Sid owner; // OwnershipAcl
@@ -70,48 +69,39 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
this.objectIdentity = objectIdentity;
this.id = id;
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
this.permissionGrantingStrategy = new DefaultPermissionGrantingStrategy(auditLogger);
}
/**
* @deprecated Use the version which takes a {@code PermissionGrantingStrategy} argument instead.
*/
@Deprecated
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
AuditLogger auditLogger, Acl parentAcl, List<Sid> loadedSids, boolean entriesInheriting, Sid owner) {
this(objectIdentity, id, aclAuthorizationStrategy, new DefaultPermissionGrantingStrategy(auditLogger),
parentAcl, loadedSids, entriesInheriting, owner);
this.auditLogger = auditLogger;
}
/**
* Full constructor, which should be used by persistence tools that do not
* provide field-level access features.
*
* @param objectIdentity the object identity this ACL relates to
* @param id the primary key assigned to this ACL
* @param aclAuthorizationStrategy authorization strategy
* @param grantingStrategy the {@code PermissionGrantingStrategy} which will be used by the {@code isGranted()} method
* @param parentAcl the parent (may be may be {@code null})
* @param loadedSids the loaded SIDs if only a subset were loaded (may be {@code null})
* @param objectIdentity the object identity this ACL relates to (required)
* @param id the primary key assigned to this ACL (required)
* @param aclAuthorizationStrategy authorization strategy (required)
* @param auditLogger audit logger (required)
* @param parentAcl the parent (may be <code>null</code>)
* @param loadedSids the loaded SIDs if only a subset were loaded (may be
* <code>null</code>)
* @param entriesInheriting if ACEs from the parent should inherit into
* this ACL
* @param owner the owner (required)
*/
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
PermissionGrantingStrategy grantingStrategy, Acl parentAcl, List<Sid> loadedSids, boolean entriesInheriting, Sid owner) {
AuditLogger auditLogger, Acl parentAcl, List<Sid> loadedSids, boolean entriesInheriting, Sid owner) {
Assert.notNull(objectIdentity, "Object Identity required");
Assert.notNull(id, "Id required");
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
Assert.notNull(owner, "Owner required");
Assert.notNull(auditLogger, "AuditLogger required");
this.objectIdentity = objectIdentity;
this.id = id;
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
this.auditLogger = auditLogger;
this.parentAcl = parentAcl; // may be null
this.loadedSids = loadedSids; // may be null
this.entriesInheriting = entriesInheriting;
this.owner = owner;
this.permissionGrantingStrategy = grantingStrategy;
}
/**
@@ -178,11 +168,35 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
}
/**
* Delegates to the {@link PermissionGrantingStrategy}.
* Determines authorization. The order of the <code>permission</code> and <code>sid</code> arguments is
* <em>extremely important</em>! The method will iterate through each of the <code>permission</code>s in the order
* specified. For each iteration, all of the <code>sid</code>s will be considered, again in the order they are
* presented. A search will then be performed for the first {@link AccessControlEntry} object that directly
* matches that <code>permission:sid</code> combination. When the <em>first full match</em> is found (ie an ACE
* that has the SID currently being searched for and the exact permission bit mask being search for), the grant or
* deny flag for that ACE will prevail. If the ACE specifies to grant access, the method will return
* <code>true</code>. If the ACE specifies to deny access, the loop will stop and the next <code>permission</code>
* iteration will be performed. If each permission indicates to deny access, the first deny ACE found will be
* considered the reason for the failure (as it was the first match found, and is therefore the one most logically
* requiring changes - although not always). If absolutely no matching ACE was found at all for any permission,
* the parent ACL will be tried (provided that there is a parent and {@link #isEntriesInheriting()} is
* <code>true</code>. The parent ACL will also scan its parent and so on. If ultimately no matching ACE is found,
* a <code>NotFoundException</code> will be thrown and the caller will need to decide how to handle the permission
* check. Similarly, if any of the SID arguments presented to the method were not loaded by the ACL,
* <code>UnloadedSidException</code> will be thrown.
*
* @param permission the exact permissions to scan for (order is important)
* @param sids the exact SIDs to scan for (order is important)
* @param administrativeMode if <code>true</code> denotes the query is for administrative purposes and no auditing
* will be undertaken
*
* @return <code>true</code> if one of the permissions has been granted, <code>false</code> if one of the
* permissions has been specifically revoked
*
* @throws NotFoundException if an exact ACE for one of the permission bit masks and SID combination could not be
* found
* @throws UnloadedSidException if the passed SIDs are unknown to this ACL because the ACL was only loaded for a
* subset of SIDs
* @see DefaultPermissionGrantingStrategy
*/
public boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
throws NotFoundException, UnloadedSidException {
@@ -193,7 +207,64 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
throw new UnloadedSidException("ACL was not loaded for one or more SID");
}
return permissionGrantingStrategy.isGranted(this, permission, sids, administrativeMode);
AccessControlEntry firstRejection = null;
for (Permission p : permission) {
for (Sid sid: sids) {
// Attempt to find exact match for this permission mask and SID
boolean scanNextSid = true;
for (AccessControlEntry ace : aces ) {
if ((ace.getPermission().getMask() == p.getMask()) && ace.getSid().equals(sid)) {
// Found a matching ACE, so its authorization decision will prevail
if (ace.isGranting()) {
// Success
if (!administrativeMode) {
auditLogger.logIfNeeded(true, ace);
}
return true;
}
// Failure for this permission, so stop search
// We will see if they have a different permission
// (this permission is 100% rejected for this SID)
if (firstRejection == null) {
// Store first rejection for auditing reasons
firstRejection = ace;
}
scanNextSid = false; // helps break the loop
break; // exit aces loop
}
}
if (!scanNextSid) {
break; // exit SID for loop (now try next permission)
}
}
}
if (firstRejection != null) {
// We found an ACE to reject the request at this point, as no
// other ACEs were found that granted a different permission
if (!administrativeMode) {
auditLogger.logIfNeeded(false, firstRejection);
}
return false;
}
// No matches have been found so far
if (isEntriesInheriting() && (parentAcl != null)) {
// We have a parent, so let them try to find a matching ACE
return parentAcl.isGranted(permission, sids, false);
} else {
// We either have no parent, or we're the uppermost parent
throw new NotFoundException("Unable to locate a matching ACE for passed permissions and SIDs");
}
}
public boolean isSidLoaded(List<Sid> sids) {
@@ -249,6 +320,39 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
return parentAcl;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("AclImpl[");
sb.append("id: ").append(this.id).append("; ");
sb.append("objectIdentity: ").append(this.objectIdentity).append("; ");
sb.append("owner: ").append(this.owner).append("; ");
int count = 0;
for (AccessControlEntry ace : aces) {
count++;
if (count == 1) {
sb.append("\r\n");
}
sb.append(ace).append("\r\n");
}
if (count == 0) {
sb.append("no ACEs; ");
}
sb.append("inheriting: ").append(this.entriesInheriting).append("; ");
sb.append("parent: ").append((this.parentAcl == null) ? "Null" : this.parentAcl.getObjectIdentity().toString());
sb.append("; ");
sb.append("aclAuthorizationStrategy: ").append(this.aclAuthorizationStrategy).append("; ");
sb.append("auditLogger: ").append(this.auditLogger);
sb.append("]");
return sb.toString();
}
public void updateAce(int aceIndex, Permission permission)
throws NotFoundException {
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
@@ -275,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;
@@ -301,37 +405,4 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
return false;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("AclImpl[");
sb.append("id: ").append(this.id).append("; ");
sb.append("objectIdentity: ").append(this.objectIdentity).append("; ");
sb.append("owner: ").append(this.owner).append("; ");
int count = 0;
for (AccessControlEntry ace : aces) {
count++;
if (count == 1) {
sb.append("\n");
}
sb.append(ace).append("\n");
}
if (count == 0) {
sb.append("no ACEs; ");
}
sb.append("inheriting: ").append(this.entriesInheriting).append("; ");
sb.append("parent: ").append((this.parentAcl == null) ? "Null" : this.parentAcl.getObjectIdentity().toString());
sb.append("; ");
sb.append("aclAuthorizationStrategy: ").append(this.aclAuthorizationStrategy).append("; ");
sb.append("permissionGrantingStrategy: ").append(this.permissionGrantingStrategy);
sb.append("]");
return sb.toString();
}
}
@@ -64,19 +64,18 @@ public class DefaultPermissionFactory implements PermissionFactory {
Field[] fields = clazz.getFields();
for (Field field : fields) {
for (int i = 0; i < fields.length; i++) {
try {
Object fieldValue = field.get(null);
Object fieldValue = fields[i].get(null);
if (Permission.class.isAssignableFrom(fieldValue.getClass())) {
// Found a Permission static field
Permission perm = (Permission) fieldValue;
String permissionName = field.getName();
String permissionName = fields[i].getName();
registerPermission(perm, permissionName);
}
} catch (Exception ignore) {
}
} catch (Exception ignore) {}
}
}
@@ -84,7 +83,7 @@ public class DefaultPermissionFactory implements PermissionFactory {
Assert.notNull(perm, "Permission required");
Assert.hasText(permissionName, "Permission name required");
Integer mask = Integer.valueOf(perm.getMask());
Integer mask = new Integer(perm.getMask());
// Ensure no existing Permission uses this integer or code
Assert.isTrue(!registeredPermissionsByInteger.containsKey(mask), "An existing Permission already provides mask " + mask);
@@ -98,7 +97,7 @@ public class DefaultPermissionFactory implements PermissionFactory {
public Permission buildFromMask(int mask) {
if (registeredPermissionsByInteger.containsKey(Integer.valueOf(mask))) {
// The requested mask has an exact match against a statically-defined Permission, so return it
return registeredPermissionsByInteger.get(Integer.valueOf(mask));
return registeredPermissionsByInteger.get(new Integer(mask));
}
// To get this far, we have to use a CumulativePermission
@@ -1,119 +0,0 @@
package org.springframework.security.acls.domain;
import java.util.List;
import org.springframework.security.acls.model.AccessControlEntry;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.PermissionGrantingStrategy;
import org.springframework.security.acls.model.Sid;
import org.springframework.util.Assert;
public class DefaultPermissionGrantingStrategy implements PermissionGrantingStrategy {
private final transient AuditLogger auditLogger;
/**
* Creates an instance with the logger which will be used to record granting and denial of requested permissions.
*/
public DefaultPermissionGrantingStrategy(AuditLogger auditLogger) {
Assert.notNull(auditLogger, "auditLogger cannot be null");
this.auditLogger = auditLogger;
}
/**
* Determines authorization. The order of the <code>permission</code> and <code>sid</code> arguments is
* <em>extremely important</em>! The method will iterate through each of the <code>permission</code>s in the order
* specified. For each iteration, all of the <code>sid</code>s will be considered, again in the order they are
* presented. A search will then be performed for the first {@link AccessControlEntry} object that directly
* matches that <code>permission:sid</code> combination. When the <em>first full match</em> is found (ie an ACE
* that has the SID currently being searched for and the exact permission bit mask being search for), the grant or
* deny flag for that ACE will prevail. If the ACE specifies to grant access, the method will return
* <code>true</code>. If the ACE specifies to deny access, the loop will stop and the next <code>permission</code>
* iteration will be performed. If each permission indicates to deny access, the first deny ACE found will be
* considered the reason for the failure (as it was the first match found, and is therefore the one most logically
* requiring changes - although not always). If absolutely no matching ACE was found at all for any permission,
* the parent ACL will be tried (provided that there is a parent and {@link Acl#isEntriesInheriting()} is
* <code>true</code>. The parent ACL will also scan its parent and so on. If ultimately no matching ACE is found,
* a <code>NotFoundException</code> will be thrown and the caller will need to decide how to handle the permission
* check. Similarly, if any of the SID arguments presented to the method were not loaded by the ACL,
* <code>UnloadedSidException</code> will be thrown.
*
* @param permission the exact permissions to scan for (order is important)
* @param sids the exact SIDs to scan for (order is important)
* @param administrativeMode if <code>true</code> denotes the query is for administrative purposes and no auditing
* will be undertaken
*
* @return <code>true</code> if one of the permissions has been granted, <code>false</code> if one of the
* permissions has been specifically revoked
*
* @throws NotFoundException if an exact ACE for one of the permission bit masks and SID combination could not be
* found
*/
public boolean isGranted(Acl acl, List<Permission> permission, List<Sid> sids, boolean administrativeMode)
throws NotFoundException {
final List<AccessControlEntry> aces = acl.getEntries();
AccessControlEntry firstRejection = null;
for (Permission p : permission) {
for (Sid sid: sids) {
// Attempt to find exact match for this permission mask and SID
boolean scanNextSid = true;
for (AccessControlEntry ace : aces ) {
if ((ace.getPermission().getMask() == p.getMask()) && ace.getSid().equals(sid)) {
// Found a matching ACE, so its authorization decision will prevail
if (ace.isGranting()) {
// Success
if (!administrativeMode) {
auditLogger.logIfNeeded(true, ace);
}
return true;
}
// Failure for this permission, so stop search
// We will see if they have a different permission
// (this permission is 100% rejected for this SID)
if (firstRejection == null) {
// Store first rejection for auditing reasons
firstRejection = ace;
}
scanNextSid = false; // helps break the loop
break; // exit aces loop
}
}
if (!scanNextSid) {
break; // exit SID for loop (now try next permission)
}
}
}
if (firstRejection != null) {
// We found an ACE to reject the request at this point, as no
// other ACEs were found that granted a different permission
if (!administrativeMode) {
auditLogger.logIfNeeded(false, firstRejection);
}
return false;
}
// No matches have been found so far
if (acl.isEntriesInheriting() && (acl.getParentAcl() != null)) {
// We have a parent, so let them try to find a matching ACE
return acl.getParentAcl().isGranted(permission, sids, false);
} else {
// We either have no parent, or we're the uppermost parent
throw new NotFoundException("Unable to locate a matching ACE for passed permissions and SIDs");
}
}
}
@@ -23,48 +23,34 @@ import net.sf.ehcache.Element;
import org.springframework.security.acls.model.AclCache;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.PermissionGrantingStrategy;
import org.springframework.security.util.FieldUtils;
import org.springframework.util.Assert;
/**
* Simple implementation of {@link AclCache} that delegates to EH-CACHE.
*
* <p>
* Designed to handle the transient fields in {@link AclImpl}. Note that this implementation assumes all
* {@link AclImpl} instances share the same {@link PermissionGrantingStrategy} and {@link AclAuthorizationStrategy}
* instances.
* {@link AclImpl} instances share the same {@link AuditLogger} and {@link AclAuthorizationStrategy} instance.
* </p>
*
* @author Ben Alex
*/
public class EhCacheBasedAclCache implements AclCache {
//~ Instance fields ================================================================================================
private final Ehcache cache;
private PermissionGrantingStrategy permissionGrantingStrategy;
private Ehcache cache;
private AuditLogger auditLogger;
private AclAuthorizationStrategy aclAuthorizationStrategy;
//~ Constructors ===================================================================================================
/**
* @deprecated use the second constructor which injects the strategy objects. See SEC-1498.
*/
@Deprecated
public EhCacheBasedAclCache(Ehcache cache) {
Assert.notNull(cache, "Cache required");
this.cache = cache;
}
public EhCacheBasedAclCache(Ehcache cache, PermissionGrantingStrategy permissionGrantingStrategy,
AclAuthorizationStrategy aclAuthorizationStrategy) {
Assert.notNull(cache, "Cache required");
Assert.notNull(permissionGrantingStrategy, "PermissionGrantingStrategy required");
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
this.cache = cache;
this.permissionGrantingStrategy = permissionGrantingStrategy;
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
}
//~ Methods ========================================================================================================
public void evictFromCache(Serializable pk) {
@@ -129,7 +115,7 @@ public class EhCacheBasedAclCache implements AclCache {
if (this.aclAuthorizationStrategy == null) {
if (acl instanceof AclImpl) {
this.aclAuthorizationStrategy = (AclAuthorizationStrategy) FieldUtils.getProtectedFieldValue("aclAuthorizationStrategy", acl);
this.permissionGrantingStrategy = (PermissionGrantingStrategy) FieldUtils.getProtectedFieldValue("permissionGrantingStrategy", acl);
this.auditLogger = (AuditLogger) FieldUtils.getProtectedFieldValue("auditLogger", acl);
}
}
@@ -144,7 +130,7 @@ public class EhCacheBasedAclCache implements AclCache {
private MutableAcl initializeTransientFields(MutableAcl value) {
if (value instanceof AclImpl) {
FieldUtils.setProtectedFieldValue("aclAuthorizationStrategy", value, this.aclAuthorizationStrategy);
FieldUtils.setProtectedFieldValue("permissionGrantingStrategy", value, this.permissionGrantingStrategy);
FieldUtils.setProtectedFieldValue("auditLogger", value, this.auditLogger);
}
if (value.getParentAcl() != null) {
@@ -30,7 +30,7 @@ import org.springframework.util.Assert;
public class GrantedAuthoritySid implements Sid {
//~ Instance fields ================================================================================================
private final String grantedAuthority;
private String grantedAuthority;
//~ Constructors ===================================================================================================
@@ -78,7 +78,7 @@ public class ObjectIdentityImpl implements ObjectIdentity {
try {
Method method = typeClass.getMethod("getId", new Class[] {});
result = method.invoke(object);
result = method.invoke(object, new Object[] {});
} catch (Exception e) {
throw new IdentityUnavailableException("Could not extract identity from object " + object, e);
}
@@ -32,7 +32,7 @@ import org.springframework.util.Assert;
public class PrincipalSid implements Sid {
//~ Instance fields ================================================================================================
private final String principal;
private String principal;
//~ Constructors ===================================================================================================
@@ -51,7 +51,7 @@ public class SidRetrievalStrategyImpl implements SidRetrievalStrategy {
//~ Methods ========================================================================================================
public List<Sid> getSids(Authentication authentication) {
Collection<? extends GrantedAuthority> authorities = roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
Collection<GrantedAuthority> authorities = roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
List<Sid> sids = new ArrayList<Sid>(authorities.size() + 1);
sids.add(new PrincipalSid(authentication));
@@ -29,6 +29,7 @@ import java.util.Set;
import javax.sql.DataSource;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementSetter;
import org.springframework.jdbc.core.ResultSetExtractor;
@@ -37,7 +38,6 @@ import org.springframework.security.acls.domain.AclAuthorizationStrategy;
import org.springframework.security.acls.domain.AclImpl;
import org.springframework.security.acls.domain.AuditLogger;
import org.springframework.security.acls.domain.DefaultPermissionFactory;
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
import org.springframework.security.acls.domain.GrantedAuthoritySid;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PermissionFactory;
@@ -49,7 +49,6 @@ import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.PermissionGrantingStrategy;
import org.springframework.security.acls.model.Sid;
import org.springframework.security.acls.model.UnloadedSidException;
import org.springframework.security.util.FieldUtils;
@@ -107,11 +106,11 @@ public final class BasicLookupStrategy implements LookupStrategy {
//~ Instance fields ================================================================================================
private final AclAuthorizationStrategy aclAuthorizationStrategy;
private AclAuthorizationStrategy aclAuthorizationStrategy;
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
private final AclCache aclCache;
private final PermissionGrantingStrategy grantingStrategy;
private final JdbcTemplate jdbcTemplate;
private AclCache aclCache;
private AuditLogger auditLogger;
private JdbcTemplate jdbcTemplate;
private int batchSize = 50;
private final Field fieldAces = FieldUtils.getField(AclImpl.class, "aces");
@@ -131,28 +130,19 @@ public final class BasicLookupStrategy implements LookupStrategy {
* @param dataSource to access the database
* @param aclCache the cache where fully-loaded elements can be stored
* @param aclAuthorizationStrategy authorization strategy (required)
*
* @deprecated Use the version which takes a {@code PermissionGrantingStrategy} argument instead.
*/
@Deprecated
public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
AclAuthorizationStrategy aclAuthorizationStrategy, AuditLogger auditLogger) {
this(dataSource, aclCache, aclAuthorizationStrategy, new DefaultPermissionGrantingStrategy(auditLogger));
}
public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
AclAuthorizationStrategy aclAuthorizationStrategy, PermissionGrantingStrategy grantingStrategy) {
AclAuthorizationStrategy aclAuthorizationStrategy, AuditLogger auditLogger) {
Assert.notNull(dataSource, "DataSource required");
Assert.notNull(aclCache, "AclCache required");
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
Assert.notNull(grantingStrategy, "grantingStrategy required");
Assert.notNull(auditLogger, "AuditLogger required");
jdbcTemplate = new JdbcTemplate(dataSource);
this.aclCache = aclCache;
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
this.grantingStrategy = grantingStrategy;
this.auditLogger = auditLogger;
fieldAces.setAccessible(true);
fieldAcl.setAccessible(true);
}
//~ Methods ========================================================================================================
@@ -405,7 +395,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
// Now we have the parent (if there is one), create the true AclImpl
AclImpl result = new AclImpl(inputAcl.getObjectIdentity(), (Long) inputAcl.getId(), aclAuthorizationStrategy,
grantingStrategy, parent, null, inputAcl.isEntriesInheriting(), inputAcl.getOwner());
auditLogger, parent, null, inputAcl.isEntriesInheriting(), inputAcl.getOwner());
// Copy the "aces" from the input to the destination
@@ -476,8 +466,8 @@ public final class BasicLookupStrategy implements LookupStrategy {
//~ Inner Classes ==================================================================================================
private class ProcessResultSet implements ResultSetExtractor<Set<Long>> {
private final Map<Serializable, Acl> acls;
private final List<Sid> sids;
private Map<Serializable, Acl> acls;
private List<Sid> sids;
public ProcessResultSet(Map<Serializable, Acl> acls, List<Sid> sids) {
Assert.notNull(acls, "ACLs cannot be null");
@@ -494,8 +484,9 @@ public final class BasicLookupStrategy implements LookupStrategy {
* @param rs The {@link ResultSet} to be processed
* @return a list of parent IDs remaining to be looked up (may be empty, but never <tt>null</tt>)
* @throws SQLException
* @throws DataAccessException
*/
public Set<Long> extractData(ResultSet rs) throws SQLException {
public Set<Long> extractData(ResultSet rs) throws SQLException, DataAccessException {
Set<Long> parentIdsToLookup = new HashSet<Long>(); // Set of parent_id Longs
while (rs.next()) {
@@ -564,7 +555,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
owner = new GrantedAuthoritySid(rs.getString("acl_sid"));
}
acl = new AclImpl(objectIdentity, id, aclAuthorizationStrategy, grantingStrategy, parentAcl, null,
acl = new AclImpl(objectIdentity, id, aclAuthorizationStrategy, auditLogger, parentAcl, null,
entriesInheriting, owner);
acls.put(id, acl);
@@ -603,7 +594,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
}
private class StubAclParent implements Acl {
private final Long id;
private Long id;
public StubAclParent(Long id) {
this.id = id;
@@ -56,8 +56,8 @@ public class JdbcAclService implements AclService {
//~ Instance fields ================================================================================================
protected final JdbcTemplate jdbcTemplate;
private final LookupStrategy lookupStrategy;
protected JdbcTemplate jdbcTemplate;
private LookupStrategy lookupStrategy;
private String findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL;
//~ Constructors ===================================================================================================
@@ -109,9 +109,10 @@ public class JdbcAclService implements AclService {
Map<ObjectIdentity, Acl> result = lookupStrategy.readAclsById(objects, sids);
// Check every requested object identity was found (throw NotFoundException if needed)
for (ObjectIdentity oid : objects) {
if (!result.containsKey(oid)) {
throw new NotFoundException("Unable to find ACL information for object identity '" + oid + "'");
for (int i = 0; i < objects.size(); i++) {
if (!result.containsKey(objects.get(i))) {
throw new NotFoundException("Unable to find ACL information for object identity '"
+ objects.get(i) + "'");
}
}
@@ -61,7 +61,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
//~ Instance fields ================================================================================================
private boolean foreignKeysInDatabase = true;
private final AclCache aclCache;
private AclCache aclCache;
private String deleteEntryByObjectIdentityForeignKey = "delete from acl_entry where acl_object_identity=?";
private String deleteObjectIdentityByPrimaryKey = "delete from acl_object_identity where id=?";
private String classIdentityQuery = "call identity()";
@@ -194,7 +194,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
Assert.notNull(sid, "Sid required");
String sidName;
String sidName = null;
boolean sidIsPrincipal = true;
if (sid instanceof PrincipalSid) {
@@ -214,7 +214,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
}
if (allowCreate) {
jdbcTemplate.update(insertSid, Boolean.valueOf(sidIsPrincipal), sidName);
jdbcTemplate.update(insertSid, new Object[] {Boolean.valueOf(sidIsPrincipal), sidName});
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
return new Long(jdbcTemplate.queryForLong(sidIdentityQuery));
}
@@ -229,8 +229,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
if (deleteChildren) {
List<ObjectIdentity> children = findChildren(objectIdentity);
if (children != null) {
for (ObjectIdentity child : children) {
deleteAcl(child, true);
for (int i = 0; i < children.size(); i++) {
deleteAcl(children.get(i), true);
}
}
} else {
@@ -263,7 +263,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
* @param oidPrimaryKey the rows in acl_entry to delete
*/
protected void deleteEntries(Long oidPrimaryKey) {
jdbcTemplate.update(deleteEntryByObjectIdentityForeignKey, oidPrimaryKey);
jdbcTemplate.update(deleteEntryByObjectIdentityForeignKey,
new Object[] {oidPrimaryKey});
}
/**
@@ -276,7 +277,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
*/
protected void deleteObjectIdentity(Long oidPrimaryKey) {
// Delete the acl_object_identity row
jdbcTemplate.update(deleteObjectIdentityByPrimaryKey, oidPrimaryKey);
jdbcTemplate.update(deleteObjectIdentityByPrimaryKey, new Object[] {oidPrimaryKey});
}
/**
@@ -290,7 +291,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
*/
protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
try {
return new Long(jdbcTemplate.queryForLong(selectObjectIdentityPrimaryKey, oid.getType(), oid.getIdentifier()));
return new Long(jdbcTemplate.queryForLong(selectObjectIdentityPrimaryKey,
new Object[] {oid.getType(), oid.getIdentifier()}));
} catch (DataAccessException notFound) {
return null;
}
@@ -324,8 +326,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
Assert.notNull(objectIdentity, "ObjectIdentity required");
List<ObjectIdentity> children = findChildren(objectIdentity);
if (children != null) {
for (ObjectIdentity child : children) {
clearCacheIncludingChildren(child);
for (int i = 0; i < children.size(); i++) {
clearCacheIncludingChildren(children.get(i));
}
}
aclCache.evictFromCache(objectIdentity);
@@ -354,7 +356,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
Long ownerSid = createOrRetrieveSidPrimaryKey(acl.getOwner(), true);
int count = jdbcTemplate.update(updateObjectIdentity,
parentId, ownerSid, Boolean.valueOf(acl.isEntriesInheriting()), acl.getId());
new Object[] {parentId, ownerSid, new Boolean(acl.isEntriesInheriting()), acl.getId()});
if (count != 1) {
throw new NotFoundException("Unable to locate ACL to update");
@@ -1,20 +0,0 @@
package org.springframework.security.acls.model;
import java.util.List;
/**
* Allow customization of the logic for determining whether a permission or permissions are granted to a particular
* sid or sids by an {@link Acl}.
*
* @author Luke Taylor
* @since 3.0.2
*/
public interface PermissionGrantingStrategy {
/**
* Returns true if the the supplied strategy decides that the supplied {@code Acl} grants access
* based on the supplied list of permissions and sids.
*/
boolean isGranted(Acl acl, List<Permission> permission, List<Sid> sids, boolean administrativeMode);
}
@@ -1,56 +0,0 @@
package org.springframework.security.acls;
import static org.mockito.Mockito.*;
import org.junit.Test;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.model.AclService;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy;
import org.springframework.security.acls.model.SidRetrievalStrategy;
import org.springframework.security.core.Authentication;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* @author Luke Taylor
*/
@SuppressWarnings({"unchecked"})
public class AclPermissionCacheOptimizerTests {
@Test
public void eagerlyLoadsRequiredAcls() throws Exception {
AclService service = mock(AclService.class);
AclPermissionCacheOptimizer pco = new AclPermissionCacheOptimizer(service);
ObjectIdentityRetrievalStrategy oidStrat = mock(ObjectIdentityRetrievalStrategy.class);
SidRetrievalStrategy sidStrat = mock(SidRetrievalStrategy.class);
pco.setObjectIdentityRetrievalStrategy(oidStrat);
pco.setSidRetrievalStrategy(sidStrat);
Object[] dos = {new Object(), null, new Object()};
ObjectIdentity[] oids = {new ObjectIdentityImpl("A", "1"), new ObjectIdentityImpl("A", "2")};
when(oidStrat.getObjectIdentity(dos[0])).thenReturn(oids[0]);
when(oidStrat.getObjectIdentity(dos[2])).thenReturn(oids[1]);
pco.cachePermissionsFor(mock(Authentication.class), Arrays.asList(dos));
// AclService should be invoked with the list of required Oids
verify(service).readAclsById(eq(Arrays.asList(oids)), any(List.class));
}
@Test
public void ignoresEmptyCollection() {
AclService service = mock(AclService.class);
AclPermissionCacheOptimizer pco = new AclPermissionCacheOptimizer(service);
ObjectIdentityRetrievalStrategy oids = mock(ObjectIdentityRetrievalStrategy.class);
SidRetrievalStrategy sids = mock(SidRetrievalStrategy.class);
pco.setObjectIdentityRetrievalStrategy(oids);
pco.setSidRetrievalStrategy(sids);
pco.cachePermissionsFor(mock(Authentication.class), Collections.emptyList());
verifyZeroInteractions(service, sids, oids);
}
}
@@ -1,64 +0,0 @@
package org.springframework.security.acls.afterinvocation;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.when;
import org.junit.Test;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.acls.model.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.SpringSecurityMessageSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* @author Luke Taylor
*/
@SuppressWarnings({"unchecked"})
public class AclEntryAfterInvocationCollectionFilteringProviderTests {
@Test
public void objectsAreRemovedIfPermissionDenied() throws Exception {
AclService service = mock(AclService.class);
Acl acl = mock(Acl.class);
when(acl.isGranted(any(List.class), any(List.class), anyBoolean())).thenReturn(false);
when(service.readAclById(any(ObjectIdentity.class), any(List.class))).thenReturn(acl);
AclEntryAfterInvocationCollectionFilteringProvider provider = new AclEntryAfterInvocationCollectionFilteringProvider(service, Arrays.asList(mock(Permission.class)));
provider.setObjectIdentityRetrievalStrategy(mock(ObjectIdentityRetrievalStrategy.class));
provider.setProcessDomainObjectClass(Object.class);
provider.setSidRetrievalStrategy(mock(SidRetrievalStrategy.class));
Object returned = provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("AFTER_ACL_COLLECTION_READ"), new ArrayList(Arrays.asList(new Object(), new Object())));
assertTrue(returned instanceof List);
assertTrue(((List)returned).isEmpty());
returned = provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("UNSUPPORTED", "AFTER_ACL_COLLECTION_READ"), new Object[] {new Object(), new Object()});
assertTrue(returned instanceof Object[]);
assertTrue(((Object[])returned).length == 0);
}
@Test
public void accessIsGrantedIfNoAttributesDefined() throws Exception {
AclEntryAfterInvocationCollectionFilteringProvider provider = new AclEntryAfterInvocationCollectionFilteringProvider(mock(AclService.class), Arrays.asList(mock(Permission.class)));
Object returned = new Object();
assertSame(returned, provider.decide(mock(Authentication.class), new Object(), Collections.<ConfigAttribute>emptyList(), returned));
}
@Test
public void nullReturnObjectIsIgnored() throws Exception {
AclService service = mock(AclService.class);
AclEntryAfterInvocationCollectionFilteringProvider provider = new AclEntryAfterInvocationCollectionFilteringProvider(service, Arrays.asList(mock(Permission.class)));
assertNull(provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("AFTER_ACL_COLLECTION_READ"), null));
verify(service, never()).readAclById(any(ObjectIdentity.class), any(List.class));
}
}
@@ -1,101 +0,0 @@
package org.springframework.security.acls.afterinvocation;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
import org.junit.Test;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.acls.model.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.SpringSecurityMessageSource;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* @author Luke Taylor
*/
@SuppressWarnings({"unchecked"})
public class AclEntryAfterInvocationProviderTests {
@Test(expected=IllegalArgumentException.class)
public void rejectsMissingPermissions() throws Exception {
try {
new AclEntryAfterInvocationProvider(mock(AclService.class), null);
fail("Exception expected");
} catch (IllegalArgumentException expected) {
}
new AclEntryAfterInvocationProvider(mock(AclService.class), Collections.<Permission>emptyList());
}
@Test
public void accessIsAllowedIfPermissionIsGranted() {
AclService service = mock(AclService.class);
Acl acl = mock(Acl.class);
when(acl.isGranted(any(List.class), any(List.class), anyBoolean())).thenReturn(true);
when(service.readAclById(any(ObjectIdentity.class), any(List.class))).thenReturn(acl);
AclEntryAfterInvocationProvider provider = new AclEntryAfterInvocationProvider(service, Arrays.asList(mock(Permission.class)));
provider.setMessageSource(new SpringSecurityMessageSource());
provider.setObjectIdentityRetrievalStrategy(mock(ObjectIdentityRetrievalStrategy.class));
provider.setProcessDomainObjectClass(Object.class);
provider.setSidRetrievalStrategy(mock(SidRetrievalStrategy.class));
Object returned = new Object();
assertSame(returned, provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("AFTER_ACL_READ"), returned));
}
@Test
public void accessIsGrantedIfNoAttributesDefined() throws Exception {
AclEntryAfterInvocationProvider provider = new AclEntryAfterInvocationProvider(mock(AclService.class), Arrays.asList(mock(Permission.class)));
Object returned = new Object();
assertSame(returned, provider.decide(mock(Authentication.class), new Object(), Collections.<ConfigAttribute>emptyList(), returned));
}
@Test
public void accessIsGrantedIfObjectTypeNotSupported() throws Exception {
AclEntryAfterInvocationProvider provider = new AclEntryAfterInvocationProvider(mock(AclService.class), Arrays.asList(mock(Permission.class)));
provider.setProcessDomainObjectClass(String.class);
// Not a String
Object returned = new Object();
assertSame(returned, provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("AFTER_ACL_READ"), returned));
}
@Test(expected= AccessDeniedException.class)
public void accessIsDeniedIfPermissionIsNotGranted() {
AclService service = mock(AclService.class);
Acl acl = mock(Acl.class);
when(acl.isGranted(any(List.class), any(List.class), anyBoolean())).thenReturn(false);
// Try a second time with no permissions found
when(acl.isGranted(any(List.class), any(List.class), anyBoolean())).thenThrow(new NotFoundException(""));
when(service.readAclById(any(ObjectIdentity.class), any(List.class))).thenReturn(acl);
AclEntryAfterInvocationProvider provider = new AclEntryAfterInvocationProvider(service, Arrays.asList(mock(Permission.class)));
provider.setProcessConfigAttribute("MY_ATTRIBUTE");
provider.setMessageSource(new SpringSecurityMessageSource());
provider.setObjectIdentityRetrievalStrategy(mock(ObjectIdentityRetrievalStrategy.class));
provider.setProcessDomainObjectClass(Object.class);
provider.setSidRetrievalStrategy(mock(SidRetrievalStrategy.class));
try {
provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("UNSUPPORTED", "MY_ATTRIBUTE"), new Object());
fail();
} catch (AccessDeniedException expected) {
}
// Second scenario with no acls found
provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("UNSUPPORTED", "MY_ATTRIBUTE"), new Object());
}
@Test
public void nullReturnObjectIsIgnored() throws Exception {
AclService service = mock(AclService.class);
AclEntryAfterInvocationProvider provider = new AclEntryAfterInvocationProvider(service, Arrays.asList(mock(Permission.class)));
assertNull(provider.decide(mock(Authentication.class), new Object(), SecurityConfig.createList("AFTER_ACL_COLLECTION_READ"), null));
verify(service, never()).readAclById(any(ObjectIdentity.class), any(List.class));
}
}
@@ -1,8 +1,10 @@
package org.springframework.security.acls.domain;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.junit.Test;
import org.springframework.security.acls.model.AccessControlEntry;
import org.springframework.security.acls.model.Acl;
@@ -16,6 +18,7 @@ import org.springframework.security.acls.model.Sid;
* @author Andrei Stefan
*/
public class AccessControlImplEntryTests {
Mockery jmock = new JUnit4Mockery();
//~ Methods ========================================================================================================
@@ -32,7 +35,7 @@ public class AccessControlImplEntryTests {
// Check Sid field is present
try {
new AccessControlEntryImpl(null, mock(Acl.class), null,
new AccessControlEntryImpl(null, jmock.mock(Acl.class), null,
BasePermission.ADMINISTRATION, true, true, true);
fail("It should have thrown IllegalArgumentException");
}
@@ -41,7 +44,7 @@ public class AccessControlImplEntryTests {
// Check Permission field is present
try {
new AccessControlEntryImpl(null, mock(Acl.class), new PrincipalSid("johndoe"), null,
new AccessControlEntryImpl(null, jmock.mock(Acl.class), new PrincipalSid("johndoe"), null,
true, true, true);
fail("It should have thrown IllegalArgumentException");
}
@@ -51,11 +54,11 @@ public class AccessControlImplEntryTests {
@Test
public void testAccessControlEntryImplGetters() {
Acl mockAcl = mock(Acl.class);
Acl mockAcl = jmock.mock(Acl.class);
Sid sid = new PrincipalSid("johndoe");
// Create a sample entry
AccessControlEntry ace = new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid, BasePermission.ADMINISTRATION,
AccessControlEntry ace = new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.ADMINISTRATION,
true, true, true);
// and check every get() method
@@ -70,31 +73,32 @@ public class AccessControlImplEntryTests {
@Test
public void testEquals() {
final Acl mockAcl = mock(Acl.class);
final ObjectIdentity oid = mock(ObjectIdentity.class);
when(mockAcl.getObjectIdentity()).thenReturn(oid);
final Acl mockAcl = jmock.mock(Acl.class);
final ObjectIdentity oid = jmock.mock(ObjectIdentity.class);
jmock.checking(new Expectations() {{
allowing(mockAcl).getObjectIdentity(); will(returnValue(oid));
}});
Sid sid = new PrincipalSid("johndoe");
AccessControlEntry ace = new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid, BasePermission.ADMINISTRATION,
AccessControlEntry ace = new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.ADMINISTRATION,
true, true, true);
assertFalse(ace.equals(null));
assertFalse(ace.equals(Long.valueOf(100)));
assertFalse(ace.equals(new Long(100)));
assertTrue(ace.equals(ace));
assertTrue(ace.equals(new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid,
assertTrue(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
BasePermission.ADMINISTRATION, true, true, true)));
assertFalse(ace.equals(new AccessControlEntryImpl(Long.valueOf(2), mockAcl, sid,
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(2), mockAcl, sid,
BasePermission.ADMINISTRATION, true, true, true)));
assertFalse(ace.equals(new AccessControlEntryImpl(Long.valueOf(1), mockAcl, new PrincipalSid("scott"),
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, new PrincipalSid("scott"),
BasePermission.ADMINISTRATION, true, true, true)));
assertFalse(ace.equals(new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid, BasePermission.WRITE, true,
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid, BasePermission.WRITE, true,
true, true)));
assertFalse(ace.equals(new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid,
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
BasePermission.ADMINISTRATION, false, true, true)));
assertFalse(ace.equals(new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid,
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
BasePermission.ADMINISTRATION, true, false, true)));
assertFalse(ace.equals(new AccessControlEntryImpl(Long.valueOf(1), mockAcl, sid,
assertFalse(ace.equals(new AccessControlEntryImpl(new Long(1), mockAcl, sid,
BasePermission.ADMINISTRATION, true, true, false)));
}
}
@@ -1,18 +1,37 @@
package org.springframework.security.acls.domain;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.junit.*;
import org.springframework.security.acls.model.*;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.util.FieldUtils;
import static org.mockito.Mockito.mock;
import java.lang.reflect.Field;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.jmock.Mockery;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.security.acls.model.AccessControlEntry;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.AlreadyExistsException;
import org.springframework.security.acls.model.AuditableAccessControlEntry;
import org.springframework.security.acls.model.AuditableAcl;
import org.springframework.security.acls.model.ChildrenExistException;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.MutableAclService;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.OwnershipAcl;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.Sid;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.util.FieldUtils;
/**
@@ -30,8 +49,8 @@ public class AclImplTests {
private static final List<Sid> BEN = Arrays.asList((Sid)new PrincipalSid("ben"));
Authentication auth = new TestingAuthenticationToken("joe", "ignored", "ROLE_ADMINISTRATOR");
AclAuthorizationStrategy authzStrategy;
PermissionGrantingStrategy pgs;
Mockery jmockCtx = new Mockery();
AclAuthorizationStrategy mockAuthzStrategy;
AuditLogger mockAuditLogger;
ObjectIdentity objectIdentity = new ObjectIdentityImpl(TARGET_CLASS, 100);
@@ -40,9 +59,8 @@ public class AclImplTests {
@Before
public void setUp() throws Exception {
SecurityContextHolder.getContext().setAuthentication(auth);
authzStrategy = mock(AclAuthorizationStrategy.class);
mockAuditLogger = mock(AuditLogger.class);
pgs = new DefaultPermissionGrantingStrategy(mockAuditLogger);
mockAuthzStrategy = mock(AclAuthorizationStrategy.class);
mockAuditLogger = mock(AuditLogger.class);;
auth.setAuthenticated(true);
}
@@ -54,26 +72,25 @@ public class AclImplTests {
@Test(expected=IllegalArgumentException.class)
public void constructorsRejectNullObjectIdentity() throws Exception {
try {
new AclImpl(null, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
new AclImpl(null, 1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid("joe"));
fail("Should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
}
new AclImpl(null, 1, authzStrategy, mockAuditLogger);
new AclImpl(null, 1, mockAuthzStrategy, mockAuditLogger);
}
@Test(expected=IllegalArgumentException.class)
public void constructorsRejectNullId() throws Exception {
try {
new AclImpl(objectIdentity, null, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
new AclImpl(objectIdentity, null, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid("joe"));
fail("Should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
}
new AclImpl(objectIdentity, null, authzStrategy, mockAuditLogger);
new AclImpl(objectIdentity, null, mockAuthzStrategy, mockAuditLogger);
}
@SuppressWarnings("deprecation")
@Test(expected=IllegalArgumentException.class)
public void constructorsRejectNullAclAuthzStrategy() throws Exception {
try {
@@ -85,9 +102,20 @@ public class AclImplTests {
new AclImpl(objectIdentity, 1, null, mockAuditLogger);
}
@Test(expected=IllegalArgumentException.class)
public void constructorsRejectNullAuditLogger() throws Exception {
try {
new AclImpl(objectIdentity, 1, mockAuthzStrategy, null, null, null, true, new PrincipalSid("joe"));
fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
}
new AclImpl(objectIdentity, 1, mockAuthzStrategy, null);
}
@Test
public void insertAceRejectsNullParameters() throws Exception {
MutableAcl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid(
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid(
"joe"));
try {
acl.insertAce(0, null, new GrantedAuthoritySid("ROLE_IGNORED"), true);
@@ -105,7 +133,7 @@ public class AclImplTests {
@Test
public void insertAceAddsElementAtCorrectIndex() throws Exception {
MutableAcl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid("joe"));
MockAclService service = new MockAclService();
// Insert one permission
@@ -141,7 +169,7 @@ public class AclImplTests {
@Test(expected=NotFoundException.class)
public void insertAceFailsForNonExistentElement() throws Exception {
MutableAcl acl = new AclImpl(objectIdentity,1, authzStrategy, pgs, null, null, true, new PrincipalSid(
MutableAcl acl = new AclImpl(objectIdentity,1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid(
"joe"));
MockAclService service = new MockAclService();
@@ -154,7 +182,8 @@ public class AclImplTests {
@Test
public void deleteAceKeepsInitialOrdering() throws Exception {
MutableAcl acl = new AclImpl(objectIdentity,1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
MutableAcl acl = new AclImpl(objectIdentity,1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid(
"joe"));
MockAclService service = new MockAclService();
// Add several permissions
@@ -185,10 +214,11 @@ public class AclImplTests {
@Test
public void deleteAceFailsForNonExistentElement() throws Exception {
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
MutableAcl acl = new AclImpl(objectIdentity, (1), strategy, pgs, null, null, true, new PrincipalSid(
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
new GrantedAuthorityImpl("ROLE_GENERAL") });
AuditLogger auditLogger = new ConsoleAuditLogger();
MutableAcl acl = new AclImpl(objectIdentity, (1), strategy, auditLogger, null, null, true, new PrincipalSid(
"joe"));
try {
acl.deleteAce(99);
@@ -200,7 +230,8 @@ public class AclImplTests {
@Test
public void isGrantingRejectsEmptyParameters() throws Exception {
MutableAcl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true, new PrincipalSid(
"joe"));
Sid ben = new PrincipalSid("ben");
try {
acl.isGranted(new ArrayList<Permission>(0), Arrays.asList(ben) , false);
@@ -224,7 +255,8 @@ public class AclImplTests {
ObjectIdentity rootOid = new ObjectIdentityImpl(TARGET_CLASS, 100);
// Create an ACL which owner is not the authenticated principal
MutableAcl rootAcl = new AclImpl(rootOid, 1, authzStrategy, pgs, null, null, false, new PrincipalSid("joe"));
MutableAcl rootAcl = new AclImpl(rootOid, 1, mockAuthzStrategy, mockAuditLogger, null, null, false, new PrincipalSid(
"joe"));
// Grant some permissions
rootAcl.insertAce(0, BasePermission.READ, new PrincipalSid("ben"), false);
@@ -267,12 +299,16 @@ public class AclImplTests {
ObjectIdentity childOid2 = new ObjectIdentityImpl(TARGET_CLASS, 104);
// Create ACLs
PrincipalSid joe = new PrincipalSid("joe");
MutableAcl grandParentAcl = new AclImpl(grandParentOid, 1, authzStrategy, pgs, null, null, false, joe);
MutableAcl parentAcl1 = new AclImpl(parentOid1, 2, authzStrategy, pgs, null, null, true, joe);
MutableAcl parentAcl2 = new AclImpl(parentOid2, 3, authzStrategy, pgs, null, null, true, joe);
MutableAcl childAcl1 = new AclImpl(childOid1, 4, authzStrategy, pgs, null, null, true, joe);
MutableAcl childAcl2 = new AclImpl(childOid2, 4, authzStrategy, pgs, null, null, false, joe);
MutableAcl grandParentAcl = new AclImpl(grandParentOid, 1, mockAuthzStrategy, mockAuditLogger, null, null, false,
new PrincipalSid("joe"));
MutableAcl parentAcl1 = new AclImpl(parentOid1, 2, mockAuthzStrategy, mockAuditLogger, null, null, true,
new PrincipalSid("joe"));
MutableAcl parentAcl2 = new AclImpl(parentOid2, 3, mockAuthzStrategy, mockAuditLogger, null, null, true,
new PrincipalSid("joe"));
MutableAcl childAcl1 = new AclImpl(childOid1, 4, mockAuthzStrategy, mockAuditLogger, null, null, true,
new PrincipalSid("joe"));
MutableAcl childAcl2 = new AclImpl(childOid2, 4, mockAuthzStrategy, mockAuditLogger, null, null, false,
new PrincipalSid("joe"));
// Create hierarchies
childAcl2.setParent(childAcl1);
@@ -330,7 +366,8 @@ public class AclImplTests {
Authentication auth = new TestingAuthenticationToken("ben", "ignored","ROLE_GENERAL");
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
MutableAcl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, false, new PrincipalSid("joe"));
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, false, new PrincipalSid(
"joe"));
MockAclService service = new MockAclService();
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
@@ -347,7 +384,7 @@ public class AclImplTests {
acl.updateAce(1, BasePermission.DELETE);
acl.updateAce(2, BasePermission.READ);
// Check the change was successfully made
// Check the change was successfuly made
assertEquals(acl.getEntries().get(0).getPermission(), BasePermission.CREATE);
assertEquals(acl.getEntries().get(1).getPermission(), BasePermission.DELETE);
assertEquals(acl.getEntries().get(2).getPermission(), BasePermission.READ);
@@ -358,7 +395,8 @@ public class AclImplTests {
Authentication auth = new TestingAuthenticationToken("ben", "ignored", "ROLE_AUDITING", "ROLE_GENERAL");
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
MutableAcl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, false, new PrincipalSid("joe"));
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, false, new PrincipalSid(
"joe"));
MockAclService service = new MockAclService();
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
@@ -383,13 +421,16 @@ public class AclImplTests {
@Test
public void gettersAndSettersAreConsistent() throws Exception {
Authentication auth = new TestingAuthenticationToken("ben", "ignored", "ROLE_GENERAL");
Authentication auth = new TestingAuthenticationToken("ben", "ignored", new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_GENERAL") });
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, (100));
ObjectIdentity identity2 = new ObjectIdentityImpl(TARGET_CLASS, (101));
MutableAcl acl = new AclImpl(identity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
MutableAcl parentAcl = new AclImpl(identity2, 2, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
MutableAcl acl = new AclImpl(identity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true,
new PrincipalSid("joe"));
MutableAcl parentAcl = new AclImpl(identity2, 2, mockAuthzStrategy, mockAuditLogger, null, null, true,
new PrincipalSid("joe"));
MockAclService service = new MockAclService();
acl.insertAce(0, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER_READ"), true);
acl.insertAce(1, BasePermission.WRITE, new GrantedAuthoritySid("ROLE_USER_READ"), true);
@@ -408,14 +449,14 @@ public class AclImplTests {
acl.setEntriesInheriting(false);
assertFalse(acl.isEntriesInheriting());
acl.setOwner(new PrincipalSid("ben"));
((OwnershipAcl) acl).setOwner(new PrincipalSid("ben"));
assertEquals(acl.getOwner(), new PrincipalSid("ben"));
}
@Test
public void isSidLoadedBehavesAsExpected() throws Exception {
List<Sid> loadedSids = Arrays.asList(new PrincipalSid("ben"), new GrantedAuthoritySid("ROLE_IGNORED"));
MutableAcl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, loadedSids, true,
MutableAcl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, loadedSids, true,
new PrincipalSid("joe"));
assertTrue(acl.isSidLoaded(loadedSids));
@@ -431,19 +472,22 @@ public class AclImplTests {
@Test(expected=NotFoundException.class)
public void insertAceRaisesNotFoundExceptionForIndexLessThanZero() throws Exception {
AclImpl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
AclImpl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true,
new PrincipalSid("joe"));
acl.insertAce(-1, mock(Permission.class), mock(Sid.class), true);
}
@Test(expected=NotFoundException.class)
public void deleteAceRaisesNotFoundExceptionForIndexLessThanZero() throws Exception {
AclImpl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
AclImpl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true,
new PrincipalSid("joe"));
acl.deleteAce(-1);
}
@Test(expected=NotFoundException.class)
public void insertAceRaisesNotFoundExceptionForIndexGreaterThanSize() throws Exception {
AclImpl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
AclImpl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true,
new PrincipalSid("joe"));
// Insert at zero, OK.
acl.insertAce(0, mock(Permission.class), mock(Sid.class), true);
// Size is now 1
@@ -453,12 +497,23 @@ public class AclImplTests {
// SEC-1151
@Test(expected=NotFoundException.class)
public void deleteAceRaisesNotFoundExceptionForIndexEqualToSize() throws Exception {
AclImpl acl = new AclImpl(objectIdentity, 1, authzStrategy, pgs, null, null, true, new PrincipalSid("joe"));
AclImpl acl = new AclImpl(objectIdentity, 1, mockAuthzStrategy, mockAuditLogger, null, null, true,
new PrincipalSid("joe"));
acl.insertAce(0, mock(Permission.class), mock(Sid.class), true);
// Size is now 1
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 ==================================================================================================
@@ -1,8 +1,8 @@
package org.springframework.security.acls.domain;
import static org.junit.Assert.*;
import junit.framework.Assert;
import junit.framework.TestCase;
import org.junit.*;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.MutableAcl;
@@ -10,7 +10,8 @@ import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.context.SecurityContextHolder;
/**
@@ -19,31 +20,28 @@ import org.springframework.security.core.context.SecurityContextHolder;
*
* @author Andrei Stefan
*/
public class AclImplementationSecurityCheckTests {
public class AclImplementationSecurityCheckTests extends TestCase {
private static final String TARGET_CLASS = "org.springframework.security.acls.TargetObject";
//~ Methods ========================================================================================================
@Before
public void setUp() throws Exception {
protected void setUp() throws Exception {
SecurityContextHolder.clearContext();
}
@After
public void tearDown() throws Exception {
protected void tearDown() throws Exception {
SecurityContextHolder.clearContext();
}
@Test
public void testSecurityCheckNoACEs() throws Exception {
Authentication auth = new TestingAuthenticationToken("user", "password","ROLE_GENERAL","ROLE_AUDITING","ROLE_OWNERSHIP");
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
new GrantedAuthorityImpl("ROLE_GENERAL") });
Acl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
@@ -52,43 +50,43 @@ public class AclImplementationSecurityCheckTests {
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
// Create another authorization strategy
AclAuthorizationStrategy aclAuthorizationStrategy2 = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_ONE"), new SimpleGrantedAuthority("ROLE_TWO"),
new SimpleGrantedAuthority("ROLE_THREE"));
AclAuthorizationStrategy aclAuthorizationStrategy2 = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO"),
new GrantedAuthorityImpl("ROLE_THREE") });
Acl acl2 = new AclImpl(identity, new Long(1), aclAuthorizationStrategy2, new ConsoleAuditLogger());
// Check access in case the principal has no authorization rights
try {
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_GENERAL);
fail("It should have thrown NotFoundException");
Assert.fail("It should have thrown NotFoundException");
}
catch (NotFoundException expected) {
}
try {
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_AUDITING);
fail("It should have thrown NotFoundException");
Assert.fail("It should have thrown NotFoundException");
}
catch (NotFoundException expected) {
}
try {
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
fail("It should have thrown NotFoundException");
Assert.fail("It should have thrown NotFoundException");
}
catch (NotFoundException expected) {
}
}
@Test
public void testSecurityCheckWithMultipleACEs() throws Exception {
// Create a simple authentication with ROLE_GENERAL
Authentication auth = new TestingAuthenticationToken("user", "password", "ROLE_GENERAL");
Authentication auth = new TestingAuthenticationToken("user", "password",
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_GENERAL") });
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
// Authorization strategy will require a different role for each access
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
new GrantedAuthorityImpl("ROLE_GENERAL") });
// Let's give the principal the ADMINISTRATION permission, without
// granting access
@@ -103,13 +101,13 @@ public class AclImplementationSecurityCheckTests {
// nor granting access
try {
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_AUDITING);
fail("It should have thrown AccessDeniedException");
Assert.fail("It should have thrown AccessDeniedException");
}
catch (AccessDeniedException expected) {
}
try {
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
fail("It should have thrown AccessDeniedException");
Assert.fail("It should have thrown AccessDeniedException");
}
catch (AccessDeniedException expected) {
}
@@ -120,7 +118,7 @@ public class AclImplementationSecurityCheckTests {
// (false) will deny this access
try {
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_AUDITING);
fail("It should have thrown AccessDeniedException");
Assert.fail("It should have thrown AccessDeniedException");
}
catch (AccessDeniedException expected) {
}
@@ -140,58 +138,58 @@ public class AclImplementationSecurityCheckTests {
aclFirstAllow.insertAce(1, BasePermission.ADMINISTRATION, new PrincipalSid(auth), false);
try {
aclAuthorizationStrategy.securityCheck(aclFirstAllow, AclAuthorizationStrategy.CHANGE_AUDITING);
assertTrue(true);
Assert.assertTrue(true);
}
catch (AccessDeniedException notExpected) {
fail("It shouldn't have thrown AccessDeniedException");
Assert.fail("It shouldn't have thrown AccessDeniedException");
}
// Create an ACL with no ACE
MutableAcl aclNoACE = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
try {
aclAuthorizationStrategy.securityCheck(aclNoACE, AclAuthorizationStrategy.CHANGE_AUDITING);
fail("It should have thrown NotFoundException");
Assert.fail("It should have thrown NotFoundException");
}
catch (NotFoundException expected) {
assertTrue(true);
Assert.assertTrue(true);
}
// and still grant access for CHANGE_GENERAL
try {
aclAuthorizationStrategy.securityCheck(aclNoACE, AclAuthorizationStrategy.CHANGE_GENERAL);
assertTrue(true);
Assert.assertTrue(true);
}
catch (NotFoundException expected) {
fail("It shouldn't have thrown NotFoundException");
Assert.fail("It shouldn't have thrown NotFoundException");
}
}
@Test
public void testSecurityCheckWithInheritableACEs() throws Exception {
// Create a simple authentication with ROLE_GENERAL
Authentication auth = new TestingAuthenticationToken("user", "password", "ROLE_GENERAL");
Authentication auth = new TestingAuthenticationToken("user", "password",
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_GENERAL") });
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, 100);
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
// Authorization strategy will require a different role for each access
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_ONE"), new SimpleGrantedAuthority("ROLE_TWO"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO"),
new GrantedAuthorityImpl("ROLE_GENERAL") });
// Let's give the principal an ADMINISTRATION permission, with granting
// access
MutableAcl parentAcl = new AclImpl(identity, 1, aclAuthorizationStrategy, new ConsoleAuditLogger());
MutableAcl parentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
parentAcl.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
MutableAcl childAcl = new AclImpl(identity, 2, aclAuthorizationStrategy, new ConsoleAuditLogger());
MutableAcl childAcl = new AclImpl(identity, new Long(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
// Check against the 'child' acl, which doesn't offer any authorization
// rights on CHANGE_OWNERSHIP
try {
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
fail("It should have thrown NotFoundException");
Assert.fail("It should have thrown NotFoundException");
}
catch (NotFoundException expected) {
assertTrue(true);
Assert.assertTrue(true);
}
// Link the child with its parent and test again against the
@@ -200,60 +198,63 @@ public class AclImplementationSecurityCheckTests {
childAcl.setEntriesInheriting(true);
try {
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
assertTrue(true);
Assert.assertTrue(true);
}
catch (NotFoundException expected) {
fail("It shouldn't have thrown NotFoundException");
Assert.fail("It shouldn't have thrown NotFoundException");
}
// Create a root parent and link it to the middle parent
MutableAcl rootParentAcl = new AclImpl(identity, 1, aclAuthorizationStrategy,
MutableAcl rootParentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy,
new ConsoleAuditLogger());
parentAcl = new AclImpl(identity, 1, aclAuthorizationStrategy, new ConsoleAuditLogger());
parentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
rootParentAcl.insertAce(0, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true);
parentAcl.setEntriesInheriting(true);
parentAcl.setParent(rootParentAcl);
childAcl.setParent(parentAcl);
try {
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
assertTrue(true);
Assert.assertTrue(true);
}
catch (NotFoundException expected) {
fail("It shouldn't have thrown NotFoundException");
Assert.fail("It shouldn't have thrown NotFoundException");
}
}
@SuppressWarnings("deprecation")
@Test
public void testSecurityCheckPrincipalOwner() throws Exception {
Authentication auth = new TestingAuthenticationToken("user", "password", "ROLE_ONE");
Authentication auth = new TestingAuthenticationToken("user", "password", new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_ONE"),
new GrantedAuthorityImpl("ROLE_ONE") });
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, 100);
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
new GrantedAuthorityImpl("ROLE_GENERAL") });
Acl acl = new AclImpl(identity, 1, aclAuthorizationStrategy, new ConsoleAuditLogger(), null, null,
Acl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger(), null, null,
false, new PrincipalSid(auth));
try {
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_GENERAL);
Assert.assertTrue(true);
}
catch (AccessDeniedException notExpected) {
fail("It shouldn't have thrown AccessDeniedException");
Assert.fail("It shouldn't have thrown AccessDeniedException");
}
try {
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_AUDITING);
fail("It shouldn't have thrown AccessDeniedException");
Assert.fail("It shouldn't have thrown AccessDeniedException");
}
catch (NotFoundException expected) {
Assert.assertTrue(true);
}
try {
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
Assert.assertTrue(true);
}
catch (AccessDeniedException notExpected) {
fail("It shouldn't have thrown AccessDeniedException");
Assert.fail("It shouldn't have thrown AccessDeniedException");
}
}
}
@@ -1,11 +1,13 @@
package org.springframework.security.acls.domain;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -19,17 +21,29 @@ import org.springframework.security.acls.model.AuditableAccessControlEntry;
*/
public class AuditLoggerTests {
//~ Instance fields ================================================================================================
private Mockery jmock = new JUnit4Mockery();
private PrintStream console;
private ByteArrayOutputStream bytes = new ByteArrayOutputStream();
private ConsoleAuditLogger logger;
private AuditableAccessControlEntry ace;
private Expectations aceRequiresAudit;
private Expectations aceDoesntRequireAudit;
//~ Methods ========================================================================================================
@Before
public void setUp() throws Exception {
logger = new ConsoleAuditLogger();
ace = mock(AuditableAccessControlEntry.class);
ace = jmock.mock(AuditableAccessControlEntry.class);
aceRequiresAudit = new Expectations() {{
allowing(ace).isAuditSuccess(); will(returnValue(true));
allowing(ace).isAuditFailure(); will(returnValue(true));
}};
aceDoesntRequireAudit = new Expectations() {{
allowing(ace).isAuditSuccess(); will(returnValue(false));
allowing(ace).isAuditFailure(); will(returnValue(false));
}};
console = System.out;
System.setOut(new PrintStream(bytes));
}
@@ -42,36 +56,35 @@ public class AuditLoggerTests {
@Test
public void nonAuditableAceIsIgnored() {
AccessControlEntry ace = mock(AccessControlEntry.class);
AccessControlEntry ace = jmock.mock(AccessControlEntry.class);
logger.logIfNeeded(true, ace);
assertEquals(0, bytes.size());
}
@Test
public void successIsNotLoggedIfAceDoesntRequireSuccessAudit() throws Exception {
when(ace.isAuditSuccess()).thenReturn(false);
jmock.checking(aceDoesntRequireAudit);
logger.logIfNeeded(true, ace);
assertEquals(0, bytes.size());
}
@Test
public void successIsLoggedIfAceRequiresSuccessAudit() throws Exception {
when(ace.isAuditSuccess()).thenReturn(true);
jmock.checking(aceRequiresAudit);
logger.logIfNeeded(true, ace);
assertTrue(bytes.toString().startsWith("GRANTED due to ACE"));
}
@Test
public void failureIsntLoggedIfAceDoesntRequireFailureAudit() throws Exception {
when(ace.isAuditFailure()).thenReturn(false);
jmock.checking(aceDoesntRequireAudit);
logger.logIfNeeded(false, ace);
assertEquals(0, bytes.size());
}
@Test
public void failureIsLoggedIfAceRequiresFailureAudit() throws Exception {
when(ace.isAuditFailure()).thenReturn(true);
jmock.checking(aceRequiresAudit);
logger.logIfNeeded(false, ace);
assertTrue(bytes.toString().startsWith("DENIED due to ACE"));
}
@@ -140,7 +140,7 @@ public class ObjectIdentityImplTests {
@Test
public void longAndIntegerIdsWithSameValueAreEqualAndHaveSameHashcode() {
ObjectIdentity obj = new ObjectIdentityImpl(Object.class, new Long(5));
ObjectIdentity obj2 = new ObjectIdentityImpl(Object.class, Integer.valueOf(5));
ObjectIdentity obj2 = new ObjectIdentityImpl(Object.class, new Integer(5));
assertEquals(obj, obj2);
assertEquals(obj.hashCode(), obj2.hashCode());
@@ -17,7 +17,7 @@ public class ObjectIdentityRetrievalStrategyImplTests extends TestCase {
public void testObjectIdentityCreation() throws Exception {
MockIdDomainObject domain = new MockIdDomainObject();
domain.setId(Integer.valueOf(1));
domain.setId(new Integer(1));
ObjectIdentityRetrievalStrategy retStrategy = new ObjectIdentityRetrievalStrategyImpl();
ObjectIdentity identity = retStrategy.getObjectIdentity(domain);
@@ -1,10 +1,19 @@
package org.springframework.security.acls.jdbc;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import junit.framework.Assert;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import org.junit.*;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -14,7 +23,6 @@ import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.domain.ConsoleAuditLogger;
import org.springframework.security.acls.domain.DefaultPermissionFactory;
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
import org.springframework.security.acls.domain.EhCacheBasedAclCache;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PrincipalSid;
@@ -25,11 +33,10 @@ import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.Sid;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.util.FileCopyUtils;
import java.util.*;
/**
* Tests {@link BasicLookupStrategy}
*
@@ -93,9 +100,10 @@ public class BasicLookupStrategyTests {
@Before
public void initializeBeans() {
EhCacheBasedAclCache cache = new EhCacheBasedAclCache(getCache());
AclAuthorizationStrategy authorizationStrategy = new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_ADMINISTRATOR"));
strategy = new BasicLookupStrategy(dataSource, cache, authorizationStrategy,
new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()));
AclAuthorizationStrategy authorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_ADMINISTRATOR"), new GrantedAuthorityImpl("ROLE_ADMINISTRATOR"),
new GrantedAuthorityImpl("ROLE_ADMINISTRATOR") });
strategy = new BasicLookupStrategy(dataSource, cache, authorizationStrategy, new ConsoleAuditLogger());
strategy.setPermissionFactory(new DefaultPermissionFactory());
}
@@ -120,7 +128,7 @@ public class BasicLookupStrategyTests {
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(101));
// Deliberately use an integer for the child, to reproduce bug report in SEC-819
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(102));
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Integer(102));
Map<ObjectIdentity, Acl> map = this.strategy.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
checkEntries(topParentOid, middleParentOid, childOid, map);
@@ -128,7 +136,7 @@ public class BasicLookupStrategyTests {
@Test
public void testAclsRetrievalFromCacheOnly() throws Exception {
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(100));
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Integer(100));
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(101));
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(102));
@@ -145,11 +153,11 @@ public class BasicLookupStrategyTests {
@Test
public void testAclsRetrievalWithCustomBatchSize() throws Exception {
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(101));
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Integer(101));
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(102));
// Set a batch size to allow multiple database queries in order to retrieve all acls
this.strategy.setBatchSize(1);
((BasicLookupStrategy) this.strategy).setBatchSize(1);
Map<ObjectIdentity, Acl> map = this.strategy.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
checkEntries(topParentOid, middleParentOid, childOid, map);
}
@@ -184,36 +192,36 @@ public class BasicLookupStrategyTests {
// Check each entry
Assert.assertTrue(topParent.isEntriesInheriting());
Assert.assertEquals(topParent.getId(), Long.valueOf(1));
Assert.assertEquals(topParent.getId(), new Long(1));
Assert.assertEquals(topParent.getOwner(), new PrincipalSid("ben"));
Assert.assertEquals(topParent.getEntries().get(0).getId(), Long.valueOf(1));
Assert.assertEquals(topParent.getEntries().get(0).getId(), new Long(1));
Assert.assertEquals(topParent.getEntries().get(0).getPermission(), BasePermission.READ);
Assert.assertEquals(topParent.getEntries().get(0).getSid(), new PrincipalSid("ben"));
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries().get(0)).isAuditFailure());
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries().get(0)).isAuditSuccess());
Assert.assertTrue((topParent.getEntries().get(0)).isGranting());
Assert.assertTrue(((AuditableAccessControlEntry) topParent.getEntries().get(0)).isGranting());
Assert.assertEquals(topParent.getEntries().get(1).getId(), Long.valueOf(2));
Assert.assertEquals(topParent.getEntries().get(1).getId(), new Long(2));
Assert.assertEquals(topParent.getEntries().get(1).getPermission(), BasePermission.WRITE);
Assert.assertEquals(topParent.getEntries().get(1).getSid(), new PrincipalSid("ben"));
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries().get(1)).isAuditFailure());
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries().get(1)).isAuditSuccess());
Assert.assertFalse(topParent.getEntries().get(1).isGranting());
Assert.assertFalse(((AuditableAccessControlEntry) topParent.getEntries().get(1)).isGranting());
Assert.assertTrue(middleParent.isEntriesInheriting());
Assert.assertEquals(middleParent.getId(), Long.valueOf(2));
Assert.assertEquals(middleParent.getId(), new Long(2));
Assert.assertEquals(middleParent.getOwner(), new PrincipalSid("ben"));
Assert.assertEquals(middleParent.getEntries().get(0).getId(), Long.valueOf(3));
Assert.assertEquals(middleParent.getEntries().get(0).getId(), new Long(3));
Assert.assertEquals(middleParent.getEntries().get(0).getPermission(), BasePermission.DELETE);
Assert.assertEquals(middleParent.getEntries().get(0).getSid(), new PrincipalSid("ben"));
Assert.assertFalse(((AuditableAccessControlEntry) middleParent.getEntries().get(0)).isAuditFailure());
Assert.assertFalse(((AuditableAccessControlEntry) middleParent.getEntries().get(0)).isAuditSuccess());
Assert.assertTrue(middleParent.getEntries().get(0).isGranting());
Assert.assertTrue(((AuditableAccessControlEntry) middleParent.getEntries().get(0)).isGranting());
Assert.assertTrue(child.isEntriesInheriting());
Assert.assertEquals(child.getId(), Long.valueOf(3));
Assert.assertEquals(child.getId(), new Long(3));
Assert.assertEquals(child.getOwner(), new PrincipalSid("ben"));
Assert.assertEquals(child.getEntries().get(0).getId(), Long.valueOf(4));
Assert.assertEquals(child.getEntries().get(0).getId(), new Long(4));
Assert.assertEquals(child.getEntries().get(0).getPermission(), BasePermission.DELETE);
Assert.assertEquals(child.getEntries().get(0).getSid(), new PrincipalSid("ben"));
Assert.assertFalse(((AuditableAccessControlEntry) child.getEntries().get(0)).isAuditFailure());
@@ -226,21 +234,21 @@ public class BasicLookupStrategyTests {
String query = "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (4,2,103,1,1,1);";
jdbcTemplate.execute(query);
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(100));
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(101));
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(102));
ObjectIdentity middleParent2Oid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(103));
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Integer(101));
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(102));
ObjectIdentity middleParent2Oid = new ObjectIdentityImpl(TARGET_CLASS, new Long(103));
// Retrieve the child
Map<ObjectIdentity, Acl> map = this.strategy.readAclsById(Arrays.asList(childOid), null);
// Check that the child and all its parents were retrieved
Assert.assertNotNull(map.get(childOid));
Assert.assertEquals(childOid, map.get(childOid).getObjectIdentity());
Assert.assertEquals(childOid, ((Acl) map.get(childOid)).getObjectIdentity());
Assert.assertNotNull(map.get(middleParentOid));
Assert.assertEquals(middleParentOid, map.get(middleParentOid).getObjectIdentity());
Assert.assertEquals(middleParentOid, ((Acl) map.get(middleParentOid)).getObjectIdentity());
Assert.assertNotNull(map.get(topParentOid));
Assert.assertEquals(topParentOid, map.get(topParentOid).getObjectIdentity());
Assert.assertEquals(topParentOid, ((Acl) map.get(topParentOid)).getObjectIdentity());
// The second parent shouldn't have been retrieved
Assert.assertNull(map.get(middleParent2Oid));
@@ -260,8 +268,8 @@ public class BasicLookupStrategyTests {
ObjectIdentity grandParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(104));
ObjectIdentity parent1Oid = new ObjectIdentityImpl(TARGET_CLASS, new Long(105));
ObjectIdentity parent2Oid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(106));
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(107));
ObjectIdentity parent2Oid = new ObjectIdentityImpl(TARGET_CLASS, new Integer(106));
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Integer(107));
// First lookup only child, thus populating the cache with grandParent, parent1 and child
List<Permission> checkPermission = Arrays.asList(BasePermission.READ);
@@ -271,7 +279,7 @@ public class BasicLookupStrategyTests {
strategy.setBatchSize(6);
Map<ObjectIdentity, Acl> foundAcls = strategy.readAclsById(childOids, sids);
Acl foundChildAcl = foundAcls.get(childOid);
Acl foundChildAcl = (Acl) foundAcls.get(childOid);
Assert.assertNotNull(foundChildAcl);
Assert.assertTrue(foundChildAcl.isGranted(checkPermission, sids, false));
@@ -285,7 +293,7 @@ public class BasicLookupStrategyTests {
Assert.fail("It shouldn't have thrown NotFoundException");
}
Acl foundParent2Acl = foundAcls.get(parent2Oid);
Acl foundParent2Acl = (Acl) foundAcls.get(parent2Oid);
Assert.assertNotNull(foundParent2Acl);
Assert.assertTrue(foundParent2Acl.isGranted(checkPermission, sids, false));
}
@@ -2,10 +2,22 @@ package org.springframework.security.acls.jdbc;
import static org.junit.Assert.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Map;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import org.junit.*;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
import org.springframework.security.acls.domain.AclImpl;
@@ -16,18 +28,11 @@ import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.util.FieldUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.*;
/**
* Tests {@link EhCacheBasedAclCache}
*
@@ -122,11 +127,11 @@ public class EhCacheBasedAclCacheTests {
// SEC-527
@Test
public void testDiskSerializationOfMutableAclObjectInstance() throws Exception {
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(100));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
MutableAcl acl = new AclImpl(identity, Long.valueOf(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
new GrantedAuthorityImpl("ROLE_GENERAL") });
MutableAcl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
// Serialization test
File file = File.createTempFile("SEC_TEST", ".object");
@@ -145,7 +150,7 @@ public class EhCacheBasedAclCacheTests {
Object retrieved1 = FieldUtils.getProtectedFieldValue("aclAuthorizationStrategy", retrieved);
assertEquals(null, retrieved1);
Object retrieved2 = FieldUtils.getProtectedFieldValue("permissionGrantingStrategy", retrieved);
Object retrieved2 = FieldUtils.getProtectedFieldValue("auditLogger", retrieved);
assertEquals(null, retrieved2);
}
@@ -154,11 +159,11 @@ public class EhCacheBasedAclCacheTests {
Ehcache cache = getCache();
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(100));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
MutableAcl acl = new AclImpl(identity, Long.valueOf(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
new GrantedAuthorityImpl("ROLE_GENERAL") });
MutableAcl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
assertEquals(0, cache.getDiskStoreSize());
myCache.putInCache(acl);
@@ -168,29 +173,29 @@ public class EhCacheBasedAclCacheTests {
assertFalse(cache.isElementInMemory(acl.getObjectIdentity()));
// Check we can get from cache the same objects we put in
assertEquals(myCache.getFromCache(Long.valueOf(1)), acl);
assertEquals(myCache.getFromCache(new Long(1)), acl);
assertEquals(myCache.getFromCache(identity), acl);
// Put another object in cache
ObjectIdentity identity2 = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(101));
MutableAcl acl2 = new AclImpl(identity2, Long.valueOf(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
ObjectIdentity identity2 = new ObjectIdentityImpl(TARGET_CLASS, new Long(101));
MutableAcl acl2 = new AclImpl(identity2, new Long(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
myCache.putInCache(acl2);
assertEquals(cache.getSize(), 4);
assertEquals(4, cache.getDiskStoreSize());
// Try to evict an entry that doesn't exist
myCache.evictFromCache(Long.valueOf(3));
myCache.evictFromCache(new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(102)));
myCache.evictFromCache(new Long(3));
myCache.evictFromCache(new ObjectIdentityImpl(TARGET_CLASS, new Long(102)));
assertEquals(cache.getSize(), 4);
assertEquals(4, cache.getDiskStoreSize());
myCache.evictFromCache(Long.valueOf(1));
myCache.evictFromCache(new Long(1));
assertEquals(cache.getSize(), 2);
assertEquals(2, cache.getDiskStoreSize());
// Check the second object inserted
assertEquals(myCache.getFromCache(Long.valueOf(2)), acl2);
assertEquals(myCache.getFromCache(new Long(2)), acl2);
assertEquals(myCache.getFromCache(identity2), acl2);
myCache.evictFromCache(identity2);
@@ -203,17 +208,18 @@ public class EhCacheBasedAclCacheTests {
Ehcache cache = getCache();
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
Authentication auth = new TestingAuthenticationToken("user", "password", "ROLE_GENERAL");
Authentication auth = new TestingAuthenticationToken("user", "password", new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_GENERAL") });
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(1));
ObjectIdentity identityParent = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(2));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
MutableAcl acl = new AclImpl(identity, Long.valueOf(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
MutableAcl parentAcl = new AclImpl(identityParent, Long.valueOf(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, new Long(1));
ObjectIdentity identityParent = new ObjectIdentityImpl(TARGET_CLASS, new Long(2));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"),
new GrantedAuthorityImpl("ROLE_GENERAL") });
MutableAcl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
MutableAcl parentAcl = new AclImpl(identityParent, new Long(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
acl.setParent(parentAcl);
@@ -234,17 +240,17 @@ public class EhCacheBasedAclCacheTests {
}
// Check we can get from cache the same objects we put in
AclImpl aclFromCache = (AclImpl) myCache.getFromCache(Long.valueOf(1));
AclImpl aclFromCache = (AclImpl) myCache.getFromCache(new Long(1));
// For the checks on transient fields, we need to be sure that the object is being loaded from the cache,
// not from the ehcache spool or elsewhere...
assertFalse(acl == aclFromCache);
assertEquals(acl, aclFromCache);
// SEC-951 check transient fields are set on parent
assertNotNull(FieldUtils.getFieldValue(aclFromCache.getParentAcl(), "aclAuthorizationStrategy"));
assertNotNull(FieldUtils.getFieldValue(aclFromCache.getParentAcl(), "permissionGrantingStrategy"));
assertNotNull(FieldUtils.getFieldValue(aclFromCache.getParentAcl(), "auditLogger"));
assertEquals(acl, myCache.getFromCache(identity));
assertNotNull(FieldUtils.getFieldValue(aclFromCache, "aclAuthorizationStrategy"));
AclImpl parentAclFromCache = (AclImpl) myCache.getFromCache(Long.valueOf(2));
AclImpl parentAclFromCache = (AclImpl) myCache.getFromCache(new Long(2));
assertEquals(parentAcl, parentAclFromCache);
assertNotNull(FieldUtils.getFieldValue(parentAclFromCache, "aclAuthorizationStrategy"));
assertEquals(parentAcl, myCache.getFromCache(identityParent));
@@ -4,7 +4,6 @@ import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import java.util.Collection;
import java.util.List;
import org.junit.Test;
@@ -54,8 +53,8 @@ public class SidRetrievalStrategyTests {
@Test
public void roleHierarchyIsUsedWhenSet() throws Exception {
RoleHierarchy rh = mock(RoleHierarchy.class);
List rhAuthorities = AuthorityUtils.createAuthorityList("D");
when(rh.getReachableGrantedAuthorities(anyCollection())).thenReturn(rhAuthorities);
List<GrantedAuthority> rhAuthorities = AuthorityUtils.createAuthorityList("D");
when(rh.getReachableGrantedAuthorities(anyList())).thenReturn(rhAuthorities);
SidRetrievalStrategy strat = new SidRetrievalStrategyImpl(rh);
List<Sid> sids = strat.getSids(authentication);
@@ -2,13 +2,14 @@ package org.springframework.security.acls.sid;
import junit.framework.Assert;
import junit.framework.TestCase;
import org.springframework.security.acls.domain.GrantedAuthoritySid;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.model.Sid;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
public class SidTests extends TestCase {
@@ -108,7 +109,7 @@ public class SidTests extends TestCase {
}
try {
GrantedAuthority ga = new SimpleGrantedAuthority(null);
GrantedAuthority ga = new GrantedAuthorityImpl(null);
new GrantedAuthoritySid(ga);
Assert.fail("It should have thrown IllegalArgumentException");
}
@@ -117,7 +118,7 @@ public class SidTests extends TestCase {
}
try {
GrantedAuthority ga = new SimpleGrantedAuthority("ROLE_TEST");
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
new GrantedAuthoritySid(ga);
Assert.assertTrue(true);
}
@@ -141,15 +142,15 @@ public class SidTests extends TestCase {
}
public void testGrantedAuthoritySidEquals() throws Exception {
GrantedAuthority ga = new SimpleGrantedAuthority("ROLE_TEST");
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
Sid gaSid = new GrantedAuthoritySid(ga);
Assert.assertFalse(gaSid.equals(null));
Assert.assertFalse(gaSid.equals("DIFFERENT_TYPE_OBJECT"));
Assert.assertTrue(gaSid.equals(gaSid));
Assert.assertTrue(gaSid.equals(new GrantedAuthoritySid(ga)));
Assert.assertTrue(gaSid.equals(new GrantedAuthoritySid(new SimpleGrantedAuthority("ROLE_TEST"))));
Assert.assertFalse(gaSid.equals(new GrantedAuthoritySid(new SimpleGrantedAuthority("ROLE_NOT_EQUAL"))));
Assert.assertTrue(gaSid.equals(new GrantedAuthoritySid(new GrantedAuthorityImpl("ROLE_TEST"))));
Assert.assertFalse(gaSid.equals(new GrantedAuthoritySid(new GrantedAuthorityImpl("ROLE_NOT_EQUAL"))));
Assert.assertTrue(gaSid.equals(new GrantedAuthoritySid("ROLE_TEST")));
Assert.assertFalse(gaSid.equals(new GrantedAuthoritySid("ROLE_NOT_EQUAL")));
}
@@ -158,26 +159,26 @@ public class SidTests extends TestCase {
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
Sid principalSid = new PrincipalSid(authentication);
Assert.assertTrue(principalSid.hashCode() == "johndoe".hashCode());
Assert.assertTrue(principalSid.hashCode() == new String("johndoe").hashCode());
Assert.assertTrue(principalSid.hashCode() == new PrincipalSid("johndoe").hashCode());
Assert.assertTrue(principalSid.hashCode() != new PrincipalSid("scott").hashCode());
Assert.assertTrue(principalSid.hashCode() != new PrincipalSid(new TestingAuthenticationToken("scott", "password")).hashCode());
}
public void testGrantedAuthoritySidHashCode() throws Exception {
GrantedAuthority ga = new SimpleGrantedAuthority("ROLE_TEST");
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
Sid gaSid = new GrantedAuthoritySid(ga);
Assert.assertTrue(gaSid.hashCode() == "ROLE_TEST".hashCode());
Assert.assertTrue(gaSid.hashCode() == new String("ROLE_TEST").hashCode());
Assert.assertTrue(gaSid.hashCode() == new GrantedAuthoritySid("ROLE_TEST").hashCode());
Assert.assertTrue(gaSid.hashCode() != new GrantedAuthoritySid("ROLE_TEST_2").hashCode());
Assert.assertTrue(gaSid.hashCode() != new GrantedAuthoritySid(new SimpleGrantedAuthority("ROLE_TEST_2")).hashCode());
Assert.assertTrue(gaSid.hashCode() != new GrantedAuthoritySid(new GrantedAuthorityImpl("ROLE_TEST_2")).hashCode());
}
public void testGetters() throws Exception {
Authentication authentication = new TestingAuthenticationToken("johndoe", "password");
PrincipalSid principalSid = new PrincipalSid(authentication);
GrantedAuthority ga = new SimpleGrantedAuthority("ROLE_TEST");
GrantedAuthority ga = new GrantedAuthorityImpl("ROLE_TEST");
GrantedAuthoritySid gaSid = new GrantedAuthoritySid(ga);
Assert.assertTrue("johndoe".equals(principalSid.getPrincipal()));
@@ -36,13 +36,13 @@
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
<constructor-arg value="ROLE_ADMINISTRATOR"/>
</bean>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
<constructor-arg value="ROLE_ADMINISTRATOR"/>
</bean>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
<constructor-arg value="ROLE_ADMINISTRATOR"/>
</bean>
</list>
-14
View File
@@ -1,14 +0,0 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.springframework.security" level="${sec.log.level}:-WARN"/>
<root level="${root.level}:-WARN">
<appender-ref ref="STDOUT" />
</root>
</configuration>
+13 -12
View File
@@ -5,18 +5,19 @@ Bundle-Name: Spring Security Acls
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.springframework.security.core.*;version="[${version}, 3.2.0)",
org.springframework.security.access.*;version="[${version}, 3.2.0)",
org.springframework.security.util.*;version="[${version}, 3.2.0)",
org.springframework.context.*;version="[${spring.version}, 3.2.0)";resolution:=optional,
org.springframework.dao.*;version="[${spring.version}, 3.2.0)";resolution:=optional,
org.springframework.jdbc.core.*;version="[${spring.version}, 3.2.0)";resolution:=optional,
org.springframework.transaction.support.*;version="[${spring.version}, 3.2.0)";resolution:=optional,
org.springframework.util.*;version="[${spring.version}, 3.2.0)";resolution:=optional,
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
Import-Template:
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
-2
View File
@@ -3,6 +3,4 @@ dependencies {
compile project(':spring-security-core'),
"org.springframework:spring-beans:$springVersion",
"org.springframework:spring-context:$springVersion"
testCompile 'aopalliance:aopalliance:1.0'
}
+61
View File
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-parent</artifactId>
<version>@pomVersion@</version>
</parent>
<packaging>jar</packaging>
<artifactId>spring-security-aspects</artifactId>
<name>Spring Security - Aspects</name>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>@pomVersion@</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.2</version>
<dependencies>
<!--
NB: You must use Maven 2.0.9 or above or these
are ignored (see MNG-2972)
-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.6.8</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -1,10 +1,6 @@
package org.springframework.security.access.intercept.aspectj.aspect;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.Before;
@@ -18,12 +14,8 @@ 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.ExpressionBasedPostInvocationAdvice;
import org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice;
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
import org.springframework.security.access.prepost.PostFilter;
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.prepost.PrePostAnnotationSecurityMetadataSource;
@@ -82,33 +74,15 @@ public class AnnotationSecurityAspectTests {
// SEC-1262
@Test(expected=AccessDeniedException.class)
public void denyAllPreAuthorizeDeniesAccess() throws Exception {
configureForElAnnotations();
SecurityContextHolder.getContext().setAuthentication(anne);
prePostSecured.denyAllMethod();
}
@Test
public void postFilterIsApplied() throws Exception {
configureForElAnnotations();
SecurityContextHolder.getContext().setAuthentication(anne);
List<String> objects = prePostSecured.postFilterMethod();
assertEquals(2, objects.size());
assertTrue(objects.contains("apple"));
assertTrue(objects.contains("aubergine"));
}
private void configureForElAnnotations() {
DefaultMethodSecurityExpressionHandler eh = new DefaultMethodSecurityExpressionHandler();
interceptor.setSecurityMetadataSource(new PrePostAnnotationSecurityMetadataSource(
new ExpressionBasedAnnotationAttributeFactory(eh)));
new ExpressionBasedAnnotationAttributeFactory(new DefaultMethodSecurityExpressionHandler())));
AffirmativeBased adm = new AffirmativeBased();
AccessDecisionVoter[] voters = new AccessDecisionVoter[]
{new PreInvocationAuthorizationAdviceVoter(new ExpressionBasedPreInvocationAdvice())};
adm.setDecisionVoters(Arrays.asList(voters));
interceptor.setAccessDecisionManager(adm);
AfterInvocationProviderManager aim = new AfterInvocationProviderManager();
aim.setProviders(Arrays.asList(new PostInvocationAdviceProvider(new ExpressionBasedPostInvocationAdvice(eh))));
interceptor.setAfterInvocationManager(aim);
prePostSecured.denyAllMethod();
}
}
@@ -118,6 +92,7 @@ interface SecuredInterface {
}
class SecuredImpl implements SecuredInterface {
// Not really secured because AspectJ doesn't inherit annotations from interfaces
public void securedMethod() {
}
@@ -128,14 +103,8 @@ class SecuredImpl implements SecuredInterface {
}
class PrePostSecured {
@PreAuthorize("denyAll")
public void denyAllMethod() {
}
@PostFilter("filterObject.startsWith('a')")
public List<String> postFilterMethod() {
ArrayList<String> objects = new ArrayList<String>();
objects.addAll(Arrays.asList(new String[] {"apple", "banana", "aubergine", "orange"}));
return objects;
}
}
+5 -3
View File
@@ -9,6 +9,8 @@ Ignored-Existing-Headers:
Import-Package,
Export-Package
Import-Template:
org.aspectj.*;version="[1.6.0, 1.7.0)";resolution:=optional,
org.apache.commons.logging.*;version="[1.0.4, 2.0.0)",
org.springframework.security.core.*;version="[${version}, 3.2.0)"
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}"
+38 -59
View File
@@ -1,40 +1,34 @@
apply plugin: 'base'
description = 'Spring Security'
allprojects {
version = '3.1.0.M2'
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://" + System.properties['user.home'] + "/.m2/repository"
mavenCentral()
mavenRepo name: 'SpringSource Milestone Repo', urls: 'http://repository.springsource.com/maven/bundles/milestone'
mavenRepo name: 'SpringSource Maven Snapshot Repo', urls: 'http://maven.springframework.org/snapshot/'
mavenRepo name: 'SpringSource Enterprise Release', urls: 'http://repository.springsource.com/maven/bundles/release'
mavenRepo name: 'SpringSource Enterprise External', urls: 'http://repository.springsource.com/maven/bundles/external'
// mavenRepo(name: 'Spock Snapshots', urls: 'http://m2repo.spockframework.org/snapshots')
}
}
// Set up different subproject lists for individual configuration
javaProjects = subprojects.findAll { project -> project.name != 'docs' && project.name != 'faq' && project.name != 'manual' }
sampleProjects = subprojects.findAll { project -> project.name.startsWith('spring-security-samples') }
itestProjects = subprojects.findAll { project -> project.name.startsWith('itest') }
coreModuleProjects = javaProjects - sampleProjects - itestProjects
aspectjProjects = [project(':spring-security-aspects'), project(':spring-security-samples-aspectj')]
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(coreModuleProjects) {
apply from: "$rootDir/gradle/bundlor.gradle"
apply from: "$rootDir/gradle/maven-deployment.gradle"
apply from: "$rootDir/gradle/emma.gradle"
// 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'
}
task coreBuild {
@@ -42,55 +36,40 @@ task coreBuild {
}
configure (aspectjProjects) {
apply from: "$rootDir/gradle/aspectj.gradle"
apply plugin: 'aspectj'
}
apply from: "$rootDir/gradle/dist.gradle"
// Task for creating the distro zip
apply plugin: 'idea'
configure(javaProjects) {
apply plugin: 'idea'
apply plugin: 'eclipse'
ideaModule {
downloadJavadoc=false
excludeDirs.add(buildDir)
gradleCacheVariable = 'GRADLE_CACHE'
outputDir = "$rootProject.projectDir/intellij/out" as File
testOutputDir = "$rootProject.projectDir/intellij/testOut" as File
whenConfigured { module ->
def allClasses = module.dependencies.findAll() { dep ->
if (dep instanceof org.gradle.plugins.idea.model.ModuleLibrary
&& dep.classes.find { path ->
path.url.matches('.*jcl-over-slf4j.*') ||
path.url.matches('.*servlet-api.*') ||
path.url.matches('.*jsp-api.*')
}) {
dep.scope = 'COMPILE'
dep.exported = false
}
}
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) {
from(rootDir) {
include '*.txt'
}
into('docs') {
with(project(':docs').apiSpec)
with(project(':docs:manual').spec)
}
into('dist') {
from coreModuleProjects.collect {project -> project.libsDir }
from project(':spring-security-samples-tutorial').libsDir
from project(':spring-security-samples-contacts').libsDir
}
}
}
ideaModule {
excludeDirs += file('.gradle')
excludeDirs += file('buildSrc/build')
excludeDirs += file('buildSrc/.gradle')
artifacts {
archives dist
archives project(':docs').docsZip
archives project(':docs').schemaZip
}
ideaProject {
javaVersion = '1.6'
subprojects = [rootProject] + javaProjects
withXml { node ->
// Use git
def vcsConfig = node.component.find { it.'@name' == 'VcsDirectoryMappings' }
vcsConfig.mapping[0].'@vcs' = 'Git'
}
}
apply from: "$rootDir/gradle/ide-integration.gradle"
task wrapper(type: Wrapper) {
gradleVersion = '0.9'
gradleVersion = '1.1'
}
+22 -6
View File
@@ -1,10 +1,15 @@
apply plugin: 'groovy'
repositories {
mavenRepo name:'localRepo', urls: "file://" + System.properties['user.home'] + "/.m2/repository"
mavenCentral()
mavenRepo name: 'GAE', urls:'http://maven-gae-plugin.googlecode.com/svn/repository'
mavenRepo name:'Shibboleth Repo', urls:'http://shibboleth.internet2.edu/downloads/maven2'
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
@@ -19,9 +24,10 @@ dependencies {
'org.apache.avalon.framework:avalon-framework-api:4.3.1']
groovy localGroovy()
compile gradleApi(),
'org.apache.xerces:resolver:2.9.1',
'org.apache.xerces:xercesImpl:2.9.1',
'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',
@@ -30,7 +36,17 @@ dependencies {
// GAE
dependencies {
compile 'com.google.appengine:appengine-tools-api:1.3.7'
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) {
-75
View File
@@ -1,75 +0,0 @@
import org.gradle.api.DefaultTask;
import org.gradle.api.tasks.*;
import org.gradle.api.tasks.bundling.Tar;
import org.gradle.api.tasks.bundling.Compression;
/**
* Extends the Tar task, uploading the created archive to a remote directory, unpacking and deleting it.
* Requires Ant ssh (jsch) support.
*/
class TarUpload extends Tar {
@Input
String remoteDir
Login login
@Input
String host
TarUpload() {
compression = Compression.BZIP2
if (project.configurations.findByName('antjsch') == null) {
project.configurations.add('antjsch')
project.dependencies {
antjsch 'org.apache.ant:ant-jsch:1.8.1'
}
def classpath = project.configurations.antjsch.asPath
project.ant {
taskdef(name: 'scp', classname: 'org.apache.tools.ant.taskdefs.optional.ssh.Scp', classpath: classpath)
taskdef(name: 'sshexec', classname: 'org.apache.tools.ant.taskdefs.optional.ssh.SSHExec', classpath: classpath)
}
}
}
@TaskAction
void copy() {
super.copy();
upload();
}
def upload() {
String username = login.username
String password = login.password
String host = login.host
project.ant {
scp(file: archivePath, todir: "$username@$host:$remoteDir", password: password)
sshexec(host: host, username: username, password: password, command: "cd $remoteDir && tar -xjf $archiveName")
sshexec(host: host, username: username, password: password, command: "rm $remoteDir/$archiveName")
}
}
void setLogin(Login login) {
dependsOn(login)
this.login = login
this.host = login.host
}
}
/**
* Stores login information for a remote host.
*/
class Login extends DefaultTask {
@Input
String host
String username
String password
@TaskAction
login() {
def console = System.console()
if (console) {
username = console.readLine("\nPlease enter the ssh username for host '$host': ")
password = new String(console.readPassword("Please enter the ssh password for '$host': "))
} else {
logger.error "Unable to access System.console()."
}
}
}
@@ -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)
}
}
@@ -92,7 +92,7 @@ public class Docbook extends DefaultTask {
factory.setXIncludeAware(XIncludeAware);
docsDir.mkdirs();
File srcFile = new File(sourceDirectory, sourceFileName);
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);
@@ -135,6 +135,32 @@ public class Docbook extends DefaultTask {
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();
@@ -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 @@
implementation-class=aspectj.AspectJPlugin
@@ -0,0 +1 @@
implementation-class=bundlor.BundlorPlugin
@@ -0,0 +1 @@
implementation-class=emma.EmmaPlugin
+3 -2
View File
@@ -4,9 +4,10 @@ dependencies {
project(':spring-security-web'),
"org.springframework:spring-context:$springVersion",
"org.springframework:spring-beans:$springVersion",
"org.springframework:spring-tx:$springVersion",
"org.springframework:spring-web:$springVersion",
"org.jasig.cas.client:cas-client-core:3.1.11",
"org.jasig.cas:cas-client-core:3.1.9",
"net.sf.ehcache:ehcache:$ehcacheVersion"
provided 'javax.servlet:servlet-api:2.5'
}
}
+55
View File
@@ -0,0 +1,55 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-parent</artifactId>
<version>@pomVersion@</version>
</parent>
<artifactId>spring-security-cas-client</artifactId>
<name>Spring Security - CAS support</name>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jasig.cas</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.1.10</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -31,8 +31,6 @@ import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
import org.springframework.security.core.userdetails.*;
import org.springframework.util.Assert;
@@ -53,16 +51,14 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
//~ Instance fields ================================================================================================
private AuthenticationUserDetailsService<CasAssertionAuthenticationToken> authenticationUserDetailsService;
private AuthenticationUserDetailsService authenticationUserDetailsService;
private final UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
private UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
private StatelessTicketCache statelessTicketCache = new NullStatelessTicketCache();
private String key;
private TicketValidator ticketValidator;
private ServiceProperties serviceProperties;
private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
//~ Methods ========================================================================================================
@@ -135,8 +131,7 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
final Assertion assertion = this.ticketValidator.validate(authentication.getCredentials().toString(), serviceProperties.getService());
final UserDetails userDetails = loadUserByAssertion(assertion);
userDetailsChecker.check(userDetails);
return new CasAuthenticationToken(this.key, userDetails, authentication.getCredentials(),
authoritiesMapper.mapAuthorities(userDetails.getAuthorities()), userDetails, assertion);
return new CasAuthenticationToken(this.key, userDetails, authentication.getCredentials(), userDetails.getAuthorities(), userDetails, assertion);
} catch (final TicketValidationException e) {
throw new BadCredentialsException(e.getMessage(), e);
}
@@ -155,7 +150,6 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
}
@Deprecated
@SuppressWarnings("unchecked")
/**
* @deprecated as of 3.0. Use the {@link org.springframework.security.cas.authentication.CasAuthenticationProvider#setAuthenticationUserDetailsService(org.springframework.security.core.userdetails.AuthenticationUserDetailsService)} instead.
*/
@@ -163,7 +157,7 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
this.authenticationUserDetailsService = new UserDetailsByNameServiceWrapper(userDetailsService);
}
public void setAuthenticationUserDetailsService(final AuthenticationUserDetailsService<CasAssertionAuthenticationToken> authenticationUserDetailsService) {
public void setAuthenticationUserDetailsService(final AuthenticationUserDetailsService authenticationUserDetailsService) {
this.authenticationUserDetailsService = authenticationUserDetailsService;
}
@@ -199,11 +193,7 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
this.ticketValidator = ticketValidator;
}
public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
this.authoritiesMapper = authoritiesMapper;
}
public boolean supports(final Class<?> authentication) {
public boolean supports(final Class<? extends Object> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)) ||
(CasAuthenticationToken.class.isAssignableFrom(authentication)) ||
(CasAssertionAuthenticationToken.class.isAssignableFrom(authentication));
@@ -15,17 +15,23 @@
package org.springframework.security.cas.authentication;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.Element;
import net.sf.ehcache.Ehcache;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.util.Assert;
/**
* Caches tickets using a Spring IoC defined <a href="http://ehcache.sourceforge.net">EHCACHE</a>.
* Caches tickets using a Spring IoC defined <A HREF="http://ehcache.sourceforge.net">EHCACHE</a>.
*
* @author Ben Alex
*/
@@ -45,13 +51,18 @@ public class EhCacheBasedTicketCache implements StatelessTicketCache, Initializi
}
public CasAuthenticationToken getByTicketId(final String serviceTicket) {
final Element element = cache.get(serviceTicket);
try {
final Element element = cache.get(serviceTicket);
if (logger.isDebugEnabled()) {
logger.debug("Cache hit: " + (element != null) + "; service ticket: " + serviceTicket);
if (logger.isDebugEnabled()) {
logger.debug("Cache hit: " + (element != null) + "; service ticket: " + serviceTicket);
}
return element == null ? null : (CasAuthenticationToken) element.getValue();
} catch (CacheException cacheException) {
throw new DataRetrievalFailureException("Cache failure: " + cacheException.getMessage());
}
return element == null ? null : (CasAuthenticationToken) element.getValue();
}
public Ehcache getCache() {
@@ -14,10 +14,13 @@
*/
package org.springframework.security.cas.userdetails;
import org.jasig.cas.client.validation.Assertion;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.core.Authentication;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.springframework.util.Assert;
import org.jasig.cas.client.validation.Assertion;
/**
* Abstract class for using the provided CAS assertion to construct a new User object. This generally is most
@@ -26,11 +29,11 @@ import org.springframework.security.core.userdetails.UserDetails;
* @author Scott Battaglia
* @since 3.0
*/
public abstract class AbstractCasAssertionUserDetailsService
implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken> {
public abstract class AbstractCasAssertionUserDetailsService implements AuthenticationUserDetailsService {
public final UserDetails loadUserDetails(final CasAssertionAuthenticationToken token) {
return loadUserDetails(token.getAssertion());
public final UserDetails loadUserDetails(final Authentication token) throws UsernameNotFoundException {
Assert.isInstanceOf(CasAssertionAuthenticationToken.class, token, "The provided token MUST be an instance of CasAssertionAuthenticationToken.class");
return loadUserDetails(((CasAssertionAuthenticationToken) token).getAssertion());
}
/**
@@ -17,7 +17,7 @@ package org.springframework.security.cas.userdetails;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.util.Assert;
import org.jasig.cas.client.validation.Assertion;
@@ -36,7 +36,7 @@ public final class GrantedAuthorityFromAssertionAttributesUserDetailsService ext
private static final String NON_EXISTENT_PASSWORD_VALUE = "NO_PASSWORD";
private final String[] attributes;
private String[] attributes;
private boolean convertToUpperCase = true;
@@ -62,11 +62,11 @@ public final class GrantedAuthorityFromAssertionAttributesUserDetailsService ext
final List list = (List) value;
for (final Object o : list) {
grantedAuthorities.add(new SimpleGrantedAuthority(this.convertToUpperCase ? o.toString().toUpperCase() : o.toString()));
grantedAuthorities.add(new GrantedAuthorityImpl(this.convertToUpperCase ? o.toString().toUpperCase() : o.toString()));
}
} else {
grantedAuthorities.add(new SimpleGrantedAuthority(this.convertToUpperCase ? value.toString().toUpperCase() : value.toString()));
grantedAuthorities.add(new GrantedAuthorityImpl(this.convertToUpperCase ? value.toString().toUpperCase() : value.toString()));
}
}
@@ -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);
}
}
@@ -18,26 +18,28 @@ package org.springframework.security.cas.authentication;
import static org.junit.Assert.*;
import java.util.HashMap;
import java.util.Map;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.AssertionImpl;
import org.jasig.cas.client.validation.TicketValidationException;
import org.jasig.cas.client.validation.TicketValidator;
import org.junit.*;
import org.junit.Test;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import java.util.*;
/**
* Tests {@link CasAuthenticationProvider}.
@@ -45,7 +47,6 @@ import java.util.*;
* @author Ben Alex
* @author Scott Battaglia
*/
@SuppressWarnings("unchecked")
public class CasAuthenticationProviderTests {
//~ Methods ========================================================================================================
@@ -96,8 +97,8 @@ public class CasAuthenticationProviderTests {
CasAuthenticationToken casResult = (CasAuthenticationToken) result;
assertEquals(makeUserDetailsFromAuthoritiesPopulator(), casResult.getPrincipal());
assertEquals("ST-123", casResult.getCredentials());
assertTrue(casResult.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_A")));
assertTrue(casResult.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_B")));
assertTrue(casResult.getAuthorities().contains(new GrantedAuthorityImpl("ROLE_A")));
assertTrue(casResult.getAuthorities().contains(new GrantedAuthorityImpl("ROLE_B")));
assertEquals(cap.getKey().hashCode(), casResult.getKeyHash());
assertEquals("details", casResult.getDetails());
@@ -254,7 +255,8 @@ public class CasAuthenticationProviderTests {
cap.setServiceProperties(makeServiceProperties());
cap.afterPropertiesSet();
TestingAuthenticationToken token = new TestingAuthenticationToken("user", "password", "ROLE_A");
TestingAuthenticationToken token = new TestingAuthenticationToken("user", "password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_A")});
assertFalse(cap.supports(TestingAuthenticationToken.class));
// Try it anyway
@@ -15,18 +15,19 @@
package org.springframework.security.cas.authentication;
import java.util.List;
import junit.framework.TestCase;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.AssertionImpl;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.*;
/**
* Tests {@link CasAuthenticationToken}.
*
@@ -107,8 +108,8 @@ public class CasAuthenticationTokenTests extends TestCase {
assertEquals("key".hashCode(), token.getKeyHash());
assertEquals(makeUserDetails(), token.getPrincipal());
assertEquals("Password", token.getCredentials());
assertTrue(token.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_ONE")));
assertTrue(token.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_TWO")));
assertTrue(token.getAuthorities().contains(new GrantedAuthorityImpl("ROLE_ONE")));
assertTrue(token.getAuthorities().contains(new GrantedAuthorityImpl("ROLE_TWO")));
assertEquals(assertion, token.getAssertion());
assertEquals(makeUserDetails().getUsername(), token.getUserDetails().getUsername());
}
@@ -1,49 +0,0 @@
package org.springframework.security.cas.userdetails;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.validation.Assertion;
import org.junit.Test;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @author Luke Taylor
*/
public class GrantedAuthorityFromAssertionAttributesUserDetailsServiceTests {
@Test
public void correctlyExtractsNamedAttributesFromAssertionAndConvertsThemToAuthorities() {
GrantedAuthorityFromAssertionAttributesUserDetailsService uds =
new GrantedAuthorityFromAssertionAttributesUserDetailsService(new String[] {"a", "b", "c", "d"});
uds.setConvertToUpperCase(false);
Assertion assertion = mock(Assertion.class);
AttributePrincipal principal = mock(AttributePrincipal.class);
Map<String, Object> attributes = new HashMap<String, Object>();
attributes.put("a", Arrays.asList("role_a1", "role_a2"));
attributes.put("b", "role_b");
attributes.put("c", "role_c");
attributes.put("d", null);
attributes.put("someother", "unused");
when(assertion.getPrincipal()).thenReturn(principal);
when(principal.getAttributes()).thenReturn(attributes);
when(principal.getName()).thenReturn("somebody");
CasAssertionAuthenticationToken token = new CasAssertionAuthenticationToken(assertion, "ticket");
UserDetails user = uds.loadUserDetails(token);
Set<String> roles = AuthorityUtils.authorityListToSet(user.getAuthorities());
assertTrue(roles.size() == 4);
assertTrue(roles.contains("role_a1"));
assertTrue(roles.contains("role_a2"));
assertTrue(roles.contains("role_b"));
assertTrue(roles.contains("role_c"));
}
}
@@ -16,7 +16,9 @@
package org.springframework.security.cas.web;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.*;
import javax.servlet.FilterChain;
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
import org.junit.Test;
@@ -24,7 +26,6 @@ import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
@@ -33,22 +34,20 @@ import org.springframework.security.core.AuthenticationException;
* Tests {@link CasAuthenticationFilter}.
*
* @author Ben Alex
* @author Rob Winch
*/
public class CasAuthenticationFilterTests {
//~ Methods ========================================================================================================
@Test
public void testGettersSetters() {
public void testGetters() {
CasAuthenticationFilter filter = new CasAuthenticationFilter();
assertEquals("/j_spring_cas_security_check", filter.getFilterProcessesUrl());
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
filter.setProxyReceptorUrl("/someurl");
filter.setServiceProperties(new ServiceProperties());
}
@Test
public void testNormalOperation() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/j_spring_cas_security_check");
MockHttpServletRequest request = new MockHttpServletRequest();
request.addParameter("ticket", "ST-0-ER94xMJmn6pha35CQRoZ");
CasAuthenticationFilter filter = new CasAuthenticationFilter();
@@ -58,8 +57,6 @@ public class CasAuthenticationFilterTests {
}
});
assertTrue(filter.requiresAuthentication(request, new MockHttpServletResponse()));
Authentication result = filter.attemptAuthentication(request, new MockHttpServletResponse());
assertTrue(result != null);
}
@@ -75,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);
}
}
@@ -15,43 +15,40 @@
package org.springframework.security.cas.web;
import static junit.framework.Assert.*;
import org.junit.Test;
import org.springframework.security.cas.SamlServiceProperties;
import org.springframework.security.cas.ServiceProperties;
import junit.framework.TestCase;
/**
* Tests {@link ServiceProperties}.
*
* @author Ben Alex
*/
public class ServicePropertiesTests {
public class ServicePropertiesTests extends TestCase {
//~ Methods ========================================================================================================
@Test(expected=IllegalArgumentException.class)
public void detectsMissingService() throws Exception {
public void testDetectsMissingLoginFormUrl() throws Exception {
ServiceProperties sp = new ServiceProperties();
sp.afterPropertiesSet();
}
@Test
public void testGettersSetters() throws Exception {
ServiceProperties[] sps = {new ServiceProperties(), new SamlServiceProperties()};
for(ServiceProperties sp : sps) {
sp.setSendRenew(false);
assertFalse(sp.isSendRenew());
sp.setSendRenew(true);
assertTrue(sp.isSendRenew());
sp.setArtifactParameter("notticket");
assertEquals("notticket", sp.getArtifactParameter());
sp.setServiceParameter("notservice");
assertEquals("notservice", sp.getServiceParameter());
sp.setService("https://mycompany.com/service");
assertEquals("https://mycompany.com/service", sp.getService());
try {
sp.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertEquals("service must be specified.", expected.getMessage());
}
}
public void testGettersSetters() throws Exception {
ServiceProperties sp = new ServiceProperties();
sp.setSendRenew(false);
assertFalse(sp.isSendRenew());
sp.setSendRenew(true);
assertTrue(sp.isSendRenew());
sp.setService("https://mycompany.com/service");
assertEquals("https://mycompany.com/service", sp.getService());
sp.afterPropertiesSet();
}
}
+10 -10
View File
@@ -9,14 +9,14 @@ 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.0)",
org.springframework.security.core.*;version="[${version}, 3.2.0)",
org.springframework.security.authentication.*;version="[${version}, 3.2.0)",
org.springframework.security.web.*;version="[${version}, 3.2.0)",
org.springframework.beans.factory;version="[${spring.version}, 3.2.0)",
org.springframework.context.*;version="[${spring.version}, 3.2.0)",
org.springframework.dao;version="[${spring.version}, 3.2.0)",
org.springframework.util;version="[${spring.version}, 3.2.0)",
net.sf.ehcache.*;version="[1.4.1, 2.0.0)";resolution:=optional,
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"
+12 -28
View File
@@ -1,55 +1,39 @@
// Config Module build file
apply plugin: 'groovy'
compileTestJava.dependsOn(':spring-security-core:compileTestJava')
configurations {
// GRADLE-1124
compile.extendsFrom = []
testCompile.extendsFrom groovy
}
dependencies {
compile project(':spring-security-core'),
project(':spring-security-web'),
"org.aspectj:aspectjweaver:$aspectjVersion",
'aopalliance:aopalliance:1.0',
"org.aspectj:aspectjweaver:$aspectjVersion",
"org.springframework:spring-aop:$springVersion",
"org.springframework:spring-context:$springVersion",
"org.springframework:spring-web:$springVersion",
"org.springframework:spring-beans:$springVersion"
"org.springframework:spring-beans:$springVersion",
"org.springframework:spring-tx:$springVersion"
provided "javax.servlet:servlet-api:2.5"
groovy group: 'org.codehaus.groovy', name: 'groovy', version: '1.7.4'
testCompile project(':spring-security-ldap'),
project(':spring-security-openid'),
'org.openid4java:openid4java-nodeps:0.9.5',
project(':spring-security-core').sourceSets.test.classes,
project(':spring-security-core').sourceSets.test.output,
'javax.annotation:jsr250-api:1.0',
"org.springframework.ldap:spring-ldap-core:$springLdapVersion",
"org.springframework:spring-expression:$springVersion",
"org.springframework:spring-jdbc:$springVersion",
"org.springframework:spring-tx:$springVersion",
'org.spockframework:spock-core:0.4-groovy-1.7',
'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 ldapTests(type: Test) {
jvmArgs = ['-ea', '-Xmx500m', "-DapacheDSWorkDir=${buildDir}/apacheDSWork"]
include ("**/ldap/**")
maxParallelForks = 1
// GRADLE-1090
testClassesDir = sourceSets.test.classesDir
classpath = sourceSets.test.runtimeClasspath
testReport = false
}
test {
dependsOn ldapTests
exclude ("**/ldap/**")
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.1.rnc spring-security-3.1.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.1.xsd spring-security.xsl spring-security-3.1.xsd
xsltproc --output spring-security-3.0.4.xsd spring-security.xsl spring-security-3.0.4.xsd
popd
+113
View File
@@ -0,0 +1,113 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-parent</artifactId>
<version>@pomVersion@</version>
</parent>
<packaging>jar</packaging>
<artifactId>spring-security-config</artifactId>
<name>Spring Security - Namespace Configuration Module</name>
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${project.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${project.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${project.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-openid</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.directory.server</groupId>
<artifactId>apacheds-core</artifactId>
<version>1.5.5</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.directory.server</groupId>
<artifactId>apacheds-server-jndi</artifactId>
<version>1.5.5</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,151 @@
package org.springframework.security.config.ldap;
import static org.junit.Assert.*;
import static org.springframework.security.config.ldap.LdapProviderBeanDefinitionParser.*;
import org.junit.After;
import org.junit.Test;
import org.springframework.context.ApplicationContextException;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.core.Authentication;
import org.springframework.security.ldap.authentication.BindAuthenticator;
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
import org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator;
import org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper;
import org.springframework.security.ldap.userdetails.LdapUserDetailsImpl;
import org.springframework.security.util.FieldUtils;
/**
* @author Luke Taylor
*/
public class LdapProviderBeanDefinitionParserTests {
InMemoryXmlApplicationContext appCtx;
@After
public void closeAppContext() {
if (appCtx != null) {
appCtx.close();
appCtx = null;
}
}
@Test
public void beanClassNamesAreCorrect() throws Exception {
assertEquals(PROVIDER_CLASS, LdapAuthenticationProvider.class.getName());
assertEquals(BIND_AUTH_CLASS, BindAuthenticator.class.getName());
assertEquals(PASSWD_AUTH_CLASS, PasswordComparisonAuthenticator.class.getName());
}
// SEC-1182
@Test
public void multipleProvidersAreSupported() throws Exception {
setContext("<ldap-server url='ldap://blah:389/dc=blah'/>" +
"<authentication-manager>" +
" <ldap-authentication-provider group-search-filter='member={0}' />" +
" <ldap-authentication-provider group-search-filter='uniqueMember={0}' />" +
"</authentication-manager>");
ProviderManager authManager = (ProviderManager) appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER);
assertEquals(2, authManager.getProviders().size());
assertEquals("member={0}", FieldUtils.getFieldValue(authManager.getProviders().get(0), "authoritiesPopulator.groupSearchFilter"));
assertEquals("uniqueMember={0}", FieldUtils.getFieldValue(authManager.getProviders().get(1), "authoritiesPopulator.groupSearchFilter"));
}
@Test
public void simpleProviderAuthenticatesCorrectly() {
setContext("<ldap-server />" +
"<authentication-manager>" +
" <ldap-authentication-provider group-search-filter='member={0}' />" +
"</authentication-manager>");
LdapAuthenticationProvider provider = getProvider();
Authentication auth = provider.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
LdapUserDetailsImpl ben = (LdapUserDetailsImpl) auth.getPrincipal();
assertEquals(3, ben.getAuthorities().size());
}
@Test(expected = ApplicationContextException.class)
public void missingServerEltCausesConfigException() {
setContext(
"<authentication-manager>" +
" <ldap-authentication-provider />" +
"</authentication-manager>");
}
@Test
public void supportsPasswordComparisonAuthentication() {
setContext("<ldap-server /> " +
"<authentication-manager>" +
"<ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>" +
" <password-compare />" +
"</ldap-authentication-provider>"+
"</authentication-manager>");
LdapAuthenticationProvider provider = getProvider();
provider.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
}
@Test
public void supportsPasswordComparisonAuthenticationWithHashAttribute() {
setContext("<ldap-server /> " +
"<authentication-manager>" +
"<ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>" +
" <password-compare password-attribute='uid' hash='plaintext'/>" +
"</ldap-authentication-provider>" +
"</authentication-manager>");
LdapAuthenticationProvider provider = getProvider();
provider.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"));
}
@Test
public void supportsPasswordComparisonAuthenticationWithPasswordEncoder() {
setContext("<ldap-server /> " +
"<authentication-manager>" +
"<ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>" +
" <password-compare password-attribute='uid'>" +
" <password-encoder hash='plaintext'/>" +
" </password-compare>" +
"</ldap-authentication-provider>" +
"</authentication-manager>");
LdapAuthenticationProvider provider = getProvider();
provider.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"));
}
@Test
public void detectsNonStandardServerId() {
setContext("<ldap-server id='myServer'/> " +
"<authentication-manager>" +
" <ldap-authentication-provider />" +
"</authentication-manager>");
}
@Test
public void inetOrgContextMapperIsSupported() throws Exception {
setContext(
"<ldap-server id='someServer' url='ldap://127.0.0.1:343/dc=springframework,dc=org'/>" +
"<authentication-manager>" +
" <ldap-authentication-provider user-details-class='inetOrgPerson'/>" +
"</authentication-manager>");
LdapAuthenticationProvider provider = getProvider();
assertTrue(FieldUtils.getFieldValue(provider, "userDetailsContextMapper") instanceof InetOrgPersonContextMapper);
}
private void setContext(String context) {
appCtx = new InMemoryXmlApplicationContext(context);
}
private LdapAuthenticationProvider getProvider() {
ProviderManager authManager = (ProviderManager) appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER);
assertEquals(1, authManager.getProviders().size());
LdapAuthenticationProvider provider = (LdapAuthenticationProvider) authManager.getProviders().get(0);
return provider;
}
}
@@ -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,3 +1,15 @@
/*
* 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.*;
@@ -23,6 +35,7 @@ import java.util.*;
/**
* @author Luke Taylor
* @author Rob Winch
*/
public class LdapUserServiceBeanDefinitionParserTests {
private InMemoryXmlApplicationContext appCtx;
@@ -47,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");
@@ -67,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");
@@ -83,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");
@@ -98,7 +111,7 @@ 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");
@@ -112,7 +125,7 @@ public class LdapUserServiceBeanDefinitionParserTests {
@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})' />" +
@@ -123,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");
@@ -133,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");
@@ -143,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() +"'/>");
@@ -6,7 +6,6 @@ package org.springframework.security.config;
* These are intended for internal use.
*
* @author Ben Alex
* @author Luke Taylor
*/
public abstract class BeanIds {
private static final String PREFIX = "org.springframework.security.";
@@ -20,7 +19,6 @@ public abstract class BeanIds {
public static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = PREFIX + "contextSettingPostProcessor";
public static final String USER_DETAILS_SERVICE = PREFIX + "userDetailsService";
public static final String USER_DETAILS_SERVICE_FACTORY = PREFIX + "userDetailsServiceFactory";
public static final String METHOD_ACCESS_MANAGER = PREFIX + "defaultMethodAccessManager";
@@ -29,6 +27,4 @@ public abstract class BeanIds {
public static final String METHOD_SECURITY_METADATA_SOURCE_ADVISOR = PREFIX + "methodSecurityMetadataSourceAdvisor";
public static final String EMBEDDED_APACHE_DS = PREFIX + "apacheDirectoryServerContainer";
public static final String CONTEXT_SOURCE = PREFIX + "securityContextSource";
public static final String DEBUG_FILTER = PREFIX + "debugFilter";
}
@@ -1,20 +0,0 @@
package org.springframework.security.config;
import org.springframework.beans.factory.config.BeanDefinition;
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.debug.SecurityDebugBeanFactoryPostProcessor;
import org.w3c.dom.Element;
/**
* @author Luke Taylor
*/
public class DebugBeanDefinitionParser implements BeanDefinitionParser {
public BeanDefinition parse(Element element, ParserContext parserContext) {
RootBeanDefinition debugPP = new RootBeanDefinition(SecurityDebugBeanFactoryPostProcessor.class);
parserContext.getReaderContext().registerWithGeneratedName(debugPP);
return null;
}
}
@@ -1,7 +1,7 @@
package org.springframework.security.config;
/**
* Contains all the element names used by Spring Security 3 namespace support.
* Contains all the element names used by Spring Security 2 namespace support.
*
* @author Ben Alex
*/
@@ -46,12 +46,9 @@ public abstract class Elements {
public static final String CUSTOM_FILTER = "custom-filter";
public static final String REQUEST_CACHE = "request-cache";
public static final String X509 = "x509";
public static final String JEE = "jee";
public static final String FILTER_SECURITY_METADATA_SOURCE = "filter-security-metadata-source";
public static final String METHOD_SECURITY_METADATA_SOURCE = "method-security-metadata-source";
@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 DEBUG = "debug";
public static final String HTTP_FIREWALL = "http-firewall";
}
@@ -24,7 +24,6 @@ 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.config.method.MethodSecurityMetadataSourceBeanDefinitionParser;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.util.ClassUtils;
import org.w3c.dom.Element;
@@ -39,6 +38,7 @@ import org.w3c.dom.Node;
*/
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;
@@ -63,8 +63,9 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
public BeanDefinition parse(Element element, ParserContext pc) {
if (!namespaceMatchesVersion(element)) {
pc.getReaderContext().fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd schema " +
"with Spring Security 3.1. Please update your schema declarations to the 3.1 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);
@@ -75,20 +76,18 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
}
if (parser == null) {
if (Elements.HTTP.equals(name) || Elements.FILTER_SECURITY_METADATA_SOURCE.equals(name) ||
Elements.FILTER_CHAIN_MAP.equals(name)) {
if (Elements.HTTP.equals(name) || Elements.FILTER_SECURITY_METADATA_SOURCE.equals(name)) {
reportMissingWebClasses(name, pc, element);
} else {
reportUnsupportedNodeType(name, pc, element);
}
return null;
}
return parser.parse(element, pc);
}
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext pc) {
BeanDefinitionDecorator decorator = null;
String name = pc.getDelegate().getLocalName(node);
// We only handle elements
@@ -108,7 +107,9 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
}
}
reportUnsupportedNodeType(name, pc, node);
if (decorator == null) {
reportUnsupportedNodeType(name, pc, node);
}
return null;
}
@@ -120,7 +121,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
private void reportMissingWebClasses(String nodeName, ParserContext pc, Node node) {
pc.getReaderContext().fatal("spring-security-web classes are not available. " +
"You need these to use <" + nodeName + ">", node);
"You need these to use <" + Elements.FILTER_CHAIN_MAP + ">", node);
}
public void init() {
@@ -138,11 +139,9 @@ 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());
parsers.put(Elements.METHOD_SECURITY_METADATA_SOURCE, new MethodSecurityMetadataSourceBeanDefinitionParser());
// 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.DEBUG, new DebugBeanDefinitionParser());
parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
parsers.put(Elements.HTTP_FIREWALL, new HttpFirewallBeanDefinitionParser());
parsers.put(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
@@ -153,11 +152,8 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
/**
* Check that the schema location declared in the source file being parsed matches the Spring Security version.
* The old 2.0 schema is not compatible with the 3.1 parser, so it is an error to explicitly use
* 2.0.
* <p>
* There are also differences between 3.0 and 3.1 which are sufficient that we report using 3.0 as an error too.
* It might be an error to declare spring-security.xsd as an alias, but you are only going to find that out
* The old 2.0 schema is not compatible with the new 3.0 parser, so it is an error to explicitly use
* 3.0. It might be an error to declare spring-security.xsd as an alias, but you are only going to find that out
* when one of the sub parsers breaks.
*
* @param element the element that is to be parsed next
@@ -169,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\\.1.*.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.*");
}
@@ -57,17 +57,6 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
if (node instanceof Element) {
Element providerElt = (Element)node;
if (StringUtils.hasText(providerElt.getAttribute(ATT_REF))) {
if (providerElt.getAttributes().getLength() > 1) {
pc.getReaderContext().error("authentication-provider element cannot be used with other attributes " +
"when using 'ref' attribute", pc.extractSource(element));
}
NodeList providerChildren = providerElt.getChildNodes();
for (int j = 0; j < providerChildren.getLength(); j++) {
if (providerChildren.item(j) instanceof Element) {
pc.getReaderContext().error("authentication-provider element cannot have child elements when used " +
"with 'ref' attribute", pc.extractSource(element));
}
}
providers.add(new RuntimeBeanReference(providerElt.getAttribute(ATT_REF)));
} else {
BeanDefinition provider = resolver.resolve(providerElt.getNamespaceURI()).parse(providerElt, pc);
@@ -85,8 +74,8 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
providerManagerBldr.addPropertyValue("providers", providers);
if ("false".equals(element.getAttribute(ATT_ERASE_CREDENTIALS))) {
providerManagerBldr.addPropertyValue("eraseCredentialsAfterAuthentication", false);
if ("true".equals(element.getAttribute(ATT_ERASE_CREDENTIALS))) {
providerManagerBldr.addPropertyValue("eraseCredentialsAfterAuthentication", true);
}
// Add the default event publisher
@@ -128,7 +117,7 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
return null;
}
public boolean supports(Class<?> authentication) {
public boolean supports(Class<? extends Object> authentication) {
return false;
}
}
@@ -18,7 +18,7 @@ import org.w3c.dom.Element;
* @author Luke Taylor
*/
public class AuthenticationProviderBeanDefinitionParser implements BeanDefinitionParser {
private static final String ATT_USER_DETAILS_REF = "user-service-ref";
private static String ATT_USER_DETAILS_REF = "user-service-ref";
public BeanDefinition parse(Element element, ParserContext pc) {
RootBeanDefinition authProvider = new RootBeanDefinition(DaoAuthenticationProvider.class);
@@ -13,7 +13,7 @@ import org.springframework.util.Assert;
*/
public class CachingUserDetailsService implements UserDetailsService {
private UserCache userCache = new NullUserCache();
private final UserDetailsService delegate;
private UserDetailsService delegate;
CachingUserDetailsService(UserDetailsService delegate) {
this.delegate = delegate;
@@ -55,7 +55,7 @@ public class PasswordEncoderParser {
ENCODER_CLASSES.put(OPT_HASH_LDAP_SSHA, LdapShaPasswordEncoder.class);
}
private static final Log logger = LogFactory.getLog(PasswordEncoderParser.class);
private static Log logger = LogFactory.getLog(PasswordEncoderParser.class);
private BeanMetadataElement passwordEncoder;
private BeanMetadataElement saltSource;
@@ -69,7 +69,7 @@ public class PasswordEncoderParser {
boolean useBase64 = false;
if (StringUtils.hasText(element.getAttribute(ATT_BASE_64))) {
useBase64 = Boolean.valueOf(element.getAttribute(ATT_BASE_64)).booleanValue();
useBase64 = new Boolean(element.getAttribute(ATT_BASE_64)).booleanValue();
}
String ref = element.getAttribute(ATT_REF);
@@ -93,7 +93,7 @@ public class PasswordEncoderParser {
BeanDefinitionBuilder beanBldr = BeanDefinitionBuilder.rootBeanDefinition(beanClass);
if (OPT_HASH_SHA256.equals(hash)) {
beanBldr.addConstructorArgValue(Integer.valueOf(256));
beanBldr.addConstructorArgValue(new Integer(256));
}
if (useBase64) {
@@ -9,12 +9,12 @@ import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.core.userdetails.memory.UserMap;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
@@ -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";
@@ -37,7 +38,7 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
private SecureRandom random;
protected String getBeanClassName(Element element) {
return InMemoryUserDetailsManager.class.getName();
return "org.springframework.security.core.userdetails.memory.InMemoryDaoImpl";
}
@SuppressWarnings("unchecked")
@@ -53,20 +54,21 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
BeanDefinition bd = new RootBeanDefinition(PropertiesFactoryBean.class);
bd.getPropertyValues().addPropertyValue("location", userProperties);
builder.addConstructorArgValue(bd);
builder.addPropertyValue("userProperties", bd);
return;
}
if (CollectionUtils.isEmpty(userElts)) {
if(CollectionUtils.isEmpty(userElts)) {
throw new BeanDefinitionStoreException("You must supply user definitions, either with <" + ELT_USER + "> child elements or a " +
"properties file (using the '" + ATT_PROPERTIES + "' attribute)" );
}
ManagedList<BeanDefinition> users = new ManagedList<BeanDefinition>();
BeanDefinition userMap = new RootBeanDefinition(UserMap.class);
ManagedMap<String, BeanDefinition> users = new ManagedMap<String, BeanDefinition>();
for (Object elt : userElts) {
Element userElt = (Element) elt;
for (Iterator i = userElts.iterator(); i.hasNext();) {
Element userElt = (Element) i.next();
String userName = userElt.getAttribute(ATT_NAME);
String password = userElt.getAttribute(ATT_PASSWORD);
@@ -89,10 +91,12 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
user.addConstructorArgValue(!locked);
user.addConstructorArgValue(authorities.getBeanDefinition());
users.add(user.getBeanDefinition());
users.put(userName.toLowerCase(), user.getBeanDefinition());
}
builder.addConstructorArgValue(users);
userMap.getPropertyValues().addPropertyValue("users", users);
builder.addPropertyValue("userMap", userMap);
}
private String generateRandomPassword() {
@@ -1,110 +0,0 @@
package org.springframework.security.config.debug;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* Spring Security debugging filter.
* <p>
* Logs information (such as session creation) to help the user understand how requests are being handled
* by Spring Security and provide them with other relevant information (such as when sessions are being created).
*
*
* @author Luke Taylor
* @since 3.1
*/
class DebugFilter extends OncePerRequestFilter {
private final FilterChainProxy fcp;
private final Map<RequestMatcher, List<Filter>> filterChainMap;
private final Logger logger = new Logger();
public DebugFilter(FilterChainProxy fcp) {
this.fcp = fcp;
this.filterChainMap = fcp.getFilterChainMap();
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
List<Filter> filters = getFilters(request);
logger.log("Request received for '" + UrlUtils.buildRequestUrl(request) + "':\n\n" +
request + "\n\n" +
"servletPath:" + request.getServletPath() + "\n" +
"pathInfo:" + request.getPathInfo() + "\n\n" +
formatFilters(filters));
fcp.doFilter(new DebugRequestWrapper(request), response, filterChain);
}
String formatFilters(List<Filter> filters) {
StringBuilder sb = new StringBuilder();
sb.append("Security filter chain: ");
if (filters == null) {
sb.append("no match");
} else if (filters.isEmpty()) {
sb.append("[] empty (bypassed by security='none') ");
} else {
sb.append("[\n");
for (Filter f : filters) {
sb.append(" ").append(f.getClass().getSimpleName()).append("\n");
}
sb.append("]");
}
return sb.toString();
}
private List<Filter> getFilters(HttpServletRequest request) {
for (Map.Entry<RequestMatcher, List<Filter>> entry : filterChainMap.entrySet()) {
RequestMatcher matcher = entry.getKey();
if (matcher.matches(request)) {
return entry.getValue();
}
}
return null;
}
}
class DebugRequestWrapper extends HttpServletRequestWrapper {
private static final Logger logger = new Logger();
public DebugRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public HttpSession getSession() {
boolean sessionExists = super.getSession(false) != null;
HttpSession session = super.getSession();
if (!sessionExists) {
logger.log("New HTTP session created: " + session.getId(), true);
}
return session;
}
@Override
public HttpSession getSession(boolean create) {
if (!create) {
return super.getSession(create);
}
return getSession();
}
}
@@ -1,41 +0,0 @@
package org.springframework.security.config.debug;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Controls output for the Spring Security debug feature.
*
* @author Luke Taylor
* @since 3.1
*/
final class Logger {
final static Log logger = LogFactory.getLog("Spring Security Debugger");
void log(String message) {
log(message, false);
}
void log(String message, boolean dumpStack) {
StringBuilder output = new StringBuilder(256);
output.append("\n\n************************************************************\n\n");
output.append(message).append("\n");
if (dumpStack) {
StringWriter os = new StringWriter();
new Exception().printStackTrace(new PrintWriter(os));
StringBuffer buffer = os.getBuffer();
// Remove the exception in case it scares people.
int start = buffer.indexOf("java.lang.Exception");
buffer.replace(start, start + 19, "");
output.append("\nCall stack: \n").append(os.toString());
}
output.append("\n\n************************************************************\n\n");
logger.info(output.toString());
}
}
@@ -1,28 +0,0 @@
package org.springframework.security.config.debug;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.security.config.BeanIds;
import org.springframework.security.web.FilterChainProxy;
/**
* @author Luke Taylor
*/
public class SecurityDebugBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Logger.logger.warn("\n\n" +
"********************************************************************\n" +
"********** Security debugging is enabled. *************\n" +
"********** This may include sensitive information. *************\n" +
"********** Do not use in a production system! *************\n" +
"********************************************************************\n\n");
if (beanFactory.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN) != null) {
FilterChainProxy fcp = beanFactory.getBean(BeanIds.FILTER_CHAIN_PROXY, FilterChainProxy.class);
beanFactory.registerSingleton(BeanIds.DEBUG_FILTER, new DebugFilter(fcp));
// Overwrite the filter chain alias
beanFactory.registerAlias(BeanIds.DEBUG_FILTER, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
}
}
}
@@ -13,29 +13,24 @@ import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.authentication.AnonymousAuthenticationProvider;
import org.springframework.security.authentication.RememberMeAuthenticationProvider;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.Elements;
import org.springframework.security.core.authority.mapping.SimpleAttributes2GrantedAuthoritiesMapper;
import org.springframework.security.core.authority.mapping.SimpleMappableAttributesRetriever;
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
import org.springframework.security.web.PortResolverImpl;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesUserDetailsService;
import org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter;
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.BasicAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.Assert;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
@@ -57,13 +52,10 @@ final class AuthenticationConfigBuilder {
static final String OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS = "org.springframework.security.openid.OpenIDAuthenticationFilter";
static final String OPEN_ID_AUTHENTICATION_PROVIDER_CLASS = "org.springframework.security.openid.OpenIDAuthenticationProvider";
private static final String OPEN_ID_CONSUMER_CLASS = "org.springframework.security.openid.OpenID4JavaConsumer";
static final String OPEN_ID_CONSUMER_CLASS = "org.springframework.security.openid.OpenID4JavaConsumer";
static final String OPEN_ID_ATTRIBUTE_CLASS = "org.springframework.security.openid.OpenIDAttribute";
private static final String OPEN_ID_ATTRIBUTE_FACTORY_CLASS = "org.springframework.security.openid.RegexBasedAxFetchListFactory";
static final String AUTHENTICATION_PROCESSING_FILTER_CLASS = "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter";
static final String ATT_AUTH_DETAILS_SOURCE_REF = "authentication-details-source-ref";
private static final String ATT_AUTO_CONFIG = "auto-config";
private static final String ATT_ACCESS_DENIED_PAGE = "access-denied-page";
@@ -72,13 +64,16 @@ final class AuthenticationConfigBuilder {
private static final String ATT_USER_SERVICE_REF = "user-service-ref";
private static final String ATT_REF = "ref";
private static final String ATT_KEY = "key";
private final Element httpElt;
private final ParserContext pc;
private Element httpElt;
private ParserContext pc;
private final boolean autoConfig;
private final boolean allowSessionCreation;
private final String portMapperName;
private RootBeanDefinition anonymousFilter;
private BeanReference anonymousProviderRef;
@@ -87,49 +82,31 @@ final class AuthenticationConfigBuilder {
private BeanReference rememberMeProviderRef;
private BeanDefinition basicFilter;
private RuntimeBeanReference basicEntryPoint;
private RootBeanDefinition formFilter;
private BeanDefinition formEntryPoint;
private RootBeanDefinition openIDFilter;
private BeanDefinition openIDEntryPoint;
private BeanReference openIDProviderRef;
private String openIDProviderId;
private String formFilterId = null;
private String openIDFilterId = null;
private BeanDefinition x509Filter;
private BeanDefinition x509EntryPoint;
private BeanReference x509ProviderRef;
private BeanDefinition jeeFilter;
private BeanReference jeeProviderRef;
private RootBeanDefinition preAuthEntryPoint;
private String x509ProviderId;
private BeanDefinition logoutFilter;
private BeanDefinition loginPageGenerationFilter;
private BeanDefinition etf;
private final BeanReference requestCache;
private BeanReference requestCache;
public AuthenticationConfigBuilder(Element element, ParserContext pc, SessionCreationPolicy sessionPolicy,
BeanReference requestCache, BeanReference authenticationManager, BeanReference sessionStrategy) {
public AuthenticationConfigBuilder(Element element, ParserContext pc, boolean allowSessionCreation,
String portMapperName) {
this.httpElt = element;
this.pc = pc;
this.requestCache = requestCache;
this.portMapperName = portMapperName;
autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
this.allowSessionCreation = sessionPolicy != SessionCreationPolicy.never
&& sessionPolicy != SessionCreationPolicy.stateless;
createAnonymousFilter();
createRememberMeFilter(authenticationManager);
createBasicFilter(authenticationManager);
createFormLoginFilter(sessionStrategy, authenticationManager);
createOpenIDLoginFilter(sessionStrategy, authenticationManager);
createX509Filter(authenticationManager);
createJeeFilter(authenticationManager);
createLogoutFilter();
createLoginPageFilterIfNeeded();
createUserDetailsServiceFactory();
createExceptionTranslationFilter();
this.allowSessionCreation = allowSessionCreation;
}
void createRememberMeFilter(BeanReference authenticationManager) {
// Parse remember me before logout as RememberMeServices is also a LogoutHandler implementation.
Element rememberMeElt = DomUtils.getChildElementByTagName(httpElt, Elements.REMEMBER_ME);
@@ -162,6 +139,7 @@ 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",
@@ -176,6 +154,7 @@ final class AuthenticationConfigBuilder {
formFilter.getPropertyValues().addPropertyValue("allowSessionCreation", allowSessionCreation);
formFilter.getPropertyValues().addPropertyValue("authenticationManager", authManager);
// Id is required by login page filter
formFilterId = pc.getReaderContext().generateBeanName(formFilter);
pc.registerBeanComponent(new BeanComponentDefinition(formFilter, formFilterId));
@@ -185,6 +164,7 @@ 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",
@@ -194,31 +174,30 @@ final class AuthenticationConfigBuilder {
openIDFilter = parser.getFilterBean();
openIDEntryPoint = parser.getEntryPointBean();
List<Element> attrExElts = DomUtils.getChildElementsByTagName(openIDLoginElt, Elements.OPENID_ATTRIBUTE_EXCHANGE);
Element attrExElt = DomUtils.getChildElementByTagName(openIDLoginElt, Elements.OPENID_ATTRIBUTE_EXCHANGE);
if (!attrExElts.isEmpty()) {
if (attrExElt != null) {
// Set up the consumer with the required attribute list
BeanDefinitionBuilder consumerBldr = BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_CONSUMER_CLASS);
BeanDefinitionBuilder axFactory = BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_ATTRIBUTE_FACTORY_CLASS);
ManagedMap<String, ManagedList<BeanDefinition>> axMap = new ManagedMap<String, ManagedList<BeanDefinition>>();
for (Element attrExElt : attrExElts) {
String identifierMatch = attrExElt.getAttribute("identifier-match");
if (!StringUtils.hasText(identifierMatch)) {
if (attrExElts.size() > 1) {
pc.getReaderContext().error("You must supply an identifier-match attribute if using more" +
" than one " + Elements.OPENID_ATTRIBUTE_EXCHANGE + " element", attrExElt);
}
// Match anything
identifierMatch = ".*";
ManagedList<BeanDefinition> attributes = new ManagedList<BeanDefinition> ();
for (Element attElt : DomUtils.getChildElementsByTagName(attrExElt, Elements.OPENID_ATTRIBUTE)) {
String name = attElt.getAttribute("name");
String type = attElt.getAttribute("type");
String required = attElt.getAttribute("required");
String count = attElt.getAttribute("count");
BeanDefinitionBuilder attrBldr = BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_ATTRIBUTE_CLASS);
attrBldr.addConstructorArgValue(name);
attrBldr.addConstructorArgValue(type);
if (StringUtils.hasLength(required)) {
attrBldr.addPropertyValue("required", Boolean.valueOf(required));
}
axMap.put(identifierMatch, parseOpenIDAttributes(attrExElt));
if (StringUtils.hasLength(count)) {
attrBldr.addPropertyValue("count", Integer.parseInt(count));
}
attributes.add(attrBldr.getBeanDefinition());
}
axFactory.addConstructorArgValue(axMap);
consumerBldr.addConstructorArgValue(axFactory.getBeanDefinition());
consumerBldr.addConstructorArgValue(attributes);
openIDFilter.getPropertyValues().addPropertyValue("consumer", consumerBldr.getBeanDefinition());
}
}
@@ -235,43 +214,20 @@ final class AuthenticationConfigBuilder {
}
}
private ManagedList<BeanDefinition> parseOpenIDAttributes(Element attrExElt) {
ManagedList<BeanDefinition> attributes = new ManagedList<BeanDefinition> ();
for (Element attElt : DomUtils.getChildElementsByTagName(attrExElt, Elements.OPENID_ATTRIBUTE)) {
String name = attElt.getAttribute("name");
String type = attElt.getAttribute("type");
String required = attElt.getAttribute("required");
String count = attElt.getAttribute("count");
BeanDefinitionBuilder attrBldr = BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_ATTRIBUTE_CLASS);
attrBldr.addConstructorArgValue(name);
attrBldr.addConstructorArgValue(type);
if (StringUtils.hasLength(required)) {
attrBldr.addPropertyValue("required", Boolean.valueOf(required));
}
if (StringUtils.hasLength(count)) {
attrBldr.addPropertyValue("count", Integer.parseInt(count));
}
attributes.add(attrBldr.getBeanDefinition());
}
return attributes;
}
private void createOpenIDProvider() {
Element openIDLoginElt = DomUtils.getChildElementByTagName(httpElt, Elements.OPENID_LOGIN);
BeanDefinitionBuilder openIDProviderBuilder =
BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_AUTHENTICATION_PROVIDER_CLASS);
RootBeanDefinition uds = new RootBeanDefinition();
uds.setFactoryBeanName(BeanIds.USER_DETAILS_SERVICE_FACTORY);
uds.setFactoryMethodName("authenticationUserDetailsService");
uds.getConstructorArgumentValues().addGenericArgumentValue(openIDLoginElt.getAttribute(ATT_USER_SERVICE_REF));
String userService = openIDLoginElt.getAttribute(ATT_USER_SERVICE_REF);
openIDProviderBuilder.addPropertyValue("authenticationUserDetailsService", uds);
if (StringUtils.hasText(userService)) {
openIDProviderBuilder.addPropertyReference("userDetailsService", userService);
}
BeanDefinition openIDProvider = openIDProviderBuilder.getBeanDefinition();
openIDProviderRef = new RuntimeBeanReference(pc.getReaderContext().registerWithGeneratedName(openIDProvider));
openIDProviderId = pc.getReaderContext().registerWithGeneratedName(openIDProvider);
openIDProviderRef = new RuntimeBeanReference(openIDProviderId);
}
private void injectRememberMeServicesRef(RootBeanDefinition bean, String rememberMeServicesId) {
@@ -283,46 +239,41 @@ final class AuthenticationConfigBuilder {
void createBasicFilter(BeanReference authManager) {
Element basicAuthElt = DomUtils.getChildElementByTagName(httpElt, Elements.BASIC_AUTH);
if (basicAuthElt == null && !autoConfig) {
// No basic auth, do nothing
return;
}
String realm = httpElt.getAttribute(ATT_REALM);
if (!StringUtils.hasText(realm)) {
realm = DEF_REALM;
}
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicAuthenticationFilter.class);
RootBeanDefinition filter = null;
String entryPointId;
if (basicAuthElt != null || autoConfig) {
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(BasicAuthenticationFilter.class);
if (basicAuthElt != null) {
if (StringUtils.hasText(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF))) {
String 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);
}
injectAuthenticationDetailsSource(basicAuthElt, filterBuilder);
filterBuilder.addPropertyValue("authenticationManager", authManager);
filterBuilder.addPropertyValue("authenticationEntryPoint", basicEntryPoint);
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
}
if (basicEntryPoint == null) {
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", basicEntryPoint);
basicFilter = filterBuilder.getBeanDefinition();
basicFilter = filter;
}
void createX509Filter(BeanReference authManager) {
Element x509Elt = DomUtils.getChildElementByTagName(httpElt, Elements.X509);
RootBeanDefinition filter = null;
RootBeanDefinition entryPoint = null;
if (x509Elt != null) {
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(X509AuthenticationFilter.class);
@@ -337,102 +288,37 @@ final class AuthenticationConfigBuilder {
filterBuilder.addPropertyValue("principalExtractor", extractor.getBeanDefinition());
}
injectAuthenticationDetailsSource(x509Elt, filterBuilder);
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
createPrauthEntryPoint(x509Elt);
entryPoint = new RootBeanDefinition(Http403ForbiddenEntryPoint.class);
entryPoint.setSource(pc.extractSource(x509Elt));
createX509Provider();
}
x509Filter = filter;
}
private void injectAuthenticationDetailsSource(Element elt, BeanDefinitionBuilder filterBuilder) {
String authDetailsSourceRef = elt.getAttribute(AuthenticationConfigBuilder.ATT_AUTH_DETAILS_SOURCE_REF);
if (StringUtils.hasText(authDetailsSourceRef)) {
filterBuilder.addPropertyReference("authenticationDetailsSource", authDetailsSourceRef);
}
x509EntryPoint = entryPoint;
}
private void createX509Provider() {
Element x509Elt = DomUtils.getChildElementByTagName(httpElt, Elements.X509);
BeanDefinition provider = new RootBeanDefinition(PreAuthenticatedAuthenticationProvider.class);
RootBeanDefinition uds = new RootBeanDefinition();
uds.setFactoryBeanName(BeanIds.USER_DETAILS_SERVICE_FACTORY);
uds.setFactoryMethodName("authenticationUserDetailsService");
uds.getConstructorArgumentValues().addGenericArgumentValue(x509Elt.getAttribute(ATT_USER_SERVICE_REF));
String userServiceRef = x509Elt.getAttribute(ATT_USER_SERVICE_REF);
provider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService", uds);
x509ProviderRef = new RuntimeBeanReference(pc.getReaderContext().registerWithGeneratedName(provider));
}
private void createPrauthEntryPoint(Element source) {
if (preAuthEntryPoint == null) {
preAuthEntryPoint = new RootBeanDefinition(Http403ForbiddenEntryPoint.class);
preAuthEntryPoint.setSource(pc.extractSource(source));
}
}
void createJeeFilter(BeanReference authManager) {
final String ATT_MAPPABLE_ROLES = "mappable-roles";
Element jeeElt = DomUtils.getChildElementByTagName(httpElt, Elements.JEE);
RootBeanDefinition filter = null;
if (jeeElt != null) {
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(J2eePreAuthenticatedProcessingFilter.class);
filterBuilder.getRawBeanDefinition().setSource(pc.extractSource(jeeElt));
filterBuilder.addPropertyValue("authenticationManager", authManager);
BeanDefinitionBuilder adsBldr = BeanDefinitionBuilder.rootBeanDefinition(J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource.class);
adsBldr.addPropertyValue("userRoles2GrantedAuthoritiesMapper", new RootBeanDefinition(SimpleAttributes2GrantedAuthoritiesMapper.class));
String roles = jeeElt.getAttribute(ATT_MAPPABLE_ROLES);
Assert.state(StringUtils.hasText(roles));
BeanDefinitionBuilder rolesBuilder = BeanDefinitionBuilder.rootBeanDefinition(StringUtils.class);
rolesBuilder.addConstructorArgValue(roles);
rolesBuilder.setFactoryMethod("commaDelimitedListToSet");
RootBeanDefinition mappableRolesRetriever = new RootBeanDefinition(SimpleMappableAttributesRetriever.class);
mappableRolesRetriever.getPropertyValues().addPropertyValue("mappableAttributes", rolesBuilder.getBeanDefinition());
adsBldr.addPropertyValue("mappableRolesRetriever", mappableRolesRetriever);
filterBuilder.addPropertyValue("authenticationDetailsSource", adsBldr.getBeanDefinition());
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
createPrauthEntryPoint(jeeElt);
createJeeProvider();
if (StringUtils.hasText(userServiceRef)) {
RootBeanDefinition preAuthUserService = new RootBeanDefinition(UserDetailsByNameServiceWrapper.class);
preAuthUserService.setSource(pc.extractSource(x509Elt));
preAuthUserService.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(userServiceRef));
provider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService", preAuthUserService);
}
jeeFilter = filter;
x509ProviderId = pc.getReaderContext().registerWithGeneratedName(provider);
x509ProviderRef = new RuntimeBeanReference(x509ProviderId);
}
private void createJeeProvider() {
Element jeeElt = DomUtils.getChildElementByTagName(httpElt, Elements.JEE);
BeanDefinition provider = new RootBeanDefinition(PreAuthenticatedAuthenticationProvider.class);
RootBeanDefinition uds;
if (StringUtils.hasText(jeeElt.getAttribute(ATT_USER_SERVICE_REF))) {
uds = new RootBeanDefinition();
uds.setFactoryBeanName(BeanIds.USER_DETAILS_SERVICE_FACTORY);
uds.setFactoryMethodName("authenticationUserDetailsService");
uds.getConstructorArgumentValues().addGenericArgumentValue(jeeElt.getAttribute(ATT_USER_SERVICE_REF));
} else {
uds = new RootBeanDefinition(PreAuthenticatedGrantedAuthoritiesUserDetailsService.class);
}
provider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService", uds);
jeeProviderRef = new RuntimeBeanReference(pc.getReaderContext().registerWithGeneratedName(provider));
}
void createLoginPageFilterIfNeeded() {
boolean needLoginPage = formFilter != null || openIDFilter != null;
boolean needLoginPage = formFilterId != null || openIDFilterId != null;
String formLoginPage = getLoginFormUrl(formEntryPoint);
String openIDLoginPage = getLoginFormUrl(openIDEntryPoint);
@@ -443,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);
}
@@ -526,6 +412,28 @@ final class AuthenticationConfigBuilder {
etf = etfBuilder.getBeanDefinition();
}
void createRequestCache() {
Element requestCacheElt = DomUtils.getChildElementByTagName(httpElt, Elements.REQUEST_CACHE);
if (requestCacheElt != null) {
requestCache = new RuntimeBeanReference(requestCacheElt.getAttribute(ATT_REF));
return;
}
BeanDefinitionBuilder requestCacheBldr = BeanDefinitionBuilder.rootBeanDefinition(HttpSessionRequestCache.class);
BeanDefinitionBuilder portResolver = BeanDefinitionBuilder.rootBeanDefinition(PortResolverImpl.class);
portResolver.addPropertyReference("portMapper", portMapperName);
requestCacheBldr.addPropertyValue("createSessionAllowed", allowSessionCreation);
requestCacheBldr.addPropertyValue("portResolver", portResolver.getBeanDefinition());
BeanDefinition bean = requestCacheBldr.getBeanDefinition();
String id = pc.getReaderContext().generateBeanName(bean);
pc.registerBeanComponent(new BeanComponentDefinition(bean, id));
this.requestCache = new RuntimeBeanReference(id);
}
private BeanMetadataElement createAccessDeniedHandler(Element element, ParserContext pc) {
String accessDeniedPage = element.getAttribute(ATT_ACCESS_DENIED_PAGE);
WebConfigUtils.validateHttpRedirect(accessDeniedPage, pc, pc.extractSource(element));
@@ -589,18 +497,18 @@ 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;
}
// If X.509 or JEE have been enabled, use the preauth entry point.
if (preAuthEntryPoint != null) {
return preAuthEntryPoint;
// If X.509 has been enabled, use the preauth entry point.
if (DomUtils.getChildElementByTagName(httpElt, Elements.X509) != null) {
return x509EntryPoint;
}
pc.getReaderContext().error("No AuthenticationEntryPoint could be established. Please " +
@@ -629,14 +537,14 @@ final class AuthenticationConfigBuilder {
return (String) pv.getValue();
}
private void createUserDetailsServiceFactory() {
if (pc.getRegistry().containsBeanDefinition(BeanIds.USER_DETAILS_SERVICE_FACTORY)) {
// Multiple <http> case
return;
}
RootBeanDefinition bean = new RootBeanDefinition(UserDetailsServiceFactoryBean.class);
bean.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
pc.getReaderContext().getRegistry().registerBeanDefinition(BeanIds.USER_DETAILS_SERVICE_FACTORY, bean);
void createUserServiceInjector() {
BeanDefinitionBuilder userServiceInjector =
BeanDefinitionBuilder.rootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class);
userServiceInjector.addConstructorArgValue(x509ProviderId);
userServiceInjector.addConstructorArgValue(rememberMeServicesId);
userServiceInjector.addConstructorArgValue(openIDProviderId);
userServiceInjector.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
pc.getReaderContext().registerWithGeneratedName(userServiceInjector.getBeanDefinition());
}
List<OrderDecorator> getFilters() {
@@ -658,16 +566,12 @@ final class AuthenticationConfigBuilder {
filters.add(new OrderDecorator(x509Filter, X509_FILTER));
}
if (jeeFilter != null) {
filters.add(new OrderDecorator(jeeFilter, PRE_AUTH_FILTER));
if (formFilterId != null) {
filters.add(new OrderDecorator(new RuntimeBeanReference(formFilterId), FORM_LOGIN_FILTER));
}
if (formFilter != null) {
filters.add(new OrderDecorator(formFilter, 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) {
@@ -702,11 +606,11 @@ final class AuthenticationConfigBuilder {
providers.add(x509ProviderRef);
}
if (jeeProviderRef != null) {
providers.add(jeeProviderRef);
}
return providers;
}
public BeanReference getRequestCache() {
return requestCache;
}
}
@@ -18,8 +18,8 @@ public class ChannelAttributeFactory {
private static final String OPT_REQUIRES_HTTPS = "https";
private static final String OPT_ANY_CHANNEL = "any";
public static List<ConfigAttribute> createChannelAttributes(String requiredChannel) {
String channelConfigAttribute;
public static final List<ConfigAttribute> createChannelAttributes(String requiredChannel) {
String channelConfigAttribute = null;
if (requiredChannel.equals(OPT_REQUIRES_HTTPS)) {
channelConfigAttribute = "REQUIRES_SECURE_CHANNEL";
@@ -2,6 +2,7 @@ package org.springframework.security.config.http;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.servlet.Filter;
@@ -10,7 +11,6 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
@@ -20,21 +20,24 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.session.SessionManagementFilter;
public class DefaultFilterChainValidator implements FilterChainProxy.FilterChainValidator {
private final Log logger = LogFactory.getLog(getClass());
private Log logger = LogFactory.getLog(getClass());
public void validate(FilterChainProxy fcp) {
for(List<Filter> filters : fcp.getFilterChainMap().values()) {
checkLoginPageIsntProtected(fcp, filters);
Map<String, List<Filter>> filterChainMap = fcp.getFilterChainMap();
for(String pattern : fcp.getFilterChainMap().keySet()) {
List<Filter> filters = filterChainMap.get(pattern);
checkFilterStack(filters);
}
checkLoginPageIsntProtected(fcp, filterChainMap.get(fcp.getMatcher().getUniversalMatchPattern()));
}
private Object getFilter(Class<?> type, List<Filter> filters) {
for (Filter f : filters) {
if (type.isAssignableFrom(f.getClass())) {
return f;
@@ -53,7 +56,6 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain
checkForDuplicates(SessionManagementFilter.class, filters);
checkForDuplicates(BasicAuthenticationFilter.class, filters);
checkForDuplicates(SecurityContextHolderAwareRequestFilter.class, filters);
checkForDuplicates(JaasApiIntegrationFilter.class, filters);
checkForDuplicates(ExceptionTranslationFilter.class, filters);
checkForDuplicates(FilterSecurityInterceptor.class, filters);
}
@@ -76,60 +78,56 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain
}
/* Checks for the common error of having a login page URL protected by the security interceptor */
private void checkLoginPageIsntProtected(FilterChainProxy fcp, List<Filter> filterStack) {
ExceptionTranslationFilter etf = (ExceptionTranslationFilter)getFilter(ExceptionTranslationFilter.class, filterStack);
private void checkLoginPageIsntProtected(FilterChainProxy fcp, List<Filter> defaultFilters) {
ExceptionTranslationFilter etf = (ExceptionTranslationFilter)getFilter(ExceptionTranslationFilter.class, defaultFilters);
if(etf == null || !(etf.getAuthenticationEntryPoint() instanceof LoginUrlAuthenticationEntryPoint)) {
return;
}
if (etf.getAuthenticationEntryPoint() instanceof LoginUrlAuthenticationEntryPoint) {
String loginPage =
((LoginUrlAuthenticationEntryPoint)etf.getAuthenticationEntryPoint()).getLoginFormUrl();
List<Filter> filters = fcp.getFilters(loginPage);
logger.info("Checking whether login URL '" + loginPage + "' is accessible with your configuration");
String loginPage = ((LoginUrlAuthenticationEntryPoint)etf.getAuthenticationEntryPoint()).getLoginFormUrl();
FilterInvocation loginRequest = new FilterInvocation(loginPage, "POST");
List<Filter> filters = fcp.getFilters(loginPage);
logger.info("Checking whether login URL '" + loginPage + "' is accessible with your configuration");
if (filters == null || filters.isEmpty()) {
logger.debug("Filter chain is empty for the login page");
return;
}
if (getFilter(DefaultLoginPageGeneratingFilter.class, filters) != null) {
logger.debug("Default generated login page is in use");
return;
}
FilterSecurityInterceptor fsi = (FilterSecurityInterceptor) getFilter(FilterSecurityInterceptor.class, filters);
DefaultFilterInvocationSecurityMetadataSource fids =
(DefaultFilterInvocationSecurityMetadataSource) fsi.getSecurityMetadataSource();
Collection<ConfigAttribute> attributes = fids.getAttributes(loginRequest);
if (attributes == null) {
logger.debug("No access attributes defined for login page URL");
if (fsi.isRejectPublicInvocations()) {
logger.warn("FilterSecurityInterceptor is configured to reject public invocations." +
" Your login page may not be accessible.");
if (filters == null || filters.isEmpty()) {
logger.debug("Filter chain is empty for the login page");
return;
}
return;
}
AnonymousAuthenticationFilter anonPF = (AnonymousAuthenticationFilter) getFilter(AnonymousAuthenticationFilter.class, filters);
if (anonPF == null) {
logger.warn("The login page is being protected by the filter chain, but you don't appear to have" +
" anonymous authentication enabled. This is almost certainly an error.");
return;
}
if (getFilter(DefaultLoginPageGeneratingFilter.class, filters) != null) {
logger.debug("Default generated login page is in use");
return;
}
// Simulate an anonymous access with the supplied attributes.
AnonymousAuthenticationToken token = new AnonymousAuthenticationToken("key", anonPF.getUserAttribute().getPassword(),
anonPF.getUserAttribute().getAuthorities());
try {
fsi.getAccessDecisionManager().decide(token, new Object(), attributes);
} catch (Exception e) {
logger.warn("Anonymous access to the login page doesn't appear to be enabled. This is almost certainly " +
"an error. Please check your configuration allows unauthenticated access to the configured " +
"login page. (Simulated access was rejected: " + e + ")");
FilterSecurityInterceptor fsi = (FilterSecurityInterceptor) getFilter(FilterSecurityInterceptor.class, filters);
DefaultFilterInvocationSecurityMetadataSource fids =
(DefaultFilterInvocationSecurityMetadataSource) fsi.getSecurityMetadataSource();
Collection<ConfigAttribute> attributes = fids.lookupAttributes(loginPage, "POST");
if (attributes == null) {
logger.debug("No access attributes defined for login page URL");
if (fsi.isRejectPublicInvocations()) {
logger.warn("FilterSecurityInterceptor is configured to reject public invocations." +
" Your login page may not be accessible.");
}
return;
}
AnonymousAuthenticationFilter anonPF = (AnonymousAuthenticationFilter) getFilter(AnonymousAuthenticationFilter.class, filters);
if (anonPF == null) {
logger.warn("The login page is being protected by the filter chain, but you don't appear to have" +
" anonymous authentication enabled. This is almost certainly an error.");
return;
}
// Simulate an anonymous access with the supplied attributes.
AnonymousAuthenticationToken token = new AnonymousAuthenticationToken("key", anonPF.getUserAttribute().getPassword(),
anonPF.getUserAttribute().getAuthorities());
try {
fsi.getAccessDecisionManager().decide(token, new Object(), fids.lookupAttributes(loginPage, "POST"));
} catch (Exception e) {
logger.warn("Anonymous access to the login page doesn't appear to be enabled. This is almost certainly " +
"an error. Please check your configuration allows unauthenticated access to the configured " +
"login page. (Simulated access was rejected: " + e + ")");
}
}
}
}
@@ -1,10 +1,5 @@
package org.springframework.security.config.http;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
@@ -13,11 +8,14 @@ import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.config.Elements;
import org.springframework.security.web.util.RegexUrlPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import java.util.*;
/**
* Sets the filter chain Map for a FilterChainProxy bean declaration.
*
@@ -32,7 +30,11 @@ public class FilterChainMapBeanDefinitionDecorator implements BeanDefinitionDeco
Map filterChainMap = new LinkedHashMap();
Element elt = (Element)node;
MatcherType matcherType = MatcherType.fromElement(elt);
String pathType = elt.getAttribute(HttpSecurityBeanDefinitionParser.ATT_PATH_TYPE);
if (HttpSecurityBeanDefinitionParser.OPT_PATH_TYPE_REGEX.equals(pathType)) {
filterChainProxy.getPropertyValues().addPropertyValue("matcher", new RegexUrlPathMatcher());
}
List<Element> filterChainElts = DomUtils.getChildElementsByTagName(elt, Elements.FILTER_CHAIN);
@@ -50,19 +52,17 @@ public class FilterChainMapBeanDefinitionDecorator implements BeanDefinitionDeco
"'must not be empty", elt);
}
BeanDefinition matcher = matcherType.createMatcher(path, null);
if (filters.equals(HttpSecurityBeanDefinitionParser.OPT_FILTERS_NONE)) {
filterChainMap.put(matcher, Collections.EMPTY_LIST);
filterChainMap.put(path, Collections.EMPTY_LIST);
} else {
String[] filterBeanNames = StringUtils.tokenizeToStringArray(filters, ",");
ManagedList filterChain = new ManagedList(filterBeanNames.length);
for (String name : filterBeanNames) {
filterChain.add(new RuntimeBeanReference(name));
for (int i=0; i < filterBeanNames.length; i++) {
filterChain.add(new RuntimeBeanReference(filterBeanNames[i]));
}
filterChainMap.put(matcher, filterChain);
filterChainMap.put(path, filterChain);
}
}
@@ -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;
@@ -17,6 +20,9 @@ import org.springframework.security.web.access.expression.DefaultWebSecurityExpr
import org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.RequestKey;
import org.springframework.security.web.util.AntUrlPathMatcher;
import org.springframework.security.web.util.UrlMatcher;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
@@ -60,11 +66,11 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
}
static BeanDefinition createSecurityMetadataSource(List<Element> interceptUrls, Element elt, ParserContext pc) {
MatcherType matcherType = MatcherType.fromElement(elt);
UrlMatcher matcher = HttpSecurityBeanDefinitionParser.createUrlMatcher(elt);
boolean useExpressions = isUseExpressions(elt);
ManagedMap<BeanDefinition, BeanDefinition> requestToAttributesMap = parseInterceptUrlsForFilterInvocationRequestMap(
matcherType, interceptUrls, useExpressions, pc);
interceptUrls, useExpressions, pc);
BeanDefinitionBuilder fidsBuilder;
if (useExpressions) {
@@ -74,37 +80,33 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
if (StringUtils.hasText(expressionHandlerRef)) {
logger.info("Using bean '" + expressionHandlerRef + "' as web SecurityExpressionHandler implementation");
} else {
expressionHandlerRef = registerDefaultExpressionHandler(pc);
BeanDefinition expressionHandler = BeanDefinitionBuilder.rootBeanDefinition(DefaultWebSecurityExpressionHandler.class).getBeanDefinition();
expressionHandlerRef = pc.getReaderContext().generateBeanName(expressionHandler);
pc.registerBeanComponent(new BeanComponentDefinition(expressionHandler, expressionHandlerRef));
}
fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(ExpressionBasedFilterInvocationSecurityMetadataSource.class);
fidsBuilder.addConstructorArgValue(matcher);
fidsBuilder.addConstructorArgValue(requestToAttributesMap);
fidsBuilder.addConstructorArgReference(expressionHandlerRef);
} else {
fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(DefaultFilterInvocationSecurityMetadataSource.class);
fidsBuilder.addConstructorArgValue(matcher);
fidsBuilder.addConstructorArgValue(requestToAttributesMap);
}
fidsBuilder.addPropertyValue("stripQueryStringFromUrls", matcher instanceof AntUrlPathMatcher);
fidsBuilder.getRawBeanDefinition().setSource(pc.extractSource(elt));
return fidsBuilder.getBeanDefinition();
}
static String registerDefaultExpressionHandler(ParserContext pc) {
BeanDefinition expressionHandler = BeanDefinitionBuilder.rootBeanDefinition(DefaultWebSecurityExpressionHandler.class).getBeanDefinition();
String expressionHandlerRef = pc.getReaderContext().generateBeanName(expressionHandler);
pc.registerBeanComponent(new BeanComponentDefinition(expressionHandler, expressionHandlerRef));
return expressionHandlerRef;
}
static boolean isUseExpressions(Element elt) {
return "true".equals(elt.getAttribute(ATT_USE_EXPRESSIONS));
}
private static ManagedMap<BeanDefinition, BeanDefinition>
parseInterceptUrlsForFilterInvocationRequestMap(MatcherType matcherType,
List<Element> urlElts, boolean useExpressions, ParserContext parserContext) {
private static ManagedMap<BeanDefinition, BeanDefinition> parseInterceptUrlsForFilterInvocationRequestMap(List<Element> urlElts,
boolean useExpressions, ParserContext parserContext) {
ManagedMap<BeanDefinition, BeanDefinition> filterInvocationDefinitionMap = new ManagedMap<BeanDefinition, BeanDefinition>();
@@ -113,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);
@@ -125,7 +134,10 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
method = null;
}
BeanDefinition matcher = matcherType.createMatcher(path, method);
BeanDefinitionBuilder keyBldr = BeanDefinitionBuilder.rootBeanDefinition(RequestKey.class);
keyBldr.addConstructorArgValue(path);
keyBldr.addConstructorArgValue(method);
BeanDefinitionBuilder attributeBuilder = BeanDefinitionBuilder.rootBeanDefinition(SecurityConfig.class);
attributeBuilder.addConstructorArgValue(access);
@@ -138,11 +150,13 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
attributeBuilder.setFactoryMethod("createListFromCommaDelimitedString");
}
if (filterInvocationDefinitionMap.containsKey(matcher)) {
BeanDefinition key = keyBldr.getBeanDefinition();
if (filterInvocationDefinitionMap.containsKey(key)) {
logger.warn("Duplicate URL defined: " + path + ". The original attribute values will be overwritten");
}
filterInvocationDefinitionMap.put(matcher, attributeBuilder.getBeanDefinition());
filterInvocationDefinitionMap.put(key, attributeBuilder.getBeanDefinition());
}
return filterInvocationDefinitionMap;
@@ -29,8 +29,6 @@ public class FormLoginBeanDefinitionParser {
private static final String ATT_FORM_LOGIN_TARGET_URL = "default-target-url";
private static final String ATT_ALWAYS_USE_DEFAULT_TARGET_URL = "always-use-default-target";
private static final String DEF_FORM_LOGIN_TARGET_URL = "/";
private static final String ATT_USERNAME_PARAMETER = "username-parameter";
private static final String ATT_PASSWORD_PARAMETER = "password-parameter";
private static final String ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL = "authentication-failure-url";
private static final String DEF_FORM_LOGIN_AUTHENTICATION_FAILURE_URL =
@@ -65,10 +63,6 @@ public class FormLoginBeanDefinitionParser {
String alwaysUseDefault = null;
String successHandlerRef = null;
String failureHandlerRef = null;
// Only available with form-login
String usernameParameter = null;
String passwordParameter = null;
String authDetailsSourceRef = null;
Object source = null;
@@ -84,27 +78,15 @@ public class FormLoginBeanDefinitionParser {
loginPage = elt.getAttribute(ATT_LOGIN_PAGE);
successHandlerRef = elt.getAttribute(ATT_SUCCESS_HANDLER_REF);
failureHandlerRef = elt.getAttribute(ATT_FAILURE_HANDLER_REF);
authDetailsSourceRef = elt.getAttribute(AuthenticationConfigBuilder.ATT_AUTH_DETAILS_SOURCE_REF);
if (!StringUtils.hasText(loginPage)) {
loginPage = null;
}
WebConfigUtils.validateHttpRedirect(loginPage, pc, source);
usernameParameter = elt.getAttribute(ATT_USERNAME_PARAMETER);
passwordParameter = elt.getAttribute(ATT_PASSWORD_PARAMETER);
}
filterBean = createFilterBean(loginUrl, defaultTargetUrl, alwaysUseDefault, loginPage, authenticationFailureUrl,
successHandlerRef, failureHandlerRef, authDetailsSourceRef);
if (StringUtils.hasText(usernameParameter)) {
filterBean.getPropertyValues().addPropertyValue("usernameParameter", usernameParameter);
}
if (StringUtils.hasText(passwordParameter)) {
filterBean.getPropertyValues().addPropertyValue("passwordParameter", passwordParameter);
}
successHandlerRef, failureHandlerRef);
filterBean.setSource(source);
BeanDefinitionBuilder entryPointBuilder =
@@ -117,8 +99,7 @@ public class FormLoginBeanDefinitionParser {
}
private RootBeanDefinition createFilterBean(String loginUrl, String defaultTargetUrl, String alwaysUseDefault,
String loginPage, String authenticationFailureUrl, String successHandlerRef, String failureHandlerRef,
String authDetailsSourceRef) {
String loginPage, String authenticationFailureUrl, String successHandlerRef, String failureHandlerRef) {
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(filterClassName);
@@ -140,10 +121,6 @@ public class FormLoginBeanDefinitionParser {
filterBuilder.addPropertyValue("authenticationSuccessHandler", successHandler.getBeanDefinition());
}
if (StringUtils.hasText(authDetailsSourceRef)) {
filterBuilder.addPropertyReference("authenticationDetailsSource", authDetailsSourceRef);
}
if (sessionStrategy != null) {
filterBuilder.addPropertyValue("sessionAuthenticationStrategy", sessionStrategy);
}
@@ -1,11 +1,14 @@
package org.springframework.security.config.http;
import static org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.*;
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;
import java.util.List;
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.RuntimeBeanReference;
@@ -22,7 +25,6 @@ import org.springframework.security.access.vote.AuthenticatedVoter;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.config.Elements;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.PortResolverImpl;
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
@@ -33,19 +35,17 @@ import org.springframework.security.web.access.channel.SecureChannelProcessor;
import org.springframework.security.web.access.expression.WebExpressionVoter;
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.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy;
import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.NullSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.NullRequestCache;
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.security.web.util.AntUrlPathMatcher;
import org.springframework.security.web.util.UrlMatcher;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
@@ -58,6 +58,9 @@ import org.w3c.dom.Element;
*/
class HttpConfigurationBuilder {
private static final String ATT_CREATE_SESSION = "create-session";
private static final String OPT_CREATE_SESSION_NEVER = "never";
private static final String DEF_CREATE_SESSION_IF_REQUIRED = "ifRequired";
private static final String OPT_CREATE_SESSION_ALWAYS = "always";
private static final String ATT_SESSION_FIXATION_PROTECTION = "session-fixation-protection";
private static final String OPT_SESSION_FIXATION_NO_PROTECTION = "none";
@@ -73,60 +76,66 @@ class HttpConfigurationBuilder {
private static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
private static final String ATT_ONCE_PER_REQUEST = "once-per-request";
private static final String ATT_REF = "ref";
private final Element httpElt;
private final ParserContext pc;
private final SessionCreationPolicy sessionPolicy;
private final UrlMatcher matcher;
private final Boolean convertPathsToLowerCase;
private final boolean allowSessionCreation;
private final List<Element> interceptUrls;
private final MatcherType matcherType;
// Use ManagedMap to allow placeholder resolution
private ManagedMap<Object, List<BeanMetadataElement>> filterChainMap;
private BeanDefinition cpf;
private BeanDefinition securityContextPersistenceFilter;
private BeanReference contextRepoRef;
private BeanReference sessionRegistryRef;
private BeanDefinition concurrentSessionFilter;
private BeanDefinition requestCacheAwareFilter;
private BeanReference sessionStrategyRef;
private RootBeanDefinition sfpf;
private BeanDefinition servApiFilter;
private BeanDefinition jaasApiFilter;
private final String portMapperName;
private String portMapperName;
private BeanReference fsi;
private BeanReference requestCache;
public HttpConfigurationBuilder(Element element, ParserContext pc, MatcherType matcherType,
String portMapperName, BeanReference authenticationManager) {
public HttpConfigurationBuilder(Element element, ParserContext pc, UrlMatcher matcher, String portMapperName) {
this.httpElt = element;
this.pc = pc;
this.portMapperName = portMapperName;
this.matcherType = matcherType;
this.matcher = matcher;
// SEC-501 - should paths stored in request maps be converted to lower case
// true if Ant path and using lower case
convertPathsToLowerCase = (matcher instanceof AntUrlPathMatcher) && matcher.requiresLowerCaseUrl();
interceptUrls = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_URL);
allowSessionCreation = !OPT_CREATE_SESSION_NEVER.equals(element.getAttribute(ATT_CREATE_SESSION));
}
void parseInterceptUrlsForEmptyFilterChains() {
filterChainMap = new ManagedMap<Object, List<BeanMetadataElement>>();
for (Element urlElt : interceptUrls) {
if (StringUtils.hasText(urlElt.getAttribute(ATT_FILTERS))) {
pc.getReaderContext().error("The use of \"filters='none'\" is no longer supported. Please define a" +
" separate <http> element for the pattern you want to exclude and use the attribute" +
" \"security='none'\".", pc.extractSource(urlElt));
String path = urlElt.getAttribute(ATT_PATH_PATTERN);
if(!StringUtils.hasText(path)) {
pc.getReaderContext().error("path attribute cannot be empty or null", urlElt);
}
BeanDefinitionBuilder pathBean = BeanDefinitionBuilder.rootBeanDefinition(HttpConfigurationBuilder.class);
pathBean.setFactoryMethod("createPath");
pathBean.addConstructorArgValue(path);
pathBean.addConstructorArgValue(convertPathsToLowerCase);
String filters = urlElt.getAttribute(ATT_FILTERS);
if (StringUtils.hasText(filters)) {
if (!filters.equals(OPT_FILTERS_NONE)) {
pc.getReaderContext().error("Currently only 'none' is supported as the custom " +
"filters attribute", urlElt);
}
List<BeanMetadataElement> noFilters = Collections.emptyList();
filterChainMap.put(pathBean.getBeanDefinition(), noFilters);
}
}
String createSession = element.getAttribute(ATT_CREATE_SESSION);
if (StringUtils.hasText(createSession)) {
sessionPolicy = SessionCreationPolicy.valueOf(createSession);
} else {
sessionPolicy = SessionCreationPolicy.ifRequired;
}
createSecurityContextPersistenceFilter();
createSessionManagementFilters();
createRequestCacheFilter();
createServletApiFilter();
createJaasApiFilter();
createChannelProcessingFilter();
createFilterSecurityInterceptor(authenticationManager);
}
// Needed to account for placeholders
@@ -134,44 +143,43 @@ class HttpConfigurationBuilder {
return lowerCase ? path.toLowerCase() : path;
}
private void createSecurityContextPersistenceFilter() {
void createSecurityContextPersistenceFilter() {
BeanDefinitionBuilder scpf = BeanDefinitionBuilder.rootBeanDefinition(SecurityContextPersistenceFilter.class);
String repoRef = httpElt.getAttribute(ATT_SECURITY_CONTEXT_REPOSITORY);
String createSession = httpElt.getAttribute(ATT_CREATE_SESSION);
String disableUrlRewriting = httpElt.getAttribute(ATT_DISABLE_URL_REWRITING);
if (StringUtils.hasText(repoRef)) {
if (sessionPolicy == SessionCreationPolicy.always) {
if (OPT_CREATE_SESSION_ALWAYS.equals(createSession)) {
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
} else if (StringUtils.hasText(createSession)) {
pc.getReaderContext().error("If using security-context-repository-ref, the only value you can set for " +
"'create-session' is 'always'. Other session creation logic should be handled by the " +
"SecurityContextRepository", httpElt);
}
} else {
BeanDefinitionBuilder contextRepo;
if (sessionPolicy == SessionCreationPolicy.stateless) {
contextRepo = BeanDefinitionBuilder.rootBeanDefinition(NullSecurityContextRepository.class);
BeanDefinitionBuilder contextRepo = BeanDefinitionBuilder.rootBeanDefinition(HttpSessionSecurityContextRepository.class);
if (OPT_CREATE_SESSION_ALWAYS.equals(createSession)) {
contextRepo.addPropertyValue("allowSessionCreation", Boolean.TRUE);
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
} else if (OPT_CREATE_SESSION_NEVER.equals(createSession)) {
contextRepo.addPropertyValue("allowSessionCreation", Boolean.FALSE);
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
} else {
contextRepo = BeanDefinitionBuilder.rootBeanDefinition(HttpSessionSecurityContextRepository.class);
switch (sessionPolicy) {
case always:
contextRepo.addPropertyValue("allowSessionCreation", Boolean.TRUE);
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.TRUE);
break;
case never:
contextRepo.addPropertyValue("allowSessionCreation", Boolean.FALSE);
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
break;
default:
contextRepo.addPropertyValue("allowSessionCreation", Boolean.TRUE);
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
}
createSession = DEF_CREATE_SESSION_IF_REQUIRED;
contextRepo.addPropertyValue("allowSessionCreation", Boolean.TRUE);
scpf.addPropertyValue("forceEagerSessionCreation", Boolean.FALSE);
}
if ("true".equals(disableUrlRewriting)) {
contextRepo.addPropertyValue("disableUrlRewriting", Boolean.TRUE);
}
if ("true".equals(disableUrlRewriting)) {
contextRepo.addPropertyValue("disableUrlRewriting", Boolean.TRUE);
}
BeanDefinition repoBean = contextRepo.getBeanDefinition();
repoRef = pc.getReaderContext().generateBeanName(repoBean);
pc.registerBeanComponent(new BeanComponentDefinition(repoBean, repoRef));
}
contextRepoRef = new RuntimeBeanReference(repoRef);
@@ -180,7 +188,7 @@ class HttpConfigurationBuilder {
securityContextPersistenceFilter = scpf.getBeanDefinition();
}
private void createSessionManagementFilters() {
void createSessionManagementFilters() {
Element sessionMgmtElt = DomUtils.getChildElementByTagName(httpElt, Elements.SESSION_MANAGEMENT);
Element sessionCtrlElt = null;
@@ -190,11 +198,6 @@ class HttpConfigurationBuilder {
String errorUrl = null;
if (sessionMgmtElt != null) {
if (sessionPolicy == SessionCreationPolicy.stateless) {
pc.getReaderContext().error(Elements.SESSION_MANAGEMENT + " cannot be used" +
" in combination with " + ATT_CREATE_SESSION + "='"+ SessionCreationPolicy.stateless +"'",
pc.extractSource(sessionMgmtElt));
}
sessionFixationAttribute = sessionMgmtElt.getAttribute(ATT_SESSION_FIXATION_PROTECTION);
invalidSessionUrl = sessionMgmtElt.getAttribute(ATT_INVALID_SESSION_URL);
sessionAuthStratRef = sessionMgmtElt.getAttribute(ATT_SESSION_AUTH_STRATEGY_REF);
@@ -214,12 +217,7 @@ class HttpConfigurationBuilder {
sessionFixationAttribute = OPT_SESSION_FIXATION_MIGRATE_SESSION;
} else if (StringUtils.hasText(sessionAuthStratRef)) {
pc.getReaderContext().error(ATT_SESSION_FIXATION_PROTECTION + " attribute cannot be used" +
" in combination with " + ATT_SESSION_AUTH_STRATEGY_REF, pc.extractSource(sessionMgmtElt));
}
if (sessionPolicy == SessionCreationPolicy.stateless) {
// SEC-1424: do nothing
return;
" in combination with " + ATT_SESSION_AUTH_STRATEGY_REF, pc.extractSource(sessionCtrlElt));
}
boolean sessionFixationProtectionRequired = !sessionFixationAttribute.equals(OPT_SESSION_FIXATION_NO_PROTECTION);
@@ -326,7 +324,7 @@ class HttpConfigurationBuilder {
}
// Adds the servlet-api integration filter if required
private void createServletApiFilter() {
void createServletApiFilter() {
final String ATT_SERVLET_API_PROVISION = "servlet-api-provision";
final String DEF_SERVLET_API_PROVISION = "true";
@@ -339,23 +337,8 @@ class HttpConfigurationBuilder {
servApiFilter = new RootBeanDefinition(SecurityContextHolderAwareRequestFilter.class);
}
}
// Adds the jaas-api integration filter if required
private void createJaasApiFilter() {
final String ATT_JAAS_API_PROVISION = "jaas-api-provision";
final String DEF_JAAS_API_PROVISION = "false";
String provideJaasApi = httpElt.getAttribute(ATT_JAAS_API_PROVISION);
if (!StringUtils.hasText(provideJaasApi)) {
provideJaasApi = DEF_JAAS_API_PROVISION;
}
if ("true".equals(provideJaasApi)) {
jaasApiFilter = new RootBeanDefinition(JaasApiIntegrationFilter.class);
}
}
private void createChannelProcessingFilter() {
void createChannelProcessingFilter() {
ManagedMap<BeanDefinition,BeanDefinition> channelRequestMap = parseInterceptUrlsForChannelSecurity();
if (channelRequestMap.isEmpty()) {
@@ -364,8 +347,9 @@ class HttpConfigurationBuilder {
RootBeanDefinition channelFilter = new RootBeanDefinition(ChannelProcessingFilter.class);
BeanDefinitionBuilder metadataSourceBldr = BeanDefinitionBuilder.rootBeanDefinition(DefaultFilterInvocationSecurityMetadataSource.class);
metadataSourceBldr.addConstructorArgValue(matcher);
metadataSourceBldr.addConstructorArgValue(channelRequestMap);
// metadataSourceBldr.addPropertyValue("stripQueryStringFromUrls", matcher instanceof AntUrlPathMatcher);
metadataSourceBldr.addPropertyValue("stripQueryStringFromUrls", matcher instanceof AntUrlPathMatcher);
channelFilter.getPropertyValues().addPropertyValue("securityMetadataSource", metadataSourceBldr.getBeanDefinition());
RootBeanDefinition channelDecisionManager = new RootBeanDefinition(ChannelDecisionManagerImpl.class);
@@ -398,58 +382,45 @@ class HttpConfigurationBuilder {
for (Element urlElt : interceptUrls) {
String path = urlElt.getAttribute(ATT_PATH_PATTERN);
String method = urlElt.getAttribute(ATT_HTTP_METHOD);
if(!StringUtils.hasText(path)) {
pc.getReaderContext().error("pattern attribute cannot be empty or null", urlElt);
pc.getReaderContext().error("path attribute cannot be empty or null", urlElt);
}
if (convertPathsToLowerCase) {
path = path.toLowerCase();
}
String requiredChannel = urlElt.getAttribute(ATT_REQUIRES_CHANNEL);
if (StringUtils.hasText(requiredChannel)) {
BeanDefinition matcher = matcherType.createMatcher(path, method);
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");
channelRequestMap.put(matcher, channelAttributes);
channelRequestMap.put(requestKey, channelAttributes);
}
}
return channelRequestMap;
}
private void createRequestCacheFilter() {
Element requestCacheElt = DomUtils.getChildElementByTagName(httpElt, Elements.REQUEST_CACHE);
if (requestCacheElt != null) {
requestCache = new RuntimeBeanReference(requestCacheElt.getAttribute(ATT_REF));
} else {
BeanDefinitionBuilder requestCacheBldr;
if (sessionPolicy == SessionCreationPolicy.stateless) {
requestCacheBldr = BeanDefinitionBuilder.rootBeanDefinition(NullRequestCache.class);
} else {
requestCacheBldr = BeanDefinitionBuilder.rootBeanDefinition(HttpSessionRequestCache.class);
BeanDefinitionBuilder portResolver = BeanDefinitionBuilder.rootBeanDefinition(PortResolverImpl.class);
portResolver.addPropertyReference("portMapper", portMapperName);
requestCacheBldr.addPropertyValue("createSessionAllowed", sessionPolicy == SessionCreationPolicy.ifRequired);
requestCacheBldr.addPropertyValue("portResolver", portResolver.getBeanDefinition());
}
BeanDefinition bean = requestCacheBldr.getBeanDefinition();
String id = pc.getReaderContext().generateBeanName(bean);
pc.registerBeanComponent(new BeanComponentDefinition(bean, id));
this.requestCache = new RuntimeBeanReference(id);
}
requestCacheAwareFilter = new RootBeanDefinition(RequestCacheAwareFilter.class);
requestCacheAwareFilter.getPropertyValues().addPropertyValue("requestCache", requestCache);
}
private void createFilterSecurityInterceptor(BeanReference authManager) {
void createFilterSecurityInterceptor(BeanReference authManager) {
boolean useExpressions = FilterInvocationSecurityMetadataSourceParser.isUseExpressions(httpElt);
BeanDefinition securityMds = FilterInvocationSecurityMetadataSourceParser.createSecurityMetadataSource(interceptUrls, httpElt, pc);
@@ -457,12 +428,7 @@ class HttpConfigurationBuilder {
ManagedList<BeanDefinition> voters = new ManagedList<BeanDefinition>(2);
if (useExpressions) {
BeanDefinitionBuilder expressionVoter = BeanDefinitionBuilder.rootBeanDefinition(WebExpressionVoter.class);
RuntimeBeanReference expressionHandler = new RuntimeBeanReference(
FilterInvocationSecurityMetadataSourceParser.registerDefaultExpressionHandler(pc));
expressionVoter.addPropertyValue("expressionHandler", expressionHandler);
voters.add(expressionVoter.getBeanDefinition());
voters.add(new RootBeanDefinition(WebExpressionVoter.class));
} else {
voters.add(new RootBeanDefinition(RoleVoter.class));
voters.add(new RootBeanDefinition(AuthenticatedVoter.class));
@@ -506,12 +472,13 @@ class HttpConfigurationBuilder {
return sessionStrategyRef;
}
SessionCreationPolicy getSessionCreationPolicy() {
return sessionPolicy;
boolean isAllowSessionCreation() {
return allowSessionCreation;
}
BeanReference getRequestCache() {
return requestCache;
public ManagedMap<Object, List<BeanMetadataElement>> getFilterChainMap() {
return filterChainMap;
}
List<OrderDecorator> getFilters() {
@@ -531,20 +498,12 @@ class HttpConfigurationBuilder {
filters.add(new OrderDecorator(servApiFilter, SERVLET_API_SUPPORT_FILTER));
}
if (jaasApiFilter != null) {
filters.add(new OrderDecorator(jaasApiFilter, JAAS_API_SUPPORT_FILTER));
}
if (sfpf != null) {
filters.add(new OrderDecorator(sfpf, SESSION_MANAGEMENT_FILTER));
}
filters.add(new OrderDecorator(fsi, FILTER_SECURITY_INTERCEPTOR));
if (sessionPolicy != SessionCreationPolicy.stateless) {
filters.add(new OrderDecorator(requestCacheAwareFilter, REQUEST_CACHE_FILTER));
}
return filters;
}
}
@@ -3,7 +3,9 @@ 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;
@@ -26,11 +28,10 @@ public class HttpFirewallBeanDefinitionParser implements BeanDefinitionParser {
pc.getReaderContext().error("ref attribute is required", pc.extractSource(element));
}
HttpSecurityBeanDefinitionParser.registerFilterChainProxy(pc,
new ManagedMap<BeanDefinition, List<BeanMetadataElement>>(),
pc.extractSource(element));
BeanDefinition filterChainProxy = pc.getRegistry().getBeanDefinition(BeanIds.FILTER_CHAIN_PROXY);
filterChainProxy.getPropertyValues().addPropertyValue("firewall", new RuntimeBeanReference(ref));
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;
}
}
@@ -1,5 +1,7 @@
package org.springframework.security.config.http;
import static org.springframework.security.config.http.SecurityFilters.REQUEST_CACHE_FILTER;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -12,7 +14,6 @@ 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.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@@ -28,7 +29,10 @@ import org.springframework.security.config.BeanIds;
import org.springframework.security.config.Elements;
import org.springframework.security.config.authentication.AuthenticationManagerFactoryBean;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.util.AnyRequestMatcher;
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
import org.springframework.security.web.util.AntUrlPathMatcher;
import org.springframework.security.web.util.RegexUrlPathMatcher;
import org.springframework.security.web.util.UrlMatcher;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
@@ -44,16 +48,24 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
private static final Log logger = LogFactory.getLog(HttpSecurityBeanDefinitionParser.class);
static final String ATT_PATH_PATTERN = "pattern";
static final String ATT_HTTP_METHOD = "method";
static final String ATT_PATH_TYPE = "path-type";
static final String OPT_PATH_TYPE_REGEX = "regex";
private static final String DEF_PATH_TYPE_ANT = "ant";
static final String ATT_FILTERS = "filters";
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";
private static final String ATT_REF = "ref";
private static final String ATT_SECURED = "security";
private static final String OPT_SECURITY_NONE = "none";
static final String EXPRESSION_FIMDS_CLASS = "org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource";
static final String EXPRESSION_HANDLER_CLASS = "org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler";
static final List<BeanMetadataElement> NO_FILTERS = Collections.emptyList();
public HttpSecurityBeanDefinitionParser() {
}
@@ -70,69 +82,54 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element));
pc.pushContainingComponent(compositeDef);
MatcherType matcherType = MatcherType.fromElement(element);
ManagedMap<BeanDefinition, List<BeanMetadataElement>> filterChainMap = new ManagedMap<BeanDefinition, List<BeanMetadataElement>>();
String filterChainPattern = element.getAttribute(ATT_PATH_PATTERN);
BeanDefinition filterChainMatcher;
if (StringUtils.hasText(filterChainPattern)) {
filterChainMatcher = matcherType.createMatcher(filterChainPattern, null);
} else {
filterChainMatcher = new RootBeanDefinition(AnyRequestMatcher.class);
}
filterChainMap.put(filterChainMatcher, createFilterChain(element, pc, matcherType));
registerFilterChainProxy(pc, filterChainMap, pc.extractSource(element));
pc.popAndRegisterContainingComponent();
return null;
}
List<BeanMetadataElement> createFilterChain(Element element, ParserContext pc, MatcherType matcherType) {
boolean secured = !OPT_SECURITY_NONE.equals(element.getAttribute(ATT_SECURED));
if (!secured) {
if (!StringUtils.hasText(element.getAttribute(ATT_PATH_PATTERN))) {
pc.getReaderContext().error("The '" + ATT_SECURED + "' attribute must be used in combination with" +
" the '" + ATT_PATH_PATTERN +"' attribute.", pc.extractSource(element));
}
for (int n=0; n < element.getChildNodes().getLength(); n ++) {
if (element.getChildNodes().item(n) instanceof Element) {
pc.getReaderContext().error("If you are using <http> to define an unsecured pattern, " +
"it cannot contain child elements.", pc.extractSource(element));
}
}
return Collections.emptyList();
}
final Object source = pc.extractSource(element);
final String portMapperName = createPortMapper(element, pc);
final UrlMatcher matcher = createUrlMatcher(element);
HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, pc, matcher, portMapperName);
httpBldr.parseInterceptUrlsForEmptyFilterChains();
httpBldr.createSecurityContextPersistenceFilter();
httpBldr.createSessionManagementFilters();
ManagedList<BeanReference> authenticationProviders = new ManagedList<BeanReference>();
BeanReference authenticationManager = createAuthenticationManager(element, pc, authenticationProviders);
BeanReference authenticationManager = createAuthenticationManager(element, pc, authenticationProviders, null);
HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, pc, matcherType,
portMapperName, authenticationManager);
httpBldr.createServletApiFilter();
httpBldr.createChannelProcessingFilter();
httpBldr.createFilterSecurityInterceptor(authenticationManager);
AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, pc,
httpBldr.getSessionCreationPolicy(), httpBldr.getRequestCache(), authenticationManager,
httpBldr.getSessionStrategy());
httpBldr.isAllowSessionCreation(), portMapperName);
authenticationProviders.addAll(authBldr.getProviders());
authBldr.createAnonymousFilter();
authBldr.createRememberMeFilter(authenticationManager);
authBldr.createRequestCache();
authBldr.createBasicFilter(authenticationManager);
authBldr.createFormLoginFilter(httpBldr.getSessionStrategy(), authenticationManager);
authBldr.createOpenIDLoginFilter(httpBldr.getSessionStrategy(), authenticationManager);
authBldr.createX509Filter(authenticationManager);
authBldr.createLogoutFilter();
authBldr.createLoginPageFilterIfNeeded();
authBldr.createUserServiceInjector();
authBldr.createExceptionTranslationFilter();
List<OrderDecorator> unorderedFilterChain = new ArrayList<OrderDecorator>();
unorderedFilterChain.addAll(httpBldr.getFilters());
unorderedFilterChain.addAll(authBldr.getFilters());
authenticationProviders.addAll(authBldr.getProviders());
BeanDefinition requestCacheAwareFilter = new RootBeanDefinition(RequestCacheAwareFilter.class);
requestCacheAwareFilter.getPropertyValues().addPropertyValue("requestCache", authBldr.getRequestCache());
unorderedFilterChain.add(new OrderDecorator(requestCacheAwareFilter, REQUEST_CACHE_FILTER));
unorderedFilterChain.addAll(buildCustomFilterList(element, pc));
Collections.sort(unorderedFilterChain, new OrderComparator());
checkFilterChainOrder(unorderedFilterChain, pc, pc.extractSource(element));
checkFilterChainOrder(unorderedFilterChain, pc, source);
List<BeanMetadataElement> filterChain = new ManagedList<BeanMetadataElement>();
@@ -140,9 +137,14 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
filterChain.add(od.bean);
}
return filterChain;
}
ManagedMap<Object, List<BeanMetadataElement>> filterChainMap = httpBldr.getFilterChainMap();
filterChainMap.put(matcher.getUniversalMatchPattern(), filterChain);
registerFilterChainProxy(pc, filterChainMap, matcher, source);
pc.popAndRegisterContainingComponent();
return null;
}
private String createPortMapper(Element elt, ParserContext pc) {
// Register the portMapper. A default will always be created, even if no element exists.
@@ -162,7 +164,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
* authentication manager.
*/
private BeanReference createAuthenticationManager(Element element, ParserContext pc,
ManagedList<BeanReference> authenticationProviders) {
ManagedList<BeanReference> authenticationProviders, BeanReference concurrencyController) {
BeanDefinitionBuilder authManager = BeanDefinitionBuilder.rootBeanDefinition(ProviderManager.class);
authManager.addPropertyValue("parent", new RootBeanDefinition(AuthenticationManagerFactoryBean.class));
authManager.addPropertyValue("providers", authenticationProviders);
@@ -171,6 +173,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
clearCredentials.getPropertyValues().addPropertyValue("targetMethod", "isEraseCredentialsAfterAuthentication");
authManager.addPropertyValue("eraseCredentialsAfterAuthentication", clearCredentials);
if (concurrencyController != null) {
authManager.addPropertyValue("sessionController", concurrencyController);
}
authManager.getRawBeanDefinition().setSource(pc.extractSource(element));
BeanDefinition authMgrBean = authManager.getBeanDefinition();
String id = pc.getReaderContext().generateBeanName(authMgrBean);
@@ -183,10 +188,10 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
logger.info("Checking sorted filter chain: " + filters);
for(int i=0; i < filters.size(); i++) {
OrderDecorator filter = filters.get(i);
OrderDecorator filter = (OrderDecorator)filters.get(i);
if (i > 0) {
OrderDecorator previous = filters.get(i-1);
OrderDecorator previous = (OrderDecorator)filters.get(i-1);
if (filter.getOrder() == previous.getOrder()) {
pc.getReaderContext().error("Filter beans '" + filter.bean + "' and '" +
previous.bean + "' have the same 'order' value. When using custom filters, " +
@@ -246,39 +251,62 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
return customFilters;
}
@SuppressWarnings("unchecked")
static void registerFilterChainProxy(ParserContext pc, Map<BeanDefinition, List<BeanMetadataElement>> filterChainMap, Object source) {
private void registerFilterChainProxy(ParserContext pc, Map<Object, List<BeanMetadataElement>> filterChainMap, UrlMatcher matcher, Object source) {
if (pc.getRegistry().containsBeanDefinition(BeanIds.FILTER_CHAIN_PROXY)) {
// Already registered. Obtain the filter chain map and add the new entries to it
BeanDefinition fcp = pc.getRegistry().getBeanDefinition(BeanIds.FILTER_CHAIN_PROXY);
Map existingFilterChainMap = (Map) fcp.getPropertyValues().getPropertyValue("filterChainMap").getValue();
for (BeanDefinition matcherBean : filterChainMap.keySet()) {
if (existingFilterChainMap.containsKey(matcherBean)) {
Map<Integer,ValueHolder> args = matcherBean.getConstructorArgumentValues().getIndexedArgumentValues();
pc.getReaderContext().error("The filter chain map already contains this request matcher ["
+ args.get(0).getValue() + ", " +args.get(1).getValue() + "]", source);
}
}
existingFilterChainMap.putAll(filterChainMap);
} else {
// Not already registered, so register it
BeanDefinitionBuilder fcpBldr = BeanDefinitionBuilder.rootBeanDefinition(FilterChainProxy.class);
fcpBldr.getRawBeanDefinition().setSource(source);
fcpBldr.addPropertyValue("filterChainMap", filterChainMap);
fcpBldr.addPropertyValue("filterChainValidator", new RootBeanDefinition(DefaultFilterChainValidator.class));
BeanDefinition fcpBean = fcpBldr.getBeanDefinition();
pc.registerBeanComponent(new BeanComponentDefinition(fcpBean, BeanIds.FILTER_CHAIN_PROXY));
pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
pc.getReaderContext().error("Duplicate <http> element detected", source);
}
BeanDefinitionBuilder fcpBldr = BeanDefinitionBuilder.rootBeanDefinition(FilterChainProxy.class);
fcpBldr.getRawBeanDefinition().setSource(source);
fcpBldr.addPropertyValue("matcher", matcher);
fcpBldr.addPropertyValue("stripQueryStringFromUrls", Boolean.valueOf(matcher instanceof AntUrlPathMatcher));
fcpBldr.addPropertyValue("filterChainMap", filterChainMap);
BeanDefinition fcpBean = fcpBldr.getBeanDefinition();
pc.registerBeanComponent(new BeanComponentDefinition(fcpBean, BeanIds.FILTER_CHAIN_PROXY));
pc.getRegistry().registerAlias(BeanIds.FILTER_CHAIN_PROXY, BeanIds.SPRING_SECURITY_FILTER_CHAIN);
}
static UrlMatcher createUrlMatcher(Element element) {
String patternType = element.getAttribute(ATT_PATH_TYPE);
if (!StringUtils.hasText(patternType)) {
patternType = DEF_PATH_TYPE_ANT;
}
boolean useRegex = patternType.equals(OPT_PATH_TYPE_REGEX);
UrlMatcher matcher = new AntUrlPathMatcher();
if (useRegex) {
matcher = new RegexUrlPathMatcher();
}
// Deal with lowercase conversion requests
String lowercaseComparisons = element.getAttribute(ATT_LOWERCASE_COMPARISONS);
if (!StringUtils.hasText(lowercaseComparisons)) {
lowercaseComparisons = null;
}
// Only change from the defaults if the attribute has been set
if ("true".equals(lowercaseComparisons)) {
if (useRegex) {
((RegexUrlPathMatcher)matcher).setRequiresLowerCaseUrl(true);
}
// Default for ant is already to force lower case
} else if ("false".equals(lowercaseComparisons)) {
if (!useRegex) {
((AntUrlPathMatcher)matcher).setRequiresLowerCaseUrl(false);
}
// Default for regex is no change
}
return matcher;
}
}
class OrderDecorator implements Ordered {
final BeanMetadataElement bean;
final int order;
BeanMetadataElement bean;
int order;
public OrderDecorator(BeanMetadataElement bean, SecurityFilters filterOrder) {
this.bean = bean;
@@ -4,10 +4,8 @@ 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.ManagedList;
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.web.authentication.logout.CookieClearingLogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.util.StringUtils;
@@ -22,13 +20,13 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
static final String DEF_LOGOUT_SUCCESS_URL = "/";
static final String ATT_INVALIDATE_SESSION = "invalidate-session";
static final String DEF_INVALIDATE_SESSION = "true";
static final String ATT_LOGOUT_URL = "logout-url";
static final String DEF_LOGOUT_URL = "/j_spring_security_logout";
static final String ATT_LOGOUT_HANDLER = "success-handler-ref";
static final String ATT_DELETE_COOKIES = "delete-cookies";
final String rememberMeServices;
String rememberMeServices;
public LogoutBeanDefinitionParser(String rememberMeServices) {
this.rememberMeServices = rememberMeServices;
@@ -40,7 +38,6 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
String successHandlerRef = null;
String logoutSuccessUrl = null;
String invalidateSession = null;
String deleteCookies = null;
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(LogoutFilter.class);
@@ -53,7 +50,6 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
logoutSuccessUrl = element.getAttribute(ATT_LOGOUT_SUCCESS_URL);
WebConfigUtils.validateHttpRedirect(logoutSuccessUrl, pc, source);
invalidateSession = element.getAttribute(ATT_INVALIDATE_SESSION);
deleteCookies = element.getAttribute(ATT_DELETE_COOKIES);
}
if (!StringUtils.hasText(logoutUrl)) {
@@ -63,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);
@@ -75,22 +71,23 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
builder.addConstructorArgValue(logoutSuccessUrl);
}
if (!StringUtils.hasText(invalidateSession)) {
invalidateSession = DEF_INVALIDATE_SESSION;
}
ManagedList handlers = new ManagedList();
BeanDefinition sclh = new RootBeanDefinition(SecurityContextLogoutHandler.class);
sclh.getPropertyValues().addPropertyValue("invalidateHttpSession", !"false".equals(invalidateSession));
SecurityContextLogoutHandler sclh = new SecurityContextLogoutHandler();
if ("true".equals(invalidateSession)) {
sclh.setInvalidateHttpSession(true);
} else {
sclh.setInvalidateHttpSession(false);
}
handlers.add(sclh);
if (rememberMeServices != null) {
handlers.add(new RuntimeBeanReference(rememberMeServices));
}
if (StringUtils.hasText(deleteCookies)) {
BeanDefinition cookieDeleter = new RootBeanDefinition(CookieClearingLogoutHandler.class);
String[] names = StringUtils.commaDelimitedListToStringArray(deleteCookies);
cookieDeleter.getConstructorArgumentValues().addGenericArgumentValue(names);
handlers.add(cookieDeleter);
}
builder.addConstructorArgValue(handlers);
return builder.getBeanDefinition();
@@ -1,66 +0,0 @@
package org.springframework.security.config.http;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.security.web.util.AntPathRequestMatcher;
import org.springframework.security.web.util.AnyRequestMatcher;
import org.springframework.security.web.util.RegexRequestMatcher;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Defines the {@link RequestMatcher} types supported by the namespace.
*
* @author Luke Taylor
* @since 3.1
*/
public enum MatcherType {
ant (AntPathRequestMatcher.class),
regex (RegexRequestMatcher.class),
ciRegex (RegexRequestMatcher.class);
private static final Log logger = LogFactory.getLog(MatcherType.class);
private static final String ATT_MATCHER_TYPE = "request-matcher";
private static final String ATT_PATH_TYPE = "path-type";
private final Class<? extends RequestMatcher> type;
MatcherType(Class<? extends RequestMatcher> type) {
this.type = type;
}
public BeanDefinition createMatcher(String path, String method) {
if (("/**".equals(path) || "**".equals(path)) && method == null) {
return new RootBeanDefinition(AnyRequestMatcher.class);
}
BeanDefinitionBuilder matcherBldr = BeanDefinitionBuilder.rootBeanDefinition(type);
matcherBldr.addConstructorArgValue(path);
matcherBldr.addConstructorArgValue(method);
if (this == ciRegex) {
matcherBldr.addConstructorArgValue(true);
}
return matcherBldr.getBeanDefinition();
}
static MatcherType fromElement(Element elt) {
if (StringUtils.hasText(elt.getAttribute(ATT_MATCHER_TYPE))) {
return valueOf(elt.getAttribute(ATT_MATCHER_TYPE));
}
if (StringUtils.hasText(elt.getAttribute(ATT_PATH_TYPE))) {
logger.warn("'" + ATT_PATH_TYPE + "' is deprecated. Please use '" + ATT_MATCHER_TYPE +"' instead.");
return valueOf(elt.getAttribute(ATT_PATH_TYPE));
}
return ant;
}
}
@@ -10,7 +10,6 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
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.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices;
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter;
@@ -88,19 +87,16 @@ class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
}
if (services != null) {
RootBeanDefinition uds = new RootBeanDefinition();
uds.setFactoryBeanName(BeanIds.USER_DETAILS_SERVICE_FACTORY);
uds.setFactoryMethodName("cachingUserDetailsService");
uds.getConstructorArgumentValues().addGenericArgumentValue(userServiceRef);
services.getPropertyValues().addPropertyValue("userDetailsService", uds);
if (userServiceSet) {
services.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(userServiceRef));
}
if ("true".equals(element.getAttribute(ATT_SECURE_COOKIE))) {
services.getPropertyValues().addPropertyValue("useSecureCookie", true);
}
if (tokenValiditySet) {
Integer tokenValidity = Integer.valueOf(tokenValiditySeconds);
Integer tokenValidity = new Integer(tokenValiditySeconds);
if (tokenValidity.intValue() < 0 && isPersistent) {
pc.getReaderContext().error(ATT_TOKEN_VALIDITY + " cannot be negative if using" +
" a persistent remember-me token repository", source);

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