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

Compare commits

..

205 Commits

Author SHA1 Message Date
Rob Winch 0a48b38179 Fix NoClassDefFoundError from Gradle upgradle 2013-12-05 11:37:45 -06:00
Rob Winch 3074dd8193 Update to Gradle 1.9
This is necessary to work with the latest Bamboo and Artifactory Gradle plugin
2013-12-05 11:30:46 -06:00
Rob Winch 8d312a6365 SEC-2313: Gradle javadoc hotfix 2013-09-11 15:43:08 -07:00
Rob Winch 4ef184d520 Fix Gradle Eclipse/AspectJ integration 2012-11-02 10:40:39 -05:00
Rob Winch 0f6c3affda Revert "Added generatePom task"
This reverts commit cf9a392b0a.

No need to generate pom since pom already exists and is maintained.
2012-11-01 15:41:43 -05:00
Rob Winch cf9a392b0a Added generatePom task
This can be used to generate the pom.xml for adding the Spring Security
snapshot jars as a Maven Dependency to another project. For example,
if mywebapp requires the Spring Security 3.1.4.CI-SNAPSHOT jars one
could generate the pom.xml files and then use that to convert the project
into a valid Maven project within the IDE. Then the SNAPSHOT dependendies
could be added to mywebapp. This prevents the need to install the SNAPSHOT
dependencies in the local Maven repository.
2012-11-01 15:36:20 -05:00
Rob Winch 39918b4a01 Reserve Server Ports in integrationTests
Previously the build would look up a server port dynamically, but since
it closed the port immediately it may not be reserved by the time jetty
started up.

We now reserve the port and do not close it till just before Jetty starts.
While there is still a race condition, it is much smaller window of time
than it was previously.
2012-11-01 12:34:01 -05:00
Rob Winch 8f21d03832 SEC-2069: Update doc to use FilterInvocationSecurityMetadataSource 2012-10-22 14:28:10 -05:00
Rob Winch e9d12d2023 Next development version 2012-10-08 22:30:22 -05:00
Spring Buildmaster 6a61d07019 Release version 3.0.8.RELEASE 2012-10-08 22:29:48 -05: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
6961 changed files with 88719 additions and 558955 deletions
-22
View File
@@ -1,22 +0,0 @@
# EditorConfig for Spring Security
# see https://github.com/spring-projects/spring-security/blob/master/CONTRIBUTING.md#mind-the-whitespace
root = true
[*]
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 120
[*.{java,xml}]
indent_style = tab
indent_size = 4
charset = utf-8
continuation_indent_size = 8
ij_smart_tabs = false
ij_java_align_multiline_parameters = false
[*.gradle]
indent_style = tab
-40
View File
@@ -1,40 +0,0 @@
<!--
For Security Vulnerabilities, please use https://pivotal.io/security#reporting
-->
### Summary
<!--
Please provide a high level summary of the issue you are having
-->
### Actual Behavior
<!--
Please describe step by step the behavior you are observing
-->
### Expected Behavior
<!--
Please describe step by step the behavior you expect
-->
### Configuration
<!--
Please provide any configuration you have.
-->
### Version
<!--
Please describe what version you are using. Does the problem occur in other versions?
-->
### Sample
<!--
Providing a complete sample (i.e. link to a github repository) will give this issue higher
priority than issues that do not have a complete sample
-->
-24
View File
@@ -1,24 +0,0 @@
---
name: Bug
about: Create a bug report to help us improve
title: ''
labels: 'status: waiting-for-triage, type: bug'
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Sample**
A link to a GitHub repository with a [minimal, reproducible sample](https://stackoverflow.com/help/minimal-reproducible-example).
Reports that include a sample will take priority over reports that do not.
At times, we may require a sample, so it is good to try and include a sample up front.
-5
View File
@@ -1,5 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Community Support
url: https://stackoverflow.com/questions/tagged/spring-security
about: Please ask and answer questions on StackOverflow with the tag `spring-security`.
-25
View File
@@ -1,25 +0,0 @@
---
name: Enhancement
about: Suggest an enhancement for this project
title: ''
labels: 'status: waiting-for-triage, type: enhancement'
assignees: ''
---
**Expected Behavior**
<!--- Tell us how it should work -->
**Current Behavior**
<!--- Explain the difference from current behavior -->
**Context**
<!---
How has this issue affected you?
What are you trying to accomplish?
What other alternatives have you considered?
Are you aware of any workarounds?
-->
-9
View File
@@ -1,9 +0,0 @@
<!--
For Security Vulnerabilities, please use https://pivotal.io/security#reporting
-->
<!--
Before creating new features, we recommend creating an issue to discuss the feature. This ensures that everyone is on the same page before extensive work is done.
Thanks for contributing to Spring Security. Please provide a brief description of your pull-request and reference any related issue numbers (prefix references with gh-).
-->
-22
View File
@@ -1,22 +0,0 @@
name: PR Build
on: pull_request
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: '8'
- name: Cache Gradle packages
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
- name: Build with Gradle
run: ./gradlew clean build --continue --scan
+1 -10
View File
@@ -1,4 +1,3 @@
classes/
target/
*/src/*/java/META-INF
*/src/META-INF/
@@ -8,7 +7,7 @@ target/
.project
.DS_Store
.settings/
.idea/*
.idea/
out/
bin/
intellij/
@@ -20,11 +19,3 @@ build/
*.iws
.gradle/
atlassian-ide-plugin.xml
!etc/eclipse/.checkstyle
.checkstyle
s101plugin.state
.attach_pid*
.~lock.*#
!.idea/checkstyle-idea.xml
!.idea/externalDependencies.xml
-19
View File
@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CheckStyle-IDEA">
<option name="configuration">
<map>
<entry key="active-configuration" value="PROJECT_RELATIVE:$PROJECT_DIR$/etc/checkstyle/checkstyle.xml:spring-security" />
<entry key="checkstyle-version" value="8.14" />
<entry key="copy-libs" value="false" />
<entry key="location-0" value="BUNDLED:(bundled):Sun Checks" />
<entry key="location-1" value="BUNDLED:(bundled):Google Checks" />
<entry key="location-2" value="PROJECT_RELATIVE:$PROJECT_DIR$/etc/checkstyle/checkstyle.xml:spring-security" />
<entry key="property-2.config_loc" value="$PROJECT_DIR$/etc/checkstyle" />
<entry key="scan-before-checkin" value="false" />
<entry key="scanscope" value="JavaOnlyWithTests" />
<entry key="suppress-errors" value="false" />
</map>
</option>
</component>
</project>
-7
View File
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalDependencies">
<plugin id="CheckStyle-IDEA" />
<plugin id="org.jetbrains.plugins.gradle" />
</component>
</project>
-225
View File
@@ -1,225 +0,0 @@
_Have something you'd like to contribute to the framework? We welcome pull requests, but ask that you carefully read this document first to understand how best to submit them; what kind of changes are likely to be accepted; and what to expect from the Spring Security team when evaluating your submission._
_Please refer back to this document as a checklist before issuing any pull request; this will save time for everyone!_
= Code of Conduct
Please see our https://github.com/spring-projects/.github/blob/master/CODE_OF_CONDUCT.md[code of conduct].
= Similar but different
Each Spring module is slightly different from one another in terms of team size, number of issues, etc. Therefore, each project is managed slightly different. You will notice that this document is very similar to the https://github.com/spring-projects/spring-framework/wiki/Contributor-guidelines[Spring Framework Contributor guidelines]. However, there are some subtle differences between the two documents, so please be sure to read this document thoroughly.
= Importing into IDE
The following provides information on setting up a development environment that can run the sample in https://www.springsource.org/sts[Spring Tool Suite 3.6.0+]. Other IDE's should work using Gradle's IDE support, but have not been tested.
* IDE Setup
** Install Spring Tool Suite 3.6.0+
** You will need the following plugins installed (can be found on the Extensions Page)
*** Gradle Eclipse
*** Groovy Eclipse
* Importing the project into Spring Tool Suite
** File -> Import… -> Gradle Project
As of new versions of Spring Tool Suite, you might need to install Groovy Eclipse pointing directly to the updated plugin location. To install Groovy Eclipse on Spring Tool Suite based on Eclipse Oxigen you must do the following steps:
Help -> Install New Software… -> Add the following URL into _Work with_ field:
https://dist.springsource.org/snapshot/GRECLIPSE/e4.7/[https://dist.springsource.org/snapshot/GRECLIPSE/e4.7/]
= Understand the basics
Not sure what a pull request is, or how to submit one? Take a look at GitHub's excellent https://help.github.com/articles/using-pull-requests[help documentation first].
= Search GitHub issues; create an issue if necessary
Is there already an issue that addresses your concern? Do a bit of searching in our https://github.com/spring-projects/spring-security/issues[GitHub issues] to see if you can find something similar. If not, please create a new issue before submitting a pull request unless the change is not a user facing issue.
= Discuss non-trivial contribution ideas with committers
If you're considering anything more than correcting a typo or fixing a minor bug, please discuss it on the https://gitter.im/spring-projects/spring-security[Spring Security Gitter] before submitting a pull request. We're happy to provide guidance but please spend an hour or two researching the subject on your own including searching the forums for prior discussions.
= Sign the Contributor License Agreement
If you have not previously done so, please fill out and submit the https://cla.pivotal.io/sign/spring[Contributor License Agreement].
= Create your branch from master
Create your topic branch to be submitted as a pull request from master. The Spring team will consider your pull request for backporting on a case-by-case basis; you don't need to worry about submitting anything for backporting.
= Use short branch names
Branches used when submitting pull requests should preferably be named according to GitHub issues, e.g. `gh-1234` or `gh-1234-fix-npe`. Otherwise, use succinct, lower-case, dash (`-`) delimited names, such as `fix-warnings` or `fix-typo`. This is important, because branch names show up in the merge commits that result from accepting pull requests, and should be as expressive and concise as possible.
= Keep commits focused
Remember each ticket should be focused on a single item of interest since the tickets are used to produce the changelog. Since each commit should be tied to a single GitHub issue, ensure that your commits are focused. For example, do not include an update to a transitive library in your commit unless the GitHub is to update the library. Reviewing your commits is essential before sending a pull request.
= Mind the whitespace
Please carefully follow the whitespace and formatting conventions already present in the framework.
. Tabs, not spaces
. Unix (LF), not dos (CRLF) line endings
. Eliminate all trailing whitespace
. Aim to wrap code at 120 characters, but favor readability over wrapping
. Preserve existing formatting; i.e. do not reformat code for its own sake
. Search the codebase using `git grep` and other tools to discover common naming conventions, etc.
. UTF-8 encoding for Java sources and XML files
Whitespace management tips
. You can use the https://marketplace.eclipse.org/content/anyedit-tools[AnyEdit Eclipse plugin] to ensure spaces are used and to clean up trailing whitespaces.
. Use Git's `pre-commit.sample` hook to prevent invalid whitespace from being pushed out. You can enable it by moving `.git/hooks/pre-commit.sample` to `.git/hooks/pre-commit` and ensuring it is executable. For more information on hooks refer to https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks[https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks].
= Add Apache license header to all new classes
----
/*
* Copyright 2002-2020 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
*
* https://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 ...;
----
= Update Apache license header to modified files as necessary
Always check the date range in the license header. For example, if you've modified a file in 2020 whose header still reads
----
* Copyright 2002-2012 the original author or authors.
----
then be sure to update it to the current year appropriately (e.g. 2020)
----
* Copyright 2002-2020 the original author or authors.
----
= Use @since tags for newly-added public API types and methods
Example:
----
/**
* …
*
* @author First Last
* @since 5.4
* @see …
*/
----
= Submit JUnit test cases for all behavior changes
Search the codebase to find related unit tests and add additional `@Test` methods within.
. Any new tests should end in the name `Tests` (note this is plural). For example, a valid name would be `FilterChainProxyTests`. An invalid name would be `FilterChainProxyTest`.
. New test methods should not start with test. This is an old JUnit3 convention and is not necessary since the method is annotated with `@Test`.
= Update spring-security-x.y.rnc for schema changes
Update the https://www.relaxng.org[RELAX NG] schema `spring-security-x.y.rnc` instead of `spring-security-x.y.xsd` if you contribute changes to supported XML configuration. The XML schema file can be generated the following Gradle task:
Changes to the XML schema will be overwritten by the Gradle build task.
= Squash commits
Use `git rebase --interactive`, `git add --patch` and other tools to "squash" multiple commits into atomic changes. In addition to the man pages for `git`, there are https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History[many resources online] to help you understand how these tools work.
= Use real name in git commits
Please configure Git to use your real first and last name for any commits you intend to submit as pull requests. Make sure the name is properly capitalized as submitted to the https://cla.pivotal.io[Pivotal Contributor License Agreement]:
----
First Last <user@mail.com>
----
This helps ensure traceability against the CLA, and also goes a long way to ensuring useful output from tools like Git shortlog and others.
You can configure this globally:
----
git config --global user.name "First Last"
git config --global user.email user@example.com
----
or locally for the current repository by omitting the `--global` flag:
----
git config user.name "First Last"
git config user.email user@example.com
----
= Format commit messages
. Keep the subject line to 50 characters or less if possible
. Do not end the subject line with a period
. In the body of the commit message, explain how things worked before this commit, what has changed, and how things work now
. Include `Closes gh-<issue-number>` at the end if this fixes a GitHub issue
. Avoid markdown, including back-ticks identifying code
Example:
----
Short (50 chars or less) summary of changes
More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of an email and the rest of the text as the body. The blank
line separating the summary from the body is critical (unless you omit
the body entirely); tools like rebase can get confused if you run the
two together.
Further paragraphs come after blank lines.
- Bullet points are okay, too
- Typically a hyphen or asterisk is used for the bullet, preceded by a
single space, with blank lines in between, but conventions vary here
Closes gh-123
----
= Run all tests prior to submission
----
./gradlew clean build integrationTest
----
= Submit your pull request
*Subject line:*
Follow the same conventions for pull request subject lines as mentioned above for commit message subject lines.
*In the body:*
. Explain your use case. What led you to submit this change? Why were existing mechanisms in the framework insufficient? Make a case that this is a general-purpose problem and that yours is a general-purpose solution, etc
. Add any additional information and ask questions; start a conversation, or continue one from GitHub Issues
. Mention any GitHub Issues
. Also mention that you have submitted the CLA as described above
Note that for pull requests containing a single commit, GitHub will default the subject line and body of the pull request to match the subject line and body of the commit message. This is fine, but please also include the items above in the body of the request.
= Mention your pull request on the associated GitHub issue
Add a comment to the associated GitHub issue(s) linking to your new pull request.
= Expect discussion and rework
The Spring team takes a very conservative approach to accepting contributions to the framework. This is to keep code quality and stability as high as possible, and to keep complexity at a minimum. Your changes, if accepted, may be heavily modified prior to merging. You will retain "Author:" attribution for your Git commits granted that the bulk of your changes remain intact. You may be asked to rework the submission for style (as explained above) and/or substance. Again, we strongly recommend discussing any serious submissions with the Spring Framework team prior to engaging in serious development work.
Note that you can always force push (`git push -f`) reworked / rebased commits against the branch used to submit your pull request. i.e. you do not need to issue a new pull request when asked to make changes.
Vendored
-245
View File
@@ -1,245 +0,0 @@
def projectProperties = [
[$class: 'BuildDiscarderProperty',
strategy: [$class: 'LogRotator', numToKeepStr: '5']],
pipelineTriggers([cron('@daily')])
]
properties(projectProperties)
def SUCCESS = hudson.model.Result.SUCCESS.toString()
currentBuild.result = SUCCESS
def GRADLE_ENTERPRISE_CACHE_USER = usernamePassword(credentialsId: 'gradle_enterprise_cache_user',
passwordVariable: 'GRADLE_ENTERPRISE_CACHE_PASSWORD',
usernameVariable: 'GRADLE_ENTERPRISE_CACHE_USERNAME')
def GRADLE_ENTERPRISE_SECRET_ACCESS_KEY = string(credentialsId: 'gradle_enterprise_secret_access_key',
variable: 'GRADLE_ENTERPRISE_ACCESS_KEY')
def SPRING_SIGNING_SECRING = file(credentialsId: 'spring-signing-secring.gpg', variable: 'SIGNING_KEYRING_FILE')
def SPRING_GPG_PASSPHRASE = string(credentialsId: 'spring-gpg-passphrase', variable: 'SIGNING_PASSWORD')
def OSSRH_CREDENTIALS = usernamePassword(credentialsId: 'oss-token', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USERNAME')
def ARTIFACTORY_CREDENTIALS = usernamePassword(credentialsId: '02bd1690-b54f-4c9f-819d-a77cb7a9822c', usernameVariable: 'ARTIFACTORY_USERNAME', passwordVariable: 'ARTIFACTORY_PASSWORD')
def JENKINS_PRIVATE_SSH_KEY = file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')
def SONAR_LOGIN_CREDENTIALS = string(credentialsId: 'spring-sonar.login', variable: 'SONAR_LOGIN')
def jdkEnv(String jdk = 'jdk8') {
def jdkTool = tool(jdk)
return "JAVA_HOME=${ jdkTool }"
}
try {
parallel check: {
stage('Check') {
node {
checkout scm
sh "git clean -dfx"
try {
withCredentials([GRADLE_ENTERPRISE_CACHE_USER,
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY,
ARTIFACTORY_CREDENTIALS]) {
withEnv([jdkEnv(),
"GRADLE_ENTERPRISE_CACHE_USERNAME=${GRADLE_ENTERPRISE_CACHE_USERNAME}",
"GRADLE_ENTERPRISE_CACHE_PASSWORD=${GRADLE_ENTERPRISE_CACHE_PASSWORD}",
"GRADLE_ENTERPRISE_ACCESS_KEY=${GRADLE_ENTERPRISE_ACCESS_KEY}"]) {
sh "./gradlew check -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --stacktrace"
}
}
} catch(Exception e) {
currentBuild.result = 'FAILED: check'
throw e
} finally {
junit '**/build/test-results/*/*.xml'
}
}
}
},
sonar: {
stage('Sonar') {
node {
checkout scm
sh "git clean -dfx"
withCredentials([SONAR_LOGIN_CREDENTIALS,
GRADLE_ENTERPRISE_CACHE_USER,
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY,
ARTIFACTORY_CREDENTIALS]) {
try {
withEnv([jdkEnv(),
"GRADLE_ENTERPRISE_CACHE_USERNAME=${GRADLE_ENTERPRISE_CACHE_USERNAME}",
"GRADLE_ENTERPRISE_CACHE_PASSWORD=${GRADLE_ENTERPRISE_CACHE_PASSWORD}",
"GRADLE_ENTERPRISE_ACCESS_KEY=${GRADLE_ENTERPRISE_ACCESS_KEY}"]) {
if ("master" == env.BRANCH_NAME) {
sh "./gradlew sonarqube -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD -PexcludeProjects='**/samples/**' -Dsonar.host.url=$SPRING_SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN --stacktrace"
} else {
sh "./gradlew sonarqube -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD -PexcludeProjects='**/samples/**' -Dsonar.projectKey='spring-security-${env.BRANCH_NAME}' -Dsonar.projectName='spring-security-${env.BRANCH_NAME}' -Dsonar.host.url=$SPRING_SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN --stacktrace"
}
}
} catch(Exception e) {
currentBuild.result = 'FAILED: sonar'
throw e
}
}
}
}
},
snapshots: {
stage('Snapshot Tests') {
node {
checkout scm
sh "git clean -dfx"
try {
withCredentials([GRADLE_ENTERPRISE_CACHE_USER,
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY,
ARTIFACTORY_CREDENTIALS]) {
withEnv([jdkEnv(),
"GRADLE_ENTERPRISE_CACHE_USERNAME=${GRADLE_ENTERPRISE_CACHE_USERNAME}",
"GRADLE_ENTERPRISE_CACHE_PASSWORD=${GRADLE_ENTERPRISE_CACHE_PASSWORD}",
"GRADLE_ENTERPRISE_ACCESS_KEY=${GRADLE_ENTERPRISE_ACCESS_KEY}"]) {
sh "./gradlew test -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --refresh-dependencies -PforceMavenRepositories=snapshot -PspringVersion='5.2.+' -PreactorVersion='Dysprosium-BUILD-SNAPSHOT' -PspringDataVersion='Neumann-BUILD-SNAPSHOT' -PrsocketVersion='1.0.+' -PspringBootVersion='2.3.+' -PlocksDisabled --stacktrace"
}
}
} catch(Exception e) {
currentBuild.result = 'FAILED: snapshots'
throw e
}
}
}
},
jdk11: {
stage('JDK 11') {
node {
checkout scm
sh "git clean -dfx"
try {
withCredentials([GRADLE_ENTERPRISE_CACHE_USER,
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY,
ARTIFACTORY_CREDENTIALS]) {
withEnv([jdkEnv("jdk11"),
"GRADLE_ENTERPRISE_CACHE_USERNAME=${GRADLE_ENTERPRISE_CACHE_USERNAME}",
"GRADLE_ENTERPRISE_CACHE_PASSWORD=${GRADLE_ENTERPRISE_CACHE_PASSWORD}",
"GRADLE_ENTERPRISE_ACCESS_KEY=${GRADLE_ENTERPRISE_ACCESS_KEY}"]) {
sh "./gradlew test -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --stacktrace"
}
}
} catch(Exception e) {
currentBuild.result = 'FAILED: jdk11'
throw e
}
}
}
},
jdk12: {
stage('JDK 12') {
node {
checkout scm
sh "git clean -dfx"
try {
withCredentials([GRADLE_ENTERPRISE_CACHE_USER,
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY,
ARTIFACTORY_CREDENTIALS]) {
withEnv([jdkEnv("openjdk12"),
"GRADLE_ENTERPRISE_CACHE_USERNAME=${GRADLE_ENTERPRISE_CACHE_USERNAME}",
"GRADLE_ENTERPRISE_CACHE_PASSWORD=${GRADLE_ENTERPRISE_CACHE_PASSWORD}",
"GRADLE_ENTERPRISE_ACCESS_KEY=${GRADLE_ENTERPRISE_ACCESS_KEY}"]) {
sh "./gradlew test -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --stacktrace"
}
}
} catch(Exception e) {
currentBuild.result = 'FAILED: jdk12'
throw e
}
}
}
}
if(currentBuild.result == 'SUCCESS') {
parallel artifacts: {
stage('Deploy Artifacts') {
node {
checkout scm
sh "git clean -dfx"
withCredentials([SPRING_SIGNING_SECRING,
SPRING_GPG_PASSPHRASE,
OSSRH_CREDENTIALS,
ARTIFACTORY_CREDENTIALS,
GRADLE_ENTERPRISE_CACHE_USER,
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY]) {
withEnv([jdkEnv(),
"GRADLE_ENTERPRISE_CACHE_USERNAME=${GRADLE_ENTERPRISE_CACHE_USERNAME}",
"GRADLE_ENTERPRISE_CACHE_PASSWORD=${GRADLE_ENTERPRISE_CACHE_PASSWORD}",
"GRADLE_ENTERPRISE_ACCESS_KEY=${GRADLE_ENTERPRISE_ACCESS_KEY}"]) {
sh "./gradlew deployArtifacts -Psigning.secretKeyRingFile=$SIGNING_KEYRING_FILE -Psigning.keyId=$SPRING_SIGNING_KEYID -Psigning.password='$SIGNING_PASSWORD' -PossrhUsername=$OSSRH_USERNAME -PossrhPassword=$OSSRH_PASSWORD -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --stacktrace --no-parallel"
sh "./gradlew finalizeDeployArtifacts -Psigning.secretKeyRingFile=$SIGNING_KEYRING_FILE -Psigning.keyId=$SPRING_SIGNING_KEYID -Psigning.password='$SIGNING_PASSWORD' -PossrhUsername=$OSSRH_USERNAME -PossrhPassword=$OSSRH_PASSWORD -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --stacktrace --no-parallel"
}
}
}
}
},
docs: {
stage('Deploy Docs') {
node {
checkout scm
sh "git clean -dfx"
withCredentials([JENKINS_PRIVATE_SSH_KEY,
SPRING_GPG_PASSPHRASE,
OSSRH_CREDENTIALS,
ARTIFACTORY_CREDENTIALS,
GRADLE_ENTERPRISE_CACHE_USER,
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY]) {
withEnv([jdkEnv(),
"GRADLE_ENTERPRISE_CACHE_USERNAME=${GRADLE_ENTERPRISE_CACHE_USERNAME}",
"GRADLE_ENTERPRISE_CACHE_PASSWORD=${GRADLE_ENTERPRISE_CACHE_PASSWORD}",
"GRADLE_ENTERPRISE_ACCESS_KEY=${GRADLE_ENTERPRISE_ACCESS_KEY}"]) {
sh "./gradlew deployDocs -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --stacktrace"
}
}
}
}
},
schema: {
stage('Deploy Schema') {
node {
checkout scm
sh "git clean -dfx"
withCredentials([JENKINS_PRIVATE_SSH_KEY,
SPRING_GPG_PASSPHRASE,
OSSRH_CREDENTIALS,
ARTIFACTORY_CREDENTIALS,
GRADLE_ENTERPRISE_CACHE_USER,
GRADLE_ENTERPRISE_SECRET_ACCESS_KEY]) {
withEnv([jdkEnv(),
"GRADLE_ENTERPRISE_CACHE_USERNAME=${GRADLE_ENTERPRISE_CACHE_USERNAME}",
"GRADLE_ENTERPRISE_CACHE_PASSWORD=${GRADLE_ENTERPRISE_CACHE_PASSWORD}",
"GRADLE_ENTERPRISE_ACCESS_KEY=${GRADLE_ENTERPRISE_ACCESS_KEY}"]) {
sh "./gradlew deploySchema -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --stacktrace"
}
}
}
}
}
}
} catch(Exception e) {
currentBuild.result = 'FAILED: deploys'
throw e
} finally {
def buildStatus = currentBuild.result
def buildNotSuccess = !SUCCESS.equals(buildStatus)
def lastBuildNotSuccess = !SUCCESS.equals(currentBuild.previousBuild?.result)
if(buildNotSuccess || lastBuildNotSuccess) {
stage('Notifiy') {
node {
final def RECIPIENTS = [[$class: 'DevelopersRecipientProvider'], [$class: 'RequesterRecipientProvider']]
def subject = "${buildStatus}: Build ${env.JOB_NAME} ${env.BUILD_NUMBER} status is now ${buildStatus}"
def details = """The build status changed to ${buildStatus}. For details see ${env.BUILD_URL}"""
emailext (
subject: subject,
body: details,
recipientProviders: RECIPIENTS,
to: "$SPRING_SECURITY_TEAM_EMAILS"
)
}
}
}
}
-202
View File
@@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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
https://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.
-63
View File
@@ -1,63 +0,0 @@
image::https://badges.gitter.im/Join%20Chat.svg[Gitter,link=https://gitter.im/spring-projects/spring-security?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge]
= Spring Security
Spring Security provides security services for the https://docs.spring.io[Spring IO Platform]. Spring Security 5.0 requires Spring 5.0 as
a minimum and also requires Java 8.
For a detailed list of features and access to the latest release, please visit https://spring.io/projects[Spring projects].
== Code of Conduct
Please see our https://github.com/spring-projects/.github/blob/master/CODE_OF_CONDUCT.md[code of conduct]
== Downloading Artifacts
See https://github.com/spring-projects/spring-framework/wiki/Downloading-Spring-artifacts[downloading Spring artifacts] for Maven repository information.
== Documentation
Be sure to read the https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/[Spring Security Reference].
Extensive JavaDoc for the Spring Security code is also available in the https://docs.spring.io/spring-security/site/docs/current/api/[Spring Security API Documentation].
== Quick Start
We recommend you visit https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/[Spring Security Reference] and read the "Getting Started" page.
== Building from Source
Spring Security uses a https://gradle.org[Gradle]-based build system.
In the instructions below, https://vimeo.com/34436402[`./gradlew`] is invoked from the root of the source tree and serves as
a cross-platform, self-contained bootstrap mechanism for the build.
=== Prerequisites
https://help.github.com/set-up-git-redirect[Git] and the https://www.oracle.com/technetwork/java/javase/downloads[JDK8 build].
Be sure that your `JAVA_HOME` environment variable points to the `jdk1.8.0` folder extracted from the JDK download.
=== Check out sources
[indent=0]
----
git clone git@github.com:spring-projects/spring-security.git
----
=== Install all spring-\* jars into your local Maven cache
[indent=0]
----
./gradlew install
----
=== Compile and test; build all jars, distribution zips, and docs
[indent=0]
----
./gradlew build
----
Discover more commands with `./gradlew tasks`.
See also the https://github.com/spring-projects/spring-framework/wiki/Gradle-build-and-release-FAQ[Gradle build and release FAQ].
== Getting Support
Check out the https://stackoverflow.com/questions/tagged/spring-security[Spring Security tags on Stack Overflow].
https://spring.io/services[Commercial support] is available too.
== Contributing
https://help.github.com/articles/creating-a-pull-request[Pull requests] are welcome; see the https://github.com/spring-projects/spring-security/blob/master/CONTRIBUTING.adoc[contributor guidelines] for details.
== License
Spring Security is Open Source software released under the
https://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0 license].
+14
View File
@@ -0,0 +1,14 @@
// Acl Module build file
dependencies {
compile project(':spring-security-core'),
"net.sf.ehcache:ehcache:$ehcacheVersion",
"org.springframework:spring-aop:$springVersion",
"org.springframework:spring-context:$springVersion",
"org.springframework:spring-tx:$springVersion",
"org.springframework:spring-jdbc:$springVersion"
testCompile "org.springframework:spring-beans:$springVersion",
"org.springframework:spring-context-support:$springVersion",
"org.springframework:spring-test:$springVersion"
}
@@ -1,7 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-framework-bom:5.2.11.RELEASE
@@ -1,7 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-framework-bom:5.2.11.RELEASE
@@ -1,26 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
antlr:antlr:2.7.7
ch.qos.logback:logback-classic:1.2.3
ch.qos.logback:logback-core:1.2.3
com.google.code.findbugs:jsr305:3.0.2
com.google.errorprone:error_prone_annotations:2.3.4
com.google.guava:failureaccess:1.0.1
com.google.guava:guava:29.0-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.3
com.puppycrawl.tools:checkstyle:8.32
commons-beanutils:commons-beanutils:1.9.4
commons-collections:commons-collections:3.2.2
info.picocli:picocli:4.2.0
io.projectreactor:reactor-bom:Dysprosium-SR14
io.spring.javaformat:spring-javaformat-checkstyle:0.0.25
io.spring.nohttp:nohttp-checkstyle:0.0.3.RELEASE
io.spring.nohttp:nohttp:0.0.3.RELEASE
net.sf.saxon:Saxon-HE:9.9.1-7
org.antlr:antlr4-runtime:4.8-1
org.checkerframework:checker-qual:2.11.1
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-framework-bom:5.2.11.RELEASE
@@ -1,15 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-aop:5.2.11.RELEASE
org.springframework:spring-beans:5.2.11.RELEASE
org.springframework:spring-context:5.2.11.RELEASE
org.springframework:spring-core:5.2.11.RELEASE
org.springframework:spring-expression:5.2.11.RELEASE
org.springframework:spring-framework-bom:5.2.11.RELEASE
org.springframework:spring-jcl:5.2.11.RELEASE
org.springframework:spring-jdbc:5.2.11.RELEASE
org.springframework:spring-tx:5.2.11.RELEASE
@@ -1,15 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-aop:5.2.11.RELEASE
org.springframework:spring-beans:5.2.11.RELEASE
org.springframework:spring-context:5.2.11.RELEASE
org.springframework:spring-core:5.2.11.RELEASE
org.springframework:spring-expression:5.2.11.RELEASE
org.springframework:spring-framework-bom:5.2.11.RELEASE
org.springframework:spring-jcl:5.2.11.RELEASE
org.springframework:spring-jdbc:5.2.11.RELEASE
org.springframework:spring-tx:5.2.11.RELEASE
@@ -1,7 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-framework-bom:5.2.11.RELEASE
@@ -1,15 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-aop:5.2.11.RELEASE
org.springframework:spring-beans:5.2.11.RELEASE
org.springframework:spring-context:5.2.11.RELEASE
org.springframework:spring-core:5.2.11.RELEASE
org.springframework:spring-expression:5.2.11.RELEASE
org.springframework:spring-framework-bom:5.2.11.RELEASE
org.springframework:spring-jcl:5.2.11.RELEASE
org.springframework:spring-jdbc:5.2.11.RELEASE
org.springframework:spring-tx:5.2.11.RELEASE
@@ -1,8 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
org.jacoco:org.jacoco.agent:0.8.2
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-framework-bom:5.2.11.RELEASE
@@ -1,15 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
org.jacoco:org.jacoco.agent:0.8.2
org.jacoco:org.jacoco.ant:0.8.2
org.jacoco:org.jacoco.core:0.8.2
org.jacoco:org.jacoco.report:0.8.2
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.ow2.asm:asm-analysis:6.2.1
org.ow2.asm:asm-commons:6.2.1
org.ow2.asm:asm-tree:6.2.1
org.ow2.asm:asm:6.2.1
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-framework-bom:5.2.11.RELEASE
@@ -1,7 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-framework-bom:5.2.11.RELEASE
@@ -1,9 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
net.sf.ehcache:ehcache:2.10.6
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.slf4j:slf4j-api:1.7.30
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-framework-bom:5.2.11.RELEASE
@@ -1,7 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-framework-bom:5.2.11.RELEASE
@@ -1,15 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-aop:5.2.11.RELEASE
org.springframework:spring-beans:5.2.11.RELEASE
org.springframework:spring-context:5.2.11.RELEASE
org.springframework:spring-core:5.2.11.RELEASE
org.springframework:spring-expression:5.2.11.RELEASE
org.springframework:spring-framework-bom:5.2.11.RELEASE
org.springframework:spring-jcl:5.2.11.RELEASE
org.springframework:spring-jdbc:5.2.11.RELEASE
org.springframework:spring-tx:5.2.11.RELEASE
@@ -1,15 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-aop:5.2.11.RELEASE
org.springframework:spring-beans:5.2.11.RELEASE
org.springframework:spring-context:5.2.11.RELEASE
org.springframework:spring-core:5.2.11.RELEASE
org.springframework:spring-expression:5.2.11.RELEASE
org.springframework:spring-framework-bom:5.2.11.RELEASE
org.springframework:spring-jcl:5.2.11.RELEASE
org.springframework:spring-jdbc:5.2.11.RELEASE
org.springframework:spring-tx:5.2.11.RELEASE
@@ -1,7 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-framework-bom:5.2.11.RELEASE
@@ -1,7 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-framework-bom:5.2.11.RELEASE
@@ -1,7 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-framework-bom:5.2.11.RELEASE
@@ -1,24 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
junit:junit:4.12
net.bytebuddy:byte-buddy-agent:1.10.15
net.bytebuddy:byte-buddy:1.10.15
org.assertj:assertj-core:3.17.2
org.hamcrest:hamcrest-core:1.3
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.mockito:mockito-core:3.5.15
org.objenesis:objenesis:3.1
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-aop:5.2.11.RELEASE
org.springframework:spring-beans:5.2.11.RELEASE
org.springframework:spring-context-support:5.2.11.RELEASE
org.springframework:spring-context:5.2.11.RELEASE
org.springframework:spring-core:5.2.11.RELEASE
org.springframework:spring-expression:5.2.11.RELEASE
org.springframework:spring-framework-bom:5.2.11.RELEASE
org.springframework:spring-jcl:5.2.11.RELEASE
org.springframework:spring-jdbc:5.2.11.RELEASE
org.springframework:spring-test:5.2.11.RELEASE
org.springframework:spring-tx:5.2.11.RELEASE
@@ -1,24 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
junit:junit:4.12
net.bytebuddy:byte-buddy-agent:1.10.15
net.bytebuddy:byte-buddy:1.10.15
org.assertj:assertj-core:3.17.2
org.hamcrest:hamcrest-core:1.3
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.mockito:mockito-core:3.5.15
org.objenesis:objenesis:3.1
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-aop:5.2.11.RELEASE
org.springframework:spring-beans:5.2.11.RELEASE
org.springframework:spring-context-support:5.2.11.RELEASE
org.springframework:spring-context:5.2.11.RELEASE
org.springframework:spring-core:5.2.11.RELEASE
org.springframework:spring-expression:5.2.11.RELEASE
org.springframework:spring-framework-bom:5.2.11.RELEASE
org.springframework:spring-jcl:5.2.11.RELEASE
org.springframework:spring-jdbc:5.2.11.RELEASE
org.springframework:spring-test:5.2.11.RELEASE
org.springframework:spring-tx:5.2.11.RELEASE
@@ -1,7 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-framework-bom:5.2.11.RELEASE
@@ -1,25 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
junit:junit:4.12
net.bytebuddy:byte-buddy-agent:1.10.15
net.bytebuddy:byte-buddy:1.10.15
org.assertj:assertj-core:3.17.2
org.hamcrest:hamcrest-core:1.3
org.hsqldb:hsqldb:2.5.1
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.mockito:mockito-core:3.5.15
org.objenesis:objenesis:3.1
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-aop:5.2.11.RELEASE
org.springframework:spring-beans:5.2.11.RELEASE
org.springframework:spring-context-support:5.2.11.RELEASE
org.springframework:spring-context:5.2.11.RELEASE
org.springframework:spring-core:5.2.11.RELEASE
org.springframework:spring-expression:5.2.11.RELEASE
org.springframework:spring-framework-bom:5.2.11.RELEASE
org.springframework:spring-jcl:5.2.11.RELEASE
org.springframework:spring-jdbc:5.2.11.RELEASE
org.springframework:spring-test:5.2.11.RELEASE
org.springframework:spring-tx:5.2.11.RELEASE
@@ -1,25 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
junit:junit:4.12
net.bytebuddy:byte-buddy-agent:1.10.15
net.bytebuddy:byte-buddy:1.10.15
org.assertj:assertj-core:3.17.2
org.hamcrest:hamcrest-core:1.3
org.hsqldb:hsqldb:2.5.1
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.mockito:mockito-core:3.5.15
org.objenesis:objenesis:3.1
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-aop:5.2.11.RELEASE
org.springframework:spring-beans:5.2.11.RELEASE
org.springframework:spring-context-support:5.2.11.RELEASE
org.springframework:spring-context:5.2.11.RELEASE
org.springframework:spring-core:5.2.11.RELEASE
org.springframework:spring-expression:5.2.11.RELEASE
org.springframework:spring-framework-bom:5.2.11.RELEASE
org.springframework:spring-jcl:5.2.11.RELEASE
org.springframework:spring-jdbc:5.2.11.RELEASE
org.springframework:spring-test:5.2.11.RELEASE
org.springframework:spring-tx:5.2.11.RELEASE
@@ -1,25 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
io.projectreactor:reactor-bom:Dysprosium-SR14
junit:junit:4.12
net.bytebuddy:byte-buddy-agent:1.10.15
net.bytebuddy:byte-buddy:1.10.15
org.assertj:assertj-core:3.17.2
org.hamcrest:hamcrest-core:1.3
org.hsqldb:hsqldb:2.5.1
org.jetbrains.kotlin:kotlin-bom:1.4.20
org.mockito:mockito-core:3.5.15
org.objenesis:objenesis:3.1
org.springframework.data:spring-data-releasetrain:Neumann-SR5
org.springframework:spring-aop:5.2.11.RELEASE
org.springframework:spring-beans:5.2.11.RELEASE
org.springframework:spring-context-support:5.2.11.RELEASE
org.springframework:spring-context:5.2.11.RELEASE
org.springframework:spring-core:5.2.11.RELEASE
org.springframework:spring-expression:5.2.11.RELEASE
org.springframework:spring-framework-bom:5.2.11.RELEASE
org.springframework:spring-jcl:5.2.11.RELEASE
org.springframework:spring-jdbc:5.2.11.RELEASE
org.springframework:spring-test:5.2.11.RELEASE
org.springframework:spring-tx:5.2.11.RELEASE
+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>
-18
View File
@@ -1,18 +0,0 @@
apply plugin: 'io.spring.convention.spring-module'
dependencies {
compile project(':spring-security-core')
compile 'org.springframework:spring-aop'
compile 'org.springframework:spring-context'
compile 'org.springframework:spring-core'
compile 'org.springframework:spring-jdbc'
compile 'org.springframework:spring-tx'
optional 'net.sf.ehcache:ehcache'
testCompile 'org.springframework:spring-beans'
testCompile 'org.springframework:spring-context-support'
testCompile 'org.springframework:spring-test'
testRuntime 'org.hsqldb:hsqldb'
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls;
import java.lang.reflect.InvocationTargetException;
@@ -22,10 +20,8 @@ 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;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.vote.AbstractAclVoter;
@@ -41,201 +37,207 @@ import org.springframework.security.acls.model.Sid;
import org.springframework.security.acls.model.SidRetrievalStrategy;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* <p>
* Given a domain object instance passed as a method argument, ensures the principal has
* appropriate permission as indicated by the {@link AclService}.
* Given a domain object instance passed as a method argument, ensures the principal has appropriate permission
* as indicated by the {@link AclService}.
* <p>
* The <tt>AclService</tt> is used to retrieve the access control list (ACL) permissions
* associated with a domain object instance for the current <tt>Authentication</tt>
* object.
* The <tt>AclService</tt> is used to retrieve the access control list (ACL) permissions associated with a
* domain object instance for the current <tt>Authentication</tt> object.
* <p>
* The voter will vote if any {@link ConfigAttribute#getAttribute()} matches the
* {@link #processConfigAttribute}. The provider will then locate the first method
* argument of type {@link #processDomainObjectClass}. Assuming that method argument is
* non-null, the provider will then lookup the ACLs from the <code>AclManager</code> and
* ensure the principal is {@link Acl#isGranted(List, List, boolean)} when presenting the
* {@link #requirePermission} array to that method.
* The voter will vote if any {@link ConfigAttribute#getAttribute()} matches the {@link #processConfigAttribute}.
* The provider will then locate the first method argument of type {@link #processDomainObjectClass}. Assuming that
* method argument is non-null, the provider will then lookup the ACLs from the <code>AclManager</code> and ensure the
* principal is {@link Acl#isGranted(List,
* List, boolean)} when presenting the {@link #requirePermission} array to that
* method.
* <p>
* If the method argument is <tt>null</tt>, the voter will abstain from voting. If the
* method argument could not be found, an {@link AuthorizationServiceException} will be
* thrown.
* If the method argument is <tt>null</tt>, the voter will abstain from voting. If the method argument
* could not be found, an {@link AuthorizationServiceException} will be thrown.
* <p>
* In practical terms users will typically setup a number of <tt>AclEntryVoter</tt>s. Each
* will have a different {@link #setProcessDomainObjectClass processDomainObjectClass},
* {@link #processConfigAttribute} and {@link #requirePermission} combination. For
* example, a small application might employ the following instances of
* In practical terms users will typically setup a number of <tt>AclEntryVoter</tt>s. Each will have a
* different {@link #setProcessDomainObjectClass processDomainObjectClass}, {@link #processConfigAttribute} and
* {@link #requirePermission} combination. For example, a small application might employ the following instances of
* <tt>AclEntryVoter</tt>:
* <ul>
* <li>Process domain object class <code>BankAccount</code>, configuration attribute
* <code>VOTE_ACL_BANK_ACCONT_READ</code>, require permission
* <code>BasePermission.READ</code></li>
* <li>Process domain object class <code>BankAccount</code>, configuration attribute
* <code>VOTE_ACL_BANK_ACCOUNT_WRITE</code>, require permission list
* <code>BasePermission.WRITE</code> and <code>BasePermission.CREATE</code> (allowing the
* principal to have <b>either</b> of these two permissions)</li>
* <li>Process domain object class <code>Customer</code>, configuration attribute
* <code>VOTE_ACL_CUSTOMER_READ</code>, require permission
* <code>BasePermission.READ</code></li>
* <li>Process domain object class <code>Customer</code>, configuration attribute
* <code>VOTE_ACL_CUSTOMER_WRITE</code>, require permission list
* <code>BasePermission.WRITE</code> and <code>BasePermission.CREATE</code></li>
* </ul>
* Alternatively, you could have used a common superclass or interface for the
* {@link #processDomainObjectClass} if both <code>BankAccount</code> and
* <code>Customer</code> had common parents.
*
* <p>
* If the principal does not have sufficient permissions, the voter will vote to deny
* access.
*
* <p>
* All comparisons and prefixes are case sensitive.
* <ul>
* <li>Process domain object class <code>BankAccount</code>, configuration attribute
* <code>VOTE_ACL_BANK_ACCONT_READ</code>, require permission <code>BasePermission.READ</code></li>
* <li>Process domain object class <code>BankAccount</code>, configuration attribute
* <code>VOTE_ACL_BANK_ACCOUNT_WRITE</code>, require permission list <code>BasePermission.WRITE</code> and
* <code>BasePermission.CREATE</code> (allowing the principal to have <b>either</b> of these two permissions)</li>
* <li>Process domain object class <code>Customer</code>, configuration attribute
* <code>VOTE_ACL_CUSTOMER_READ</code>, require permission <code>BasePermission.READ</code></li>
* <li>Process domain object class <code>Customer</code>, configuration attribute
* <code>VOTE_ACL_CUSTOMER_WRITE</code>, require permission list <code>BasePermission.WRITE</code> and
* <code>BasePermission.CREATE</code></li>
* </ul>
* Alternatively, you could have used a common superclass or interface for the {@link #processDomainObjectClass}
* if both <code>BankAccount</code> and <code>Customer</code> had common parents.</p>
* <p>If the principal does not have sufficient permissions, the voter will vote to deny access.</p>
* <p>All comparisons and prefixes are case sensitive.</p>
*
* @author Ben Alex
*/
public class AclEntryVoter extends AbstractAclVoter {
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(AclEntryVoter.class);
private static final Log logger = LogFactory.getLog(AclEntryVoter.class);
private final AclService aclService;
//~ Instance fields ================================================================================================
private final String processConfigAttribute;
private AclService aclService;
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
private String internalMethod;
private String processConfigAttribute;
private List<Permission> requirePermission;
private final List<Permission> requirePermission;
//~ Constructors ===================================================================================================
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
public AclEntryVoter(AclService aclService, String processConfigAttribute, Permission[] requirePermission) {
Assert.notNull(processConfigAttribute, "A processConfigAttribute is mandatory");
Assert.notNull(aclService, "An AclService is mandatory");
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
if ((requirePermission == null) || (requirePermission.length == 0)) {
throw new IllegalArgumentException("One or more requirePermission entries is mandatory");
}
private String internalMethod;
this.aclService = aclService;
this.processConfigAttribute = processConfigAttribute;
this.requirePermission = Arrays.asList(requirePermission);
}
public AclEntryVoter(AclService aclService, String processConfigAttribute, Permission[] requirePermission) {
Assert.notNull(processConfigAttribute, "A processConfigAttribute is mandatory");
Assert.notNull(aclService, "An AclService is mandatory");
Assert.isTrue(!ObjectUtils.isEmpty(requirePermission), "One or more requirePermission entries is mandatory");
this.aclService = aclService;
this.processConfigAttribute = processConfigAttribute;
this.requirePermission = Arrays.asList(requirePermission);
}
//~ Methods ========================================================================================================
/**
* Optionally specifies a method of the domain object that will be used to obtain a
* contained domain object. That contained domain object will be used for the ACL
* evaluation. This is useful if a domain object contains a parent that an ACL
* evaluation should be targeted for, instead of the child domain object (which
* perhaps is being created and as such does not yet have any ACL permissions)
* @return <code>null</code> to use the domain object, or the name of a method (that
* requires no arguments) that should be invoked to obtain an <code>Object</code>
* which will be the domain object used for ACL evaluation
*/
protected String getInternalMethod() {
return this.internalMethod;
}
/**
* Optionally specifies a method of the domain object that will be used to obtain a contained domain
* object. That contained domain object will be used for the ACL evaluation. This is useful if a domain object
* contains a parent that an ACL evaluation should be targeted for, instead of the child domain object (which
* perhaps is being created and as such does not yet have any ACL permissions)
*
* @return <code>null</code> to use the domain object, or the name of a method (that requires no arguments) that
* should be invoked to obtain an <code>Object</code> which will be the domain object used for ACL
* evaluation
*/
protected String getInternalMethod() {
return internalMethod;
}
public void setInternalMethod(String internalMethod) {
this.internalMethod = internalMethod;
}
public void setInternalMethod(String internalMethod) {
this.internalMethod = internalMethod;
}
protected String getProcessConfigAttribute() {
return this.processConfigAttribute;
}
protected String getProcessConfigAttribute() {
return processConfigAttribute;
}
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
Assert.notNull(objectIdentityRetrievalStrategy, "ObjectIdentityRetrievalStrategy required");
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
}
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
Assert.notNull(objectIdentityRetrievalStrategy, "ObjectIdentityRetrievalStrategy required");
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
@Override
public boolean supports(ConfigAttribute attribute) {
return (attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute());
}
public boolean supports(ConfigAttribute attribute) {
if ((attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute())) {
return true;
} else {
return false;
}
}
@Override
public int vote(Authentication authentication, MethodInvocation object, Collection<ConfigAttribute> attributes) {
for (ConfigAttribute attr : attributes) {
if (!supports(attr)) {
continue;
}
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
// Need to make an access decision on this invocation
// Attempt to locate the domain object instance to process
Object domainObject = getDomainObjectInstance(object);
for(ConfigAttribute attr : attributes) {
// If domain object is null, vote to abstain
if (domainObject == null) {
logger.debug("Voting to abstain - domainObject is null");
return ACCESS_ABSTAIN;
}
if (!this.supports(attr)) {
continue;
}
// Need to make an access decision on this invocation
// Attempt to locate the domain object instance to process
Object domainObject = getDomainObjectInstance(object);
// Evaluate if we are required to use an inner domain object
if (StringUtils.hasText(this.internalMethod)) {
domainObject = invokeInternalMethod(domainObject);
}
// If domain object is null, vote to abstain
if (domainObject == null) {
if (logger.isDebugEnabled()) {
logger.debug("Voting to abstain - domainObject is null");
}
// Obtain the OID applicable to the domain object
ObjectIdentity objectIdentity = this.objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
return ACCESS_ABSTAIN;
}
// Obtain the SIDs applicable to the principal
List<Sid> sids = this.sidRetrievalStrategy.getSids(authentication);
// Evaluate if we are required to use an inner domain object
if (StringUtils.hasText(internalMethod)) {
try {
Class<?> clazz = domainObject.getClass();
Method method = clazz.getMethod(internalMethod, new Class[0]);
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);
} catch (IllegalAccessException iae) {
logger.debug("IllegalAccessException", iae);
Acl acl;
throw new AuthorizationServiceException("Problem invoking internalMethod: " + internalMethod
+ " for object: " + domainObject);
} catch (InvocationTargetException ite) {
logger.debug("InvocationTargetException", ite);
try {
// Lookup only ACLs for SIDs we're interested in
acl = this.aclService.readAclById(objectIdentity, sids);
}
catch (NotFoundException ex) {
logger.debug("Voting to deny access - no ACLs apply for this principal");
return ACCESS_DENIED;
}
throw new AuthorizationServiceException("Problem invoking internalMethod: " + internalMethod
+ " for object: " + domainObject);
}
}
try {
if (acl.isGranted(this.requirePermission, sids, false)) {
logger.debug("Voting to grant access");
return ACCESS_GRANTED;
}
logger.debug("Voting to deny access - ACLs returned, but insufficient permissions for this principal");
return ACCESS_DENIED;
}
catch (NotFoundException ex) {
logger.debug("Voting to deny access - no ACLs apply for this principal");
return ACCESS_DENIED;
}
}
// Obtain the OID applicable to the domain object
ObjectIdentity objectIdentity = objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
// No configuration attribute matched, so abstain
return ACCESS_ABSTAIN;
}
// Obtain the SIDs applicable to the principal
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
private Object invokeInternalMethod(Object domainObject) {
try {
Class<?> domainObjectType = domainObject.getClass();
Method method = domainObjectType.getMethod(this.internalMethod, new Class[0]);
return method.invoke(domainObject);
}
catch (NoSuchMethodException ex) {
throw new AuthorizationServiceException("Object of class '" + domainObject.getClass()
+ "' does not provide the requested internalMethod: " + this.internalMethod);
}
catch (IllegalAccessException ex) {
logger.debug("IllegalAccessException", ex);
throw new AuthorizationServiceException(
"Problem invoking internalMethod: " + this.internalMethod + " for object: " + domainObject);
}
catch (InvocationTargetException ex) {
logger.debug("InvocationTargetException", ex);
throw new AuthorizationServiceException(
"Problem invoking internalMethod: " + this.internalMethod + " for object: " + domainObject);
}
}
Acl acl;
try {
// Lookup only ACLs for SIDs we're interested in
acl = aclService.readAclById(objectIdentity, sids);
} catch (NotFoundException nfe) {
if (logger.isDebugEnabled()) {
logger.debug("Voting to deny access - no ACLs apply for this principal");
}
return ACCESS_DENIED;
}
try {
if (acl.isGranted(requirePermission, sids, false)) {
if (logger.isDebugEnabled()) {
logger.debug("Voting to grant access");
}
return ACCESS_GRANTED;
} else {
if (logger.isDebugEnabled()) {
logger.debug(
"Voting to deny access - ACLs returned, but insufficient permissions for this principal");
}
return ACCESS_DENIED;
}
} catch (NotFoundException nfe) {
if (logger.isDebugEnabled()) {
logger.debug("Voting to deny access - no ACLs apply for this principal");
}
return ACCESS_DENIED;
}
}
// No configuration attribute matched, so abstain
return ACCESS_ABSTAIN;
}
}
@@ -1,82 +0,0 @@
/*
* Copyright 2002-2016 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
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls;
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.core.log.LogMessage;
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;
}
@Override
public void cachePermissionsFor(Authentication authentication, Collection<?> objects) {
if (objects.isEmpty()) {
return;
}
List<ObjectIdentity> oidsToCache = new ArrayList<>(objects.size());
for (Object domainObject : objects) {
if (domainObject != null) {
ObjectIdentity oid = this.oidRetrievalStrategy.getObjectIdentity(domainObject);
oidsToCache.add(oid);
}
}
List<Sid> sids = this.sidRetrievalStrategy.getSids(authentication);
this.logger.debug(LogMessage.of(() -> "Eagerly loading Acls for " + oidsToCache.size() + " objects"));
this.aclService.readAclsById(oidsToCache, sids);
}
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
this.oidRetrievalStrategy = objectIdentityRetrievalStrategy;
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
}
@@ -1,30 +1,11 @@
/*
* Copyright 2002-2016 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
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.log.LogMessage;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.acls.domain.DefaultPermissionFactory;
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
@@ -42,8 +23,8 @@ import org.springframework.security.acls.model.SidRetrievalStrategy;
import org.springframework.security.core.Authentication;
/**
* Used by Spring Security's expression-based access control implementation to evaluate
* permissions for a particular object using the ACL module. Similar in behaviour to
* Used by Spring Security's expression-based access control implementation to evaluate permissions for a particular
* object using the ACL module. Similar in behaviour to
* {@link org.springframework.security.acls.AclEntryVoter AclEntryVoter}.
*
* @author Luke Taylor
@@ -51,106 +32,114 @@ import org.springframework.security.core.Authentication;
*/
public class AclPermissionEvaluator implements PermissionEvaluator {
private final Log logger = LogFactory.getLog(getClass());
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();
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
public AclPermissionEvaluator(AclService aclService) {
this.aclService = aclService;
}
private ObjectIdentityGenerator objectIdentityGenerator = new ObjectIdentityRetrievalStrategyImpl();
/**
* Determines whether the user has the given permission(s) on the domain object using the ACL
* configuration. If the domain object is null, returns false (this can always be overridden using a null
* check in the expression itself).
*/
public boolean hasPermission(Authentication authentication, Object domainObject, Object permission) {
if (domainObject == null) {
return false;
}
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
ObjectIdentity objectIdentity = objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
private PermissionFactory permissionFactory = new DefaultPermissionFactory();
return checkPermission(authentication, objectIdentity, permission);
}
public AclPermissionEvaluator(AclService aclService) {
this.aclService = aclService;
}
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
ObjectIdentity objectIdentity = objectIdentityGenerator.createObjectIdentity(targetId, targetType);
/**
* Determines whether the user has the given permission(s) on the domain object using
* the ACL configuration. If the domain object is null, returns false (this can always
* be overridden using a null check in the expression itself).
*/
@Override
public boolean hasPermission(Authentication authentication, Object domainObject, Object permission) {
if (domainObject == null) {
return false;
}
ObjectIdentity objectIdentity = this.objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
return checkPermission(authentication, objectIdentity, permission);
}
return checkPermission(authentication, objectIdentity, permission);
}
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType,
Object permission) {
ObjectIdentity objectIdentity = this.objectIdentityGenerator.createObjectIdentity(targetId, targetType);
return checkPermission(authentication, objectIdentity, permission);
}
private boolean checkPermission(Authentication authentication, ObjectIdentity oid, Object permission) {
// Obtain the SIDs applicable to the principal
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
List<Permission> requiredPermission = resolvePermission(permission);
private boolean checkPermission(Authentication authentication, ObjectIdentity oid, Object permission) {
// Obtain the SIDs applicable to the principal
List<Sid> sids = this.sidRetrievalStrategy.getSids(authentication);
List<Permission> requiredPermission = resolvePermission(permission);
this.logger.debug(LogMessage.of(() -> "Checking permission '" + permission + "' for object '" + oid + "'"));
try {
// Lookup only ACLs for SIDs we're interested in
Acl acl = this.aclService.readAclById(oid, sids);
if (acl.isGranted(requiredPermission, sids, false)) {
this.logger.debug("Access is granted");
return true;
}
this.logger.debug("Returning false - ACLs returned, but insufficient permissions for this principal");
}
catch (NotFoundException nfe) {
this.logger.debug("Returning false - no ACLs apply for this principal");
}
return false;
}
try {
// Lookup only ACLs for SIDs we're interested in
Acl acl = aclService.readAclById(oid, sids);
List<Permission> resolvePermission(Object permission) {
if (permission instanceof Integer) {
return Arrays.asList(this.permissionFactory.buildFromMask((Integer) permission));
}
if (permission instanceof Permission) {
return Arrays.asList((Permission) permission);
}
if (permission instanceof Permission[]) {
return Arrays.asList((Permission[]) permission);
}
if (permission instanceof String) {
String permString = (String) permission;
Permission p = buildPermission(permString);
if (p != null) {
return Arrays.asList(p);
}
}
throw new IllegalArgumentException("Unsupported permission: " + permission);
}
if (acl.isGranted(requiredPermission, sids, false)) {
if (logger.isDebugEnabled()) {
logger.debug("Access is granted");
}
private Permission buildPermission(String permString) {
try {
return this.permissionFactory.buildFromName(permString);
}
catch (IllegalArgumentException notfound) {
return this.permissionFactory.buildFromName(permString.toUpperCase(Locale.ENGLISH));
}
}
return true;
}
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
}
if (logger.isDebugEnabled()) {
logger.debug("Returning false - ACLs returned, but insufficient permissions for this principal");
}
public void setObjectIdentityGenerator(ObjectIdentityGenerator objectIdentityGenerator) {
this.objectIdentityGenerator = objectIdentityGenerator;
}
} catch (NotFoundException nfe) {
if (logger.isDebugEnabled()) {
logger.debug("Returning false - no ACLs apply for this principal");
}
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
return false;
public void setPermissionFactory(PermissionFactory permissionFactory) {
this.permissionFactory = permissionFactory;
}
}
List<Permission> resolvePermission(Object permission) {
if (permission instanceof Integer) {
return Arrays.asList(permissionFactory.buildFromMask(((Integer)permission).intValue()));
}
if (permission instanceof Permission) {
return Arrays.asList((Permission)permission);
}
if (permission instanceof Permission[]) {
return Arrays.asList((Permission[])permission);
}
if (permission instanceof String) {
String permString = (String)permission;
Permission p = null;
try {
p = permissionFactory.buildFromName(permString);
} catch(IllegalArgumentException notfound) {
p = permissionFactory.buildFromName(permString.toUpperCase());
}
if (p != null) {
return Arrays.asList(p);
}
}
throw new IllegalArgumentException("Unsupported permission: " + permission);
}
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
}
public void setObjectIdentityGenerator(ObjectIdentityGenerator objectIdentityGenerator) {
this.objectIdentityGenerator = objectIdentityGenerator;
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
public void setPermissionFactory(PermissionFactory permissionFactory) {
this.permissionFactory = permissionFactory;
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -16,10 +15,12 @@
package org.springframework.security.acls.afterinvocation;
import java.util.Arrays;
import java.util.List;
import org.springframework.security.access.AfterInvocationProvider;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.domain.ObjectIdentityRetrievalStrategyImpl;
import org.springframework.security.acls.domain.SidRetrievalStrategyImpl;
import org.springframework.security.acls.model.Acl;
@@ -32,93 +33,95 @@ import org.springframework.security.acls.model.Sid;
import org.springframework.security.acls.model.SidRetrievalStrategy;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Abstract {@link AfterInvocationProvider} which provides commonly-used ACL-related
* services.
* Abstract {@link AfterInvocationProvider} which provides commonly-used ACL-related services.
*
* @author Ben Alex
*/
*/
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 List<Permission> requirePermission = Arrays.asList(BasePermission.READ);
protected String processConfigAttribute;
//~ Constructors ===================================================================================================
protected Class<?> processDomainObjectClass = Object.class;
public AbstractAclProvider(AclService aclService, String processConfigAttribute, List<Permission> requirePermission) {
Assert.hasText(processConfigAttribute, "A processConfigAttribute is mandatory");
Assert.notNull(aclService, "An AclService is mandatory");
protected ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
if (requirePermission == null || requirePermission.isEmpty()) {
throw new IllegalArgumentException("One or more requirePermission entries is mandatory");
}
protected SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
this.aclService = aclService;
this.processConfigAttribute = processConfigAttribute;
this.requirePermission = requirePermission;
}
protected final List<Permission> requirePermission;
//~ Methods ========================================================================================================
public AbstractAclProvider(AclService aclService, String processConfigAttribute,
List<Permission> requirePermission) {
Assert.hasText(processConfigAttribute, "A processConfigAttribute is mandatory");
Assert.notNull(aclService, "An AclService is mandatory");
Assert.isTrue(!ObjectUtils.isEmpty(requirePermission), "One or more requirePermission entries is mandatory");
this.aclService = aclService;
this.processConfigAttribute = processConfigAttribute;
this.requirePermission = requirePermission;
}
protected Class<?> getProcessDomainObjectClass() {
return processDomainObjectClass;
}
protected Class<?> getProcessDomainObjectClass() {
return this.processDomainObjectClass;
}
protected boolean hasPermission(Authentication authentication, Object domainObject) {
// Obtain the OID applicable to the domain object
ObjectIdentity objectIdentity = objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
protected boolean hasPermission(Authentication authentication, Object domainObject) {
// Obtain the OID applicable to the domain object
ObjectIdentity objectIdentity = this.objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
// Obtain the SIDs applicable to the principal
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
// Obtain the SIDs applicable to the principal
List<Sid> sids = this.sidRetrievalStrategy.getSids(authentication);
Acl acl = null;
try {
// Lookup only ACLs for SIDs we're interested in
Acl acl = this.aclService.readAclById(objectIdentity, sids);
return acl.isGranted(this.requirePermission, sids, false);
}
catch (NotFoundException ex) {
return false;
}
}
try {
// Lookup only ACLs for SIDs we're interested in
acl = aclService.readAclById(objectIdentity, sids);
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
Assert.notNull(objectIdentityRetrievalStrategy, "ObjectIdentityRetrievalStrategy required");
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
}
return acl.isGranted(requirePermission, sids, false);
} catch (NotFoundException ignore) {
return false;
}
}
protected void setProcessConfigAttribute(String processConfigAttribute) {
Assert.hasText(processConfigAttribute, "A processConfigAttribute is mandatory");
this.processConfigAttribute = processConfigAttribute;
}
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
Assert.notNull(objectIdentityRetrievalStrategy, "ObjectIdentityRetrievalStrategy required");
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
}
public void setProcessDomainObjectClass(Class<?> processDomainObjectClass) {
Assert.notNull(processDomainObjectClass, "processDomainObjectClass cannot be set to null");
this.processDomainObjectClass = processDomainObjectClass;
}
protected void setProcessConfigAttribute(String processConfigAttribute) {
Assert.hasText(processConfigAttribute, "A processConfigAttribute is mandatory");
this.processConfigAttribute = processConfigAttribute;
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
public void setProcessDomainObjectClass(Class<?> processDomainObjectClass) {
Assert.notNull(processDomainObjectClass, "processDomainObjectClass cannot be set to null");
this.processDomainObjectClass = processDomainObjectClass;
}
@Override
public boolean supports(ConfigAttribute attribute) {
return this.processConfigAttribute.equals(attribute.getAttribute());
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
/**
* This implementation supports any type of class, because it does not query the
* presented secure object.
* @param clazz the secure object
* @return always <code>true</code>
*/
@Override
public boolean supports(Class<?> clazz) {
return true;
}
public boolean supports(ConfigAttribute attribute) {
return processConfigAttribute.equals(attribute.getAttribute());
}
/**
* This implementation supports any type of class, because it does not query the presented secure object.
*
* @param clazz the secure object
*
* @return always <code>true</code>
*/
public boolean supports(Class<?> clazz) {
return true;
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.afterinvocation;
import java.util.Collection;
@@ -21,8 +19,6 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.log.LogMessage;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.AuthorizationServiceException;
import org.springframework.security.access.ConfigAttribute;
@@ -30,33 +26,31 @@ import org.springframework.security.acls.model.AclService;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.core.Authentication;
/**
* <p>
* Given a <code>Collection</code> of domain object instances returned from a secure
* object invocation, remove any <code>Collection</code> elements the principal does not
* have appropriate permission to access as defined by the {@link AclService}.
* Given a <code>Collection</code> of domain object instances returned from a secure object invocation, remove
* any <code>Collection</code> elements the principal does not have appropriate permission to access as defined by the
* {@link AclService}.
* <p>
* The <code>AclService</code> is used to retrieve the access control list (ACL)
* permissions associated with each <code>Collection</code> domain object instance element
* for the current <code>Authentication</code> object.
* The <code>AclService</code> is used to retrieve the access control list (ACL) permissions associated with
* each <code>Collection</code> domain object instance element for the current <code>Authentication</code> object.
* <p>
* This after invocation provider will fire if any {@link ConfigAttribute#getAttribute()}
* matches the {@link #processConfigAttribute}. The provider will then lookup the ACLs
* from the <code>AclService</code> and ensure the principal is
* {@link org.springframework.security.acls.model.Acl#isGranted(List, List, boolean)
* Acl.isGranted()} when presenting the {@link #requirePermission} array to that method.
* This after invocation provider will fire if any {@link ConfigAttribute#getAttribute()} matches the {@link
* #processConfigAttribute}. The provider will then lookup the ACLs from the <code>AclService</code> and ensure the
* principal is {@link org.springframework.security.acls.model.Acl#isGranted(List, List, boolean) Acl.isGranted()}
* when presenting the {@link #requirePermission} array to that method.
* <p>
* If the principal does not have permission, that element will not be included in the
* returned <code>Collection</code>.
* If the principal does not have permission, that element will not be included in the returned
* <code>Collection</code>.
* <p>
* Often users will setup a <code>BasicAclEntryAfterInvocationProvider</code> with a
* {@link #processConfigAttribute} of <code>AFTER_ACL_COLLECTION_READ</code> and a
* {@link #requirePermission} of <code>BasePermission.READ</code>. These are also the
* defaults.
* Often users will setup a <code>BasicAclEntryAfterInvocationProvider</code> with a {@link
* #processConfigAttribute} of <code>AFTER_ACL_COLLECTION_READ</code> and a {@link #requirePermission} of
* <code>BasePermission.READ</code>. These are also the defaults.
* <p>
* If the provided <code>returnObject</code> is <code>null</code>, a <code>null</code>
* <code>Collection</code> will be returned. If the provided <code>returnObject</code> is
* not a <code>Collection</code>, an {@link AuthorizationServiceException} will be thrown.
* If the provided <code>returnObject</code> is <code>null</code>, a <code>null</code><code>Collection</code>
* will be returned. If the provided <code>returnObject</code> is not a <code>Collection</code>, an {@link
* AuthorizationServiceException} will be thrown.
* <p>
* All comparisons and prefixes are case sensitive.
*
@@ -64,57 +58,66 @@ import org.springframework.security.core.Authentication;
* @author Paulo Neves
*/
public class AclEntryAfterInvocationCollectionFilteringProvider extends AbstractAclProvider {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationCollectionFilteringProvider.class);
protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationCollectionFilteringProvider.class);
public AclEntryAfterInvocationCollectionFilteringProvider(AclService aclService,
List<Permission> requirePermission) {
super(aclService, "AFTER_ACL_COLLECTION_READ", requirePermission);
}
//~ Constructors ===================================================================================================
@Override
@SuppressWarnings("unchecked")
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
Object returnedObject) throws AccessDeniedException {
if (returnedObject == null) {
logger.debug("Return object is null, skipping");
return null;
}
public AclEntryAfterInvocationCollectionFilteringProvider(AclService aclService, List<Permission> requirePermission) {
super(aclService, "AFTER_ACL_COLLECTION_READ", requirePermission);
}
for (ConfigAttribute attr : config) {
if (!this.supports(attr)) {
continue;
}
//~ Methods ========================================================================================================
// Need to process the Collection for this invocation
Filterer filterer = getFilterer(returnedObject);
@SuppressWarnings("unchecked")
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
Object returnedObject) throws AccessDeniedException {
// Locate unauthorised Collection elements
for (Object domainObject : filterer) {
// Ignore nulls or entries which aren't instances of the configured domain
// object class
if (domainObject == null || !getProcessDomainObjectClass().isAssignableFrom(domainObject.getClass())) {
continue;
}
if (!hasPermission(authentication, domainObject)) {
filterer.remove(domainObject);
logger.debug(LogMessage.of(() -> "Principal is NOT authorised for element: " + domainObject));
}
}
return filterer.getFilteredObject();
}
return returnedObject;
}
if (returnedObject == null) {
if (logger.isDebugEnabled()) {
logger.debug("Return object is null, skipping");
}
private Filterer getFilterer(Object returnedObject) {
if (returnedObject instanceof Collection) {
return new CollectionFilterer((Collection) returnedObject);
}
if (returnedObject.getClass().isArray()) {
return new ArrayFilterer((Object[]) returnedObject);
}
throw new AuthorizationServiceException("A Collection or an array (or null) was required as the "
+ "returnedObject, but the returnedObject was: " + returnedObject);
}
return null;
}
for (ConfigAttribute attr : config) {
if (!this.supports(attr)) {
continue;
}
// Need to process the Collection for this invocation
Filterer filterer;
if (returnedObject instanceof Collection) {
filterer = new CollectionFilterer((Collection) returnedObject);
} else if (returnedObject.getClass().isArray()) {
filterer = new ArrayFilterer((Object[]) returnedObject);
} else {
throw new AuthorizationServiceException("A Collection or an array (or null) was required as the "
+ "returnedObject, but the returnedObject was: " + returnedObject);
}
// Locate unauthorised Collection elements
for (Object domainObject : filterer) {
// Ignore nulls or entries which aren't instances of the configured domain object class
if (domainObject == null || !getProcessDomainObjectClass().isAssignableFrom(domainObject.getClass())) {
continue;
}
if(!hasPermission(authentication, domainObject)) {
filterer.remove(domainObject);
if (logger.isDebugEnabled()) {
logger.debug("Principal is NOT authorised for element: " + domainObject);
}
}
}
return filterer.getFilteredObject();
}
return returnedObject;
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.afterinvocation;
import java.util.Collection;
@@ -21,7 +19,6 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;
@@ -32,87 +29,94 @@ import org.springframework.security.acls.model.Permission;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.SpringSecurityMessageSource;
/**
* Given a domain object instance returned from a secure object invocation, ensures the
* principal has appropriate permission as defined by the {@link AclService}.
* Given a domain object instance returned from a secure object invocation, ensures the principal has
* appropriate permission as defined by the {@link AclService}.
* <p>
* The <code>AclService</code> is used to retrieve the access control list (ACL)
* permissions associated with a domain object instance for the current
* <code>Authentication</code> object.
* The <code>AclService</code> is used to retrieve the access control list (ACL) permissions associated with a
* domain object instance for the current <code>Authentication</code> object.
* <p>
* This after invocation provider will fire if any {@link ConfigAttribute#getAttribute()}
* matches the {@link #processConfigAttribute}. The provider will then lookup the ACLs
* from the <tt>AclService</tt> and ensure the principal is
* {@link org.springframework.security.acls.model.Acl#isGranted(List, List, boolean)
* Acl.isGranted(List, List, boolean)} when presenting the {@link #requirePermission}
* array to that method.
* This after invocation provider will fire if any {@link ConfigAttribute#getAttribute()} matches the {@link
* #processConfigAttribute}. The provider will then lookup the ACLs from the <tt>AclService</tt> and ensure the
* principal is {@link org.springframework.security.acls.model.Acl#isGranted(List, List, boolean)
* Acl.isGranted(List, List, boolean)} when presenting the {@link #requirePermission} array to that method.
* <p>
* Often users will set up an <code>AclEntryAfterInvocationProvider</code> with a
* {@link #processConfigAttribute} of <code>AFTER_ACL_READ</code> and a
* {@link #requirePermission} of <code>BasePermission.READ</code>. These are also the
* defaults.
* Often users will set up an <code>AclEntryAfterInvocationProvider</code> with a {@link
* #processConfigAttribute} of <code>AFTER_ACL_READ</code> and a {@link #requirePermission} of
* <code>BasePermission.READ</code>. These are also the defaults.
* <p>
* If the principal does not have sufficient permissions, an
* <code>AccessDeniedException</code> will be thrown.
* If the principal does not have sufficient permissions, an <code>AccessDeniedException</code> will be thrown.
* <p>
* If the provided <tt>returnedObject</tt> is <code>null</code>, permission will always be
* granted and <code>null</code> will be returned.
* If the provided <tt>returnedObject</tt> is <code>null</code>, permission will always be granted and
* <code>null</code> will be returned.
* <p>
* All comparisons and prefixes are case sensitive.
*/
public class AclEntryAfterInvocationProvider extends AbstractAclProvider implements MessageSourceAware {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationProvider.class);
protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationProvider.class);
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
//~ Instance fields ================================================================================================
public AclEntryAfterInvocationProvider(AclService aclService, List<Permission> requirePermission) {
this(aclService, "AFTER_ACL_READ", requirePermission);
}
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
public AclEntryAfterInvocationProvider(AclService aclService, String processConfigAttribute,
List<Permission> requirePermission) {
super(aclService, processConfigAttribute, requirePermission);
}
//~ Constructors ===================================================================================================
@Override
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
Object returnedObject) throws AccessDeniedException {
public AclEntryAfterInvocationProvider(AclService aclService, List<Permission> requirePermission) {
super(aclService, "AFTER_ACL_READ", requirePermission);
}
if (returnedObject == null) {
// AclManager interface contract prohibits nulls
// As they have permission to null/nothing, grant access
logger.debug("Return object is null, skipping");
return null;
}
public AclEntryAfterInvocationProvider(AclService aclService, String processConfigAttribute,
List<Permission> requirePermission) {
super(aclService, processConfigAttribute, requirePermission);
}
if (!getProcessDomainObjectClass().isAssignableFrom(returnedObject.getClass())) {
logger.debug("Return object is not applicable for this provider, skipping");
return returnedObject;
}
//~ Methods ========================================================================================================
for (ConfigAttribute attr : config) {
if (!this.supports(attr)) {
continue;
}
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
Object returnedObject) throws AccessDeniedException {
// Need to make an access decision on this invocation
if (hasPermission(authentication, returnedObject)) {
return returnedObject;
}
if (returnedObject == null) {
// AclManager interface contract prohibits nulls
// As they have permission to null/nothing, grant access
if (logger.isDebugEnabled()) {
logger.debug("Return object is null, skipping");
}
logger.debug("Denying access");
throw new AccessDeniedException(this.messages.getMessage("AclEntryAfterInvocationProvider.noPermission",
new Object[] { authentication.getName(), returnedObject },
"Authentication {0} has NO permissions to the domain object {1}"));
}
return null;
}
return returnedObject;
}
if (!getProcessDomainObjectClass().isAssignableFrom(returnedObject.getClass())) {
if (logger.isDebugEnabled()) {
logger.debug("Return object is not applicable for this provider, skipping");
}
@Override
public void setMessageSource(MessageSource messageSource) {
this.messages = new MessageSourceAccessor(messageSource);
}
return returnedObject;
}
for (ConfigAttribute attr : config) {
if (!this.supports(attr)) {
continue;
}
// Need to make an access decision on this invocation
if (hasPermission(authentication, returnedObject)) {
return returnedObject;
}
logger.debug("Denying access");
throw new AccessDeniedException(messages.getMessage("AclEntryAfterInvocationProvider.noPermission",
new Object[] {authentication.getName(), returnedObject},
"Authentication {0} has NO permissions to the domain object {1}"));
}
return returnedObject;
}
public void setMessageSource(MessageSource messageSource) {
this.messages = new MessageSourceAccessor(messageSource);
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -25,7 +24,6 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.log.LogMessage;
/**
* A filter used to filter arrays.
@@ -34,70 +32,86 @@ import org.springframework.core.log.LogMessage;
* @author Paulo Neves
*/
class ArrayFilterer<T> implements Filterer<T> {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(ArrayFilterer.class);
protected static final Log logger = LogFactory.getLog(ArrayFilterer.class);
private final Set<T> removeList;
//~ Instance fields ================================================================================================
private final T[] list;
private final Set<T> removeList;
private final T[] list;
ArrayFilterer(T[] list) {
this.list = list;
// Collect the removed objects to a HashSet so that
// it is fast to lookup them when a filtered array
// is constructed.
this.removeList = new HashSet<>();
}
//~ Constructors ===================================================================================================
@Override
@SuppressWarnings("unchecked")
public T[] getFilteredObject() {
// Recreate an array of same type and filter the removed objects.
int originalSize = this.list.length;
int sizeOfResultingList = originalSize - this.removeList.size();
T[] filtered = (T[]) Array.newInstance(this.list.getClass().getComponentType(), sizeOfResultingList);
for (int i = 0, j = 0; i < this.list.length; i++) {
T object = this.list[i];
if (!this.removeList.contains(object)) {
filtered[j] = object;
j++;
}
}
logger.debug(LogMessage.of(() -> "Original array contained " + originalSize + " elements; now contains "
+ sizeOfResultingList + " elements"));
return filtered;
}
ArrayFilterer(T[] list) {
this.list = list;
@Override
public Iterator<T> iterator() {
return new ArrayFiltererIterator();
}
// Collect the removed objects to a HashSet so that
// it is fast to lookup them when a filtered array
// is constructed.
removeList = new HashSet<T>();
}
@Override
public void remove(T object) {
this.removeList.add(object);
}
//~ Methods ========================================================================================================
/**
* Iterator for {@link ArrayFilterer} elements.
*/
private class ArrayFiltererIterator implements Iterator<T> {
/**
*
* @see org.springframework.security.acls.afterinvocation.Filterer#getFilteredObject()
*/
@SuppressWarnings("unchecked")
public T[] getFilteredObject() {
// Recreate an array of same type and filter the removed objects.
int originalSize = list.length;
int sizeOfResultingList = originalSize - removeList.size();
T[] filtered = (T[]) Array.newInstance(list.getClass().getComponentType(), sizeOfResultingList);
private int index = 0;
for (int i = 0, j = 0; i < list.length; i++) {
T object = list[i];
@Override
public boolean hasNext() {
return this.index < ArrayFilterer.this.list.length;
}
if (!removeList.contains(object)) {
filtered[j] = object;
j++;
}
}
@Override
public T next() {
if (hasNext()) {
return ArrayFilterer.this.list[this.index++];
}
throw new NoSuchElementException();
}
if (logger.isDebugEnabled()) {
logger.debug("Original array contained " + originalSize + " elements; now contains " + sizeOfResultingList
+ " elements");
}
}
return filtered;
}
/**
*
* @see org.springframework.security.acls.afterinvocation.Filterer#iterator()
*/
public Iterator<T> iterator() {
return new Iterator<T>() {
private int index = 0;
public boolean hasNext() {
return index < list.length;
}
public T next() {
if (hasNext() == false) {
throw new NoSuchElementException();
}
return list[index++];
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
*
* @see org.springframework.security.acls.afterinvocation.Filterer#remove(java.lang.Object)
*/
public void remove(T object) {
removeList.add(object);
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -16,15 +15,14 @@
package org.springframework.security.acls.afterinvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.log.LogMessage;
/**
* A filter used to filter Collections.
@@ -33,46 +31,73 @@ import org.springframework.core.log.LogMessage;
* @author Paulo Neves
*/
class CollectionFilterer<T> implements Filterer<T> {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(CollectionFilterer.class);
protected static final Log logger = LogFactory.getLog(CollectionFilterer.class);
private final Collection<T> collection;
//~ Instance fields ================================================================================================
private final Set<T> removeList;
private Collection<T> collection;
CollectionFilterer(Collection<T> collection) {
this.collection = collection;
// We create a Set of objects to be removed from the Collection,
// as ConcurrentModificationException prevents removal during
// iteration, and making a new Collection to be returned is
// problematic as the original Collection implementation passed
// to the method may not necessarily be re-constructable (as
// the Collection(collection) constructor is not guaranteed and
// manually adding may lose sort order or other capabilities)
this.removeList = new HashSet<>();
}
// collectionIter offers significant performance optimisations (as
// per security-developer mailing list conversation 19/5/05)
private Iterator<T> collectionIter;
private Set<T> removeList;
@Override
public Object getFilteredObject() {
// Now the Iterator has ended, remove Objects from Collection
Iterator<T> removeIter = this.removeList.iterator();
int originalSize = this.collection.size();
while (removeIter.hasNext()) {
this.collection.remove(removeIter.next());
}
logger.debug(LogMessage.of(() -> "Original collection contained " + originalSize + " elements; now contains "
+ this.collection.size() + " elements"));
return this.collection;
}
//~ Constructors ===================================================================================================
@Override
public Iterator<T> iterator() {
return this.collection.iterator();
}
CollectionFilterer(Collection<T> collection) {
this.collection = collection;
@Override
public void remove(T object) {
this.removeList.add(object);
}
// We create a Set of objects to be removed from the Collection,
// as ConcurrentModificationException prevents removal during
// iteration, and making a new Collection to be returned is
// problematic as the original Collection implementation passed
// to the method may not necessarily be re-constructable (as
// the Collection(collection) constructor is not guaranteed and
// manually adding may lose sort order or other capabilities)
removeList = new HashSet<T>();
}
//~ Methods ========================================================================================================
/**
*
* @see org.springframework.security.acls.afterinvocation.Filterer#getFilteredObject()
*/
public Object getFilteredObject() {
// Now the Iterator has ended, remove Objects from Collection
Iterator<T> removeIter = removeList.iterator();
int originalSize = collection.size();
while (removeIter.hasNext()) {
collection.remove(removeIter.next());
}
if (logger.isDebugEnabled()) {
logger.debug("Original collection contained " + originalSize + " elements; now contains "
+ collection.size() + " elements");
}
return collection;
}
/**
*
* @see org.springframework.security.acls.afterinvocation.Filterer#iterator()
*/
public Iterator<T> iterator() {
collectionIter = collection.iterator();
return collectionIter;
}
/**
*
* @see org.springframework.security.acls.afterinvocation.Filterer#remove(java.lang.Object)
*/
public void remove(T object) {
removeList.add(object);
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -18,6 +17,7 @@ package org.springframework.security.acls.afterinvocation;
import java.util.Iterator;
/**
* Filterer strategy interface.
*
@@ -25,24 +25,26 @@ import java.util.Iterator;
* @author Paulo Neves
*/
interface Filterer<T> extends Iterable<T> {
//~ Methods ========================================================================================================
/**
* Gets the filtered collection or array.
* @return the filtered collection or array
*/
Object getFilteredObject();
/**
* Gets the filtered collection or array.
*
* @return the filtered collection or array
*/
Object getFilteredObject();
/**
* Returns an iterator over the filtered collection or array.
* @return an Iterator
*/
@Override
Iterator<T> iterator();
/**
* Removes the given object from the resulting list.
* @param object the object to be removed
*/
void remove(T object);
/**
* Returns an iterator over the filtered collection or array.
*
* @return an Iterator
*/
Iterator<T> iterator();
/**
* Removes the the given object from the resulting list.
*
* @param object the object to be removed
*/
void remove(T object);
}
@@ -1,21 +1,6 @@
/*
* Copyright 2002-2016 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
*
* https://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.
*/
/**
* After-invocation providers for collection and array filtering. Consider using a
* {@code PostFilter} annotation in preference.
* After-invocation providers for collection and array filtering. Consider using a {@code PostFilter} annotation in
* preference.
*/
package org.springframework.security.acls.afterinvocation;
@@ -1,19 +1,3 @@
/*
* Copyright 2002-2016 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
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
import org.springframework.security.acls.model.Permission;
@@ -26,61 +10,63 @@ import org.springframework.security.acls.model.Permission;
*/
public abstract class AbstractPermission implements Permission {
protected final char code;
//~ Instance fields ================================================================================================
protected int mask;
protected char code;
protected int mask;
/**
* Sets the permission mask and uses the '*' character to represent active bits when
* represented as a bit pattern string.
* @param mask the integer bit mask for the permission
*/
protected AbstractPermission(int mask) {
this.mask = mask;
this.code = '*';
}
//~ Constructors ===================================================================================================
/**
* Sets the permission mask and uses the '*' character to represent active bits when represented as a bit
* pattern string.
*
* @param mask the integer bit mask for the permission
*/
protected AbstractPermission(int mask) {
this.mask = mask;
this.code = '*';
}
/**
* Sets the permission mask and uses the specified character for active bits.
* @param mask the integer bit mask for the permission
* @param code the character to print for each active bit in the mask (see
* {@link Permission#getPattern()})
*/
protected AbstractPermission(int mask, char code) {
this.mask = mask;
this.code = code;
}
/**
* Sets the permission mask and uses the specified character for active bits.
*
* @param mask the integer bit mask for the permission
* @param code the character to print for each active bit in the mask (see {@link Permission#getPattern()})
*/
protected AbstractPermission(int mask, char code) {
this.mask = mask;
this.code = code;
}
@Override
public final boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!(obj instanceof Permission)) {
return false;
}
Permission other = (Permission) obj;
return (this.mask == other.getMask());
}
//~ Methods ========================================================================================================
@Override
public final int hashCode() {
return this.mask;
}
public final boolean equals(Object arg0) {
if (arg0 == null) {
return false;
}
@Override
public final String toString() {
return this.getClass().getSimpleName() + "[" + getPattern() + "=" + this.mask + "]";
}
if (!(arg0 instanceof Permission)) {
return false;
}
@Override
public final int getMask() {
return this.mask;
}
Permission rhs = (Permission) arg0;
@Override
public String getPattern() {
return AclFormattingUtils.printBinary(this.mask, this.code);
}
return (this.mask == rhs.getMask());
}
public final int getMask() {
return mask;
}
public String getPattern() {
return AclFormattingUtils.printBinary(mask, code);
}
public final String toString() {
return this.getClass().getSimpleName() + "[" + getPattern() + "=" + mask + "]";
}
public final int hashCode() {
return this.mask;
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2002-2016 the original author or authors.
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,180 +12,163 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
import java.io.Serializable;
import org.springframework.security.acls.model.AccessControlEntry;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.AuditableAccessControlEntry;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.Sid;
import org.springframework.util.Assert;
import java.io.Serializable;
/**
* An immutable default implementation of <code>AccessControlEntry</code>.
*
* @author Ben Alex
*/
public class AccessControlEntryImpl implements AccessControlEntry, AuditableAccessControlEntry {
//~ Instance fields ================================================================================================
private final Acl acl;
private Acl acl;
private Permission permission;
private Serializable id;
private Sid sid;
private boolean auditFailure = false;
private boolean auditSuccess = false;
private boolean granting;
private Permission permission;
//~ Constructors ===================================================================================================
private final Serializable id;
public AccessControlEntryImpl(Serializable id, Acl acl, Sid sid, Permission permission, boolean granting,
boolean auditSuccess, boolean auditFailure) {
Assert.notNull(acl, "Acl required");
Assert.notNull(sid, "Sid required");
Assert.notNull(permission, "Permission required");
this.id = id;
this.acl = acl; // can be null
this.sid = sid;
this.permission = permission;
this.granting = granting;
this.auditSuccess = auditSuccess;
this.auditFailure = auditFailure;
}
private final Sid sid;
//~ Methods ========================================================================================================
private boolean auditFailure = false;
public boolean equals(Object arg0) {
if (!(arg0 instanceof AccessControlEntryImpl)) {
return false;
}
private boolean auditSuccess = false;
AccessControlEntryImpl rhs = (AccessControlEntryImpl) arg0;
private final boolean granting;
if (this.acl == null) {
if (rhs.getAcl() != null) {
return false;
}
// Both this.acl and rhs.acl are null and thus equal
} else {
// this.acl is non-null
if (rhs.getAcl() == null) {
return false;
}
public AccessControlEntryImpl(Serializable id, Acl acl, Sid sid, Permission permission, boolean granting,
boolean auditSuccess, boolean auditFailure) {
Assert.notNull(acl, "Acl required");
Assert.notNull(sid, "Sid required");
Assert.notNull(permission, "Permission required");
this.id = id;
this.acl = acl; // can be null
this.sid = sid;
this.permission = permission;
this.granting = granting;
this.auditSuccess = auditSuccess;
this.auditFailure = auditFailure;
}
// Both this.acl and rhs.acl are non-null, so do a comparison
if (this.acl.getObjectIdentity() == null) {
if (rhs.acl.getObjectIdentity() != null) {
return false;
}
// Both this.acl and rhs.acl are null and thus equal
} else {
// Both this.acl.objectIdentity and rhs.acl.objectIdentity are non-null
if (!this.acl.getObjectIdentity().equals(rhs.getAcl().getObjectIdentity())) {
return false;
}
}
}
@Override
public boolean equals(Object arg0) {
if (!(arg0 instanceof AccessControlEntryImpl)) {
return false;
}
AccessControlEntryImpl other = (AccessControlEntryImpl) arg0;
if (this.acl == null) {
if (other.getAcl() != null) {
return false;
}
// Both this.acl and rhs.acl are null and thus equal
}
else {
// this.acl is non-null
if (other.getAcl() == null) {
return false;
}
if (this.id == null) {
if (rhs.id != null) {
return false;
}
// Both this.id and rhs.id are null and thus equal
} else {
// this.id is non-null
if (rhs.id == null) {
return false;
}
// Both this.acl and rhs.acl are non-null, so do a comparison
if (this.acl.getObjectIdentity() == null) {
if (other.acl.getObjectIdentity() != null) {
return false;
}
// Both this.acl and rhs.acl are null and thus equal
}
else {
// Both this.acl.objectIdentity and rhs.acl.objectIdentity are non-null
if (!this.acl.getObjectIdentity().equals(other.getAcl().getObjectIdentity())) {
return false;
}
}
}
if (this.id == null) {
if (other.id != null) {
return false;
}
// Both this.id and rhs.id are null and thus equal
}
else {
// this.id is non-null
if (other.id == null) {
return false;
}
// Both this.id and rhs.id are non-null
if (!this.id.equals(other.id)) {
return false;
}
}
if ((this.auditFailure != other.isAuditFailure()) || (this.auditSuccess != other.isAuditSuccess())
|| (this.granting != other.isGranting()) || !this.permission.equals(other.getPermission())
|| !this.sid.equals(other.getSid())) {
return false;
}
return true;
}
// Both this.id and rhs.id are non-null
if (!this.id.equals(rhs.id)) {
return false;
}
}
@Override
public int hashCode() {
int result = this.permission.hashCode();
result = 31 * result + ((this.id != null) ? this.id.hashCode() : 0);
result = 31 * result + (this.sid.hashCode());
result = 31 * result + (this.auditFailure ? 1 : 0);
result = 31 * result + (this.auditSuccess ? 1 : 0);
result = 31 * result + (this.granting ? 1 : 0);
return result;
}
if ((this.auditFailure != rhs.isAuditFailure()) || (this.auditSuccess != rhs.isAuditSuccess())
|| (this.granting != rhs.isGranting())
|| !this.permission.equals(rhs.getPermission()) || !this.sid.equals(rhs.getSid())) {
return false;
}
@Override
public Acl getAcl() {
return this.acl;
}
return true;
}
@Override
public Serializable getId() {
return this.id;
}
public Acl getAcl() {
return acl;
}
@Override
public Permission getPermission() {
return this.permission;
}
public Serializable getId() {
return id;
}
@Override
public Sid getSid() {
return this.sid;
}
public Permission getPermission() {
return permission;
}
@Override
public boolean isAuditFailure() {
return this.auditFailure;
}
public Sid getSid() {
return sid;
}
@Override
public boolean isAuditSuccess() {
return this.auditSuccess;
}
public boolean isAuditFailure() {
return auditFailure;
}
@Override
public boolean isGranting() {
return this.granting;
}
public boolean isAuditSuccess() {
return auditSuccess;
}
void setAuditFailure(boolean auditFailure) {
this.auditFailure = auditFailure;
}
public boolean isGranting() {
return granting;
}
void setAuditSuccess(boolean auditSuccess) {
this.auditSuccess = auditSuccess;
}
void setAuditFailure(boolean auditFailure) {
this.auditFailure = auditFailure;
}
void setPermission(Permission permission) {
Assert.notNull(permission, "Permission required");
this.permission = permission;
}
void setAuditSuccess(boolean auditSuccess) {
this.auditSuccess = auditSuccess;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("AccessControlEntryImpl[");
sb.append("id: ").append(this.id).append("; ");
sb.append("granting: ").append(this.granting).append("; ");
sb.append("sid: ").append(this.sid).append("; ");
sb.append("permission: ").append(this.permission).append("; ");
sb.append("auditSuccess: ").append(this.auditSuccess).append("; ");
sb.append("auditFailure: ").append(this.auditFailure);
sb.append("]");
return sb.toString();
}
void setPermission(Permission permission) {
Assert.notNull(permission, "Permission required");
this.permission = permission;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("AccessControlEntryImpl[");
sb.append("id: ").append(this.id).append("; ");
sb.append("granting: ").append(this.granting).append("; ");
sb.append("sid: ").append(this.sid).append("; ");
sb.append("permission: ").append(this.permission).append("; ");
sb.append("auditSuccess: ").append(this.auditSuccess).append("; ");
sb.append("auditFailure: ").append(this.auditFailure);
sb.append("]");
return sb.toString();
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -18,6 +17,7 @@ package org.springframework.security.acls.domain;
import org.springframework.security.acls.model.Acl;
/**
* Strategy used by {@link AclImpl} to determine whether a principal is permitted to call
* adminstrative methods on the <code>AclImpl</code>.
@@ -25,13 +25,13 @@ import org.springframework.security.acls.model.Acl;
* @author Ben Alex
*/
public interface AclAuthorizationStrategy {
//~ Static fields/initializers =====================================================================================
int CHANGE_OWNERSHIP = 0;
int CHANGE_OWNERSHIP = 0;
int CHANGE_AUDITING = 1;
int CHANGE_GENERAL = 2;
int CHANGE_AUDITING = 1;
int CHANGE_GENERAL = 2;
void securityCheck(Acl acl, int changeType);
//~ Methods ========================================================================================================
void securityCheck(Acl acl, int changeType);
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -18,7 +17,6 @@ package org.springframework.security.acls.domain;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.acls.model.Acl;
@@ -26,118 +24,96 @@ import org.springframework.security.acls.model.Sid;
import org.springframework.security.acls.model.SidRetrievalStrategy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.Assert;
/**
* Default implementation of {@link AclAuthorizationStrategy}.
* <p>
* Permission will be granted if at least one of the following conditions is true for the
* current principal.
* <ul>
* <li>is the owner (as defined by the ACL).</li>
* <li>holds the relevant system-wide {@link GrantedAuthority} injected into the
* constructor.</li>
* <li>has {@link BasePermission#ADMINISTRATION} permission (as defined by the ACL).</li>
* </ul>
* Permission will be granted provided the current principal is either the owner (as defined by the ACL), has
* {@link BasePermission#ADMINISTRATION} (as defined by the ACL and via a {@link Sid} retrieved for the current
* principal via {@link #sidRetrievalStrategy}), or if the current principal holds the relevant system-wide
* {@link GrantedAuthority} and injected into the constructor.
*
* @author Ben Alex
*/
public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
//~ Instance fields ================================================================================================
private final GrantedAuthority gaGeneralChanges;
private GrantedAuthority gaGeneralChanges;
private GrantedAuthority gaModifyAuditing;
private GrantedAuthority gaTakeOwnership;
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
private final GrantedAuthority gaModifyAuditing;
//~ Constructors ===================================================================================================
private final GrantedAuthority gaTakeOwnership;
/**
* Constructor. The only mandatory parameter relates to the system-wide {@link GrantedAuthority} instances that
* can be held to always permit ACL changes.
*
* @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)
*/
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];
}
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
//~ Methods ========================================================================================================
/**
* 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 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) {
this.gaTakeOwnership = auths[0];
this.gaModifyAuditing = auths[1];
this.gaGeneralChanges = auths[2];
}
else {
this.gaTakeOwnership = auths[0];
this.gaModifyAuditing = auths[0];
this.gaGeneralChanges = auths[0];
}
}
public void securityCheck(Acl acl, int changeType) {
if ((SecurityContextHolder.getContext() == null)
|| (SecurityContextHolder.getContext().getAuthentication() == null)
|| !SecurityContextHolder.getContext().getAuthentication().isAuthenticated()) {
throw new AccessDeniedException("Authenticated principal required to operate with ACLs");
}
@Override
public void securityCheck(Acl acl, int changeType) {
if ((SecurityContextHolder.getContext() == null)
|| (SecurityContextHolder.getContext().getAuthentication() == null)
|| !SecurityContextHolder.getContext().getAuthentication().isAuthenticated()) {
throw new AccessDeniedException("Authenticated principal required to operate with ACLs");
}
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// Check if authorized by virtue of ACL ownership
Sid currentUser = createCurrentUser(authentication);
if (currentUser.equals(acl.getOwner())
&& ((changeType == CHANGE_GENERAL) || (changeType == CHANGE_OWNERSHIP))) {
return;
}
// Not authorized by ACL ownership; try via adminstrative permissions
GrantedAuthority requiredAuthority = getRequiredAuthority(changeType);
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// Iterate this principal's authorities to determine right
Set<String> authorities = AuthorityUtils.authorityListToSet(authentication.getAuthorities());
if (authorities.contains(requiredAuthority.getAuthority())) {
return;
}
// Check if authorized by virtue of ACL ownership
Sid currentUser = new PrincipalSid(authentication);
// Try to get permission via ACEs within the ACL
List<Sid> sids = this.sidRetrievalStrategy.getSids(authentication);
if (acl.isGranted(Arrays.asList(BasePermission.ADMINISTRATION), sids, false)) {
return;
}
if (currentUser.equals(acl.getOwner())
&& ((changeType == CHANGE_GENERAL) || (changeType == CHANGE_OWNERSHIP))) {
return;
}
throw new AccessDeniedException(
"Principal does not have required ACL permissions to perform requested operation");
}
// Not authorized by ACL ownership; try via adminstrative permissions
GrantedAuthority requiredAuthority = null;
private GrantedAuthority getRequiredAuthority(int changeType) {
if (changeType == CHANGE_AUDITING) {
return this.gaModifyAuditing;
}
if (changeType == CHANGE_GENERAL) {
return this.gaGeneralChanges;
}
if (changeType == CHANGE_OWNERSHIP) {
return this.gaTakeOwnership;
}
throw new IllegalArgumentException("Unknown change type");
}
if (changeType == CHANGE_AUDITING) {
requiredAuthority = this.gaModifyAuditing;
} else if (changeType == CHANGE_GENERAL) {
requiredAuthority = this.gaGeneralChanges;
} else if (changeType == CHANGE_OWNERSHIP) {
requiredAuthority = this.gaTakeOwnership;
} else {
throw new IllegalArgumentException("Unknown change type");
}
/**
* Creates a principal-like sid from the authentication information.
* @param authentication the authentication information that can provide principal and
* thus the sid's id will be dependant on the value inside
* @return a sid with the ID taken from the authentication information
*/
protected Sid createCurrentUser(Authentication authentication) {
return new PrincipalSid(authentication);
}
// Iterate this principal's authorities to determine right
if (authentication.getAuthorities().contains(requiredAuthority)) {
return;
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
// Try to get permission via ACEs within the ACL
List<Sid> sids = sidRetrievalStrategy.getSids(authentication);
if (acl.isGranted(Arrays.asList(BasePermission.ADMINISTRATION), sids, false)) {
return;
}
throw new AccessDeniedException(
"Principal does not have required ACL permissions to perform requested operation");
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,12 +12,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
import org.springframework.security.acls.model.Permission;
import org.springframework.util.Assert;
/**
* Utility methods for displaying ACL information.
*
@@ -26,74 +25,83 @@ import org.springframework.util.Assert;
*/
public abstract class AclFormattingUtils {
public static String demergePatterns(String original, String removeBits) {
Assert.notNull(original, "Original string required");
Assert.notNull(removeBits, "Bits To Remove string required");
Assert.isTrue(original.length() == removeBits.length(),
"Original and Bits To Remove strings must be identical length");
char[] replacement = new char[original.length()];
for (int i = 0; i < original.length(); i++) {
if (removeBits.charAt(i) == Permission.RESERVED_OFF) {
replacement[i] = original.charAt(i);
}
else {
replacement[i] = Permission.RESERVED_OFF;
}
}
return new String(replacement);
}
public static String demergePatterns(String original, String removeBits) {
Assert.notNull(original, "Original string required");
Assert.notNull(removeBits, "Bits To Remove string required");
Assert.isTrue(original.length() == removeBits.length(),
"Original and Bits To Remove strings must be identical length");
public static String mergePatterns(String original, String extraBits) {
Assert.notNull(original, "Original string required");
Assert.notNull(extraBits, "Extra Bits string required");
Assert.isTrue(original.length() == extraBits.length(),
"Original and Extra Bits strings must be identical length");
char[] replacement = new char[extraBits.length()];
for (int i = 0; i < extraBits.length(); i++) {
if (extraBits.charAt(i) == Permission.RESERVED_OFF) {
replacement[i] = original.charAt(i);
}
else {
replacement[i] = extraBits.charAt(i);
}
}
return new String(replacement);
}
char[] replacement = new char[original.length()];
/**
* Returns a representation of the active bits in the presented mask, with each active
* bit being denoted by character '*'.
* <p>
* Inactive bits will be denoted by character {@link Permission#RESERVED_OFF}.
* @param i the integer bit mask to print the active bits for
* @return a 32-character representation of the bit mask
*/
public static String printBinary(int i) {
return printBinary(i, '*', Permission.RESERVED_OFF);
}
for (int i = 0; i < original.length(); i++) {
if (removeBits.charAt(i) == Permission.RESERVED_OFF) {
replacement[i] = original.charAt(i);
} else {
replacement[i] = Permission.RESERVED_OFF;
}
}
/**
* Returns a representation of the active bits in the presented mask, with each active
* bit being denoted by the passed character.
* <p>
* Inactive bits will be denoted by character {@link Permission#RESERVED_OFF}.
* @param mask the integer bit mask to print the active bits for
* @param code the character to print when an active bit is detected
* @return a 32-character representation of the bit mask
*/
public static String printBinary(int mask, char code) {
Assert.doesNotContain(Character.toString(code), Character.toString(Permission.RESERVED_ON),
() -> Permission.RESERVED_ON + " is a reserved character code");
Assert.doesNotContain(Character.toString(code), Character.toString(Permission.RESERVED_OFF),
() -> Permission.RESERVED_OFF + " is a reserved character code");
return printBinary(mask, Permission.RESERVED_ON, Permission.RESERVED_OFF).replace(Permission.RESERVED_ON, code);
}
return new String(replacement);
}
private static String printBinary(int i, char on, char off) {
String s = Integer.toBinaryString(i);
String pattern = Permission.THIRTY_TWO_RESERVED_OFF;
String temp2 = pattern.substring(0, pattern.length() - s.length()) + s;
return temp2.replace('0', off).replace('1', on);
}
public static String mergePatterns(String original, String extraBits) {
Assert.notNull(original, "Original string required");
Assert.notNull(extraBits, "Extra Bits string required");
Assert.isTrue(original.length() == extraBits.length(),
"Original and Extra Bits strings must be identical length");
char[] replacement = new char[extraBits.length()];
for (int i = 0; i < extraBits.length(); i++) {
if (extraBits.charAt(i) == Permission.RESERVED_OFF) {
replacement[i] = original.charAt(i);
} else {
replacement[i] = extraBits.charAt(i);
}
}
return new String(replacement);
}
/**
* Returns a representation of the active bits in the presented mask, with each active bit being denoted by
* character '*'.
* <p>
* Inactive bits will be denoted by character {@link Permission#RESERVED_OFF}.
*
* @param i the integer bit mask to print the active bits for
*
* @return a 32-character representation of the bit mask
*/
public static String printBinary(int i) {
return printBinary(i, '*', Permission.RESERVED_OFF);
}
/**
* Returns a representation of the active bits in the presented mask, with each active bit being denoted by
* the passed character.
* <p>
* Inactive bits will be denoted by character {@link Permission#RESERVED_OFF}.
*
* @param mask the integer bit mask to print the active bits for
* @param code the character to print when an active bit is detected
*
* @return a 32-character representation of the bit mask
*/
public static String printBinary(int mask, char code) {
Assert.doesNotContain(Character.toString(code), Character.toString(Permission.RESERVED_ON),
Permission.RESERVED_ON + " is a reserved character code");
Assert.doesNotContain(Character.toString(code), Character.toString(Permission.RESERVED_OFF),
Permission.RESERVED_OFF + " is a reserved character code");
return printBinary(mask, Permission.RESERVED_ON, Permission.RESERVED_OFF).replace(Permission.RESERVED_ON, code);
}
private static String printBinary(int i, char on, char off) {
String s = Integer.toString(i, 2);
String pattern = Permission.THIRTY_TWO_RESERVED_OFF;
String temp2 = pattern.substring(0, pattern.length() - s.length()) + s;
return temp2.replace('0', off).replace('1', on);
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
import java.io.Serializable;
@@ -28,11 +26,10 @@ 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;
import org.springframework.util.ObjectUtils;
/**
* Base implementation of <code>Acl</code>.
@@ -40,301 +37,372 @@ import org.springframework.util.ObjectUtils;
* @author Ben Alex
*/
public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
//~ Instance fields ================================================================================================
private Acl parentAcl;
private Acl parentAcl;
private transient AclAuthorizationStrategy aclAuthorizationStrategy;
private transient AuditLogger auditLogger;
private List<AccessControlEntry> aces = new ArrayList<AccessControlEntry>();
private ObjectIdentity objectIdentity;
private Serializable id;
private Sid owner; // OwnershipAcl
private List<Sid> loadedSids = null; // includes all SIDs the WHERE clause covered, even if there was no ACE for a SID
private boolean entriesInheriting = true;
private transient AclAuthorizationStrategy aclAuthorizationStrategy;
//~ Constructors ===================================================================================================
private transient PermissionGrantingStrategy permissionGrantingStrategy;
/**
* Minimal constructor, which should be used {@link
* org.springframework.security.acls.model.MutableAclService#createAcl(ObjectIdentity)}.
*
* @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)
*/
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
AuditLogger auditLogger) {
Assert.notNull(objectIdentity, "Object Identity required");
Assert.notNull(id, "Id required");
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
Assert.notNull(auditLogger, "AuditLogger required");
this.objectIdentity = objectIdentity;
this.id = id;
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
this.auditLogger = auditLogger;
}
private final List<AccessControlEntry> aces = new ArrayList<>();
/**
* 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 (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,
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;
}
private ObjectIdentity objectIdentity;
/**
* Private no-argument constructor for use by reflection-based persistence
* tools along with field-level access.
*/
@SuppressWarnings("unused")
private AclImpl() {}
private Serializable id;
//~ Methods ========================================================================================================
// OwnershipAcl
private Sid owner;
public void deleteAce(int aceIndex) throws NotFoundException {
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
verifyAceIndexExists(aceIndex);
// includes all SIDs the WHERE clause covered, even if there was no ACE for a SID
private List<Sid> loadedSids = null;
synchronized (aces) {
this.aces.remove(aceIndex);
}
}
private boolean entriesInheriting = true;
private void verifyAceIndexExists(int aceIndex) {
if (aceIndex < 0) {
throw new NotFoundException("aceIndex must be greater than or equal to zero");
}
if (aceIndex >= this.aces.size()) {
throw new NotFoundException("aceIndex must refer to an index of the AccessControlEntry list. " +
"List size is " + aces.size() + ", index was " + aceIndex);
}
}
/**
* Minimal constructor, which should be used
* {@link org.springframework.security.acls.model.MutableAclService#createAcl(ObjectIdentity)}
* .
* @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)
*/
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
AuditLogger auditLogger) {
Assert.notNull(objectIdentity, "Object Identity required");
Assert.notNull(id, "Id required");
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
Assert.notNull(auditLogger, "AuditLogger required");
this.objectIdentity = objectIdentity;
this.id = id;
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
this.permissionGrantingStrategy = new DefaultPermissionGrantingStrategy(auditLogger);
}
public void insertAce(int atIndexLocation, Permission permission, Sid sid, boolean granting) throws NotFoundException {
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
Assert.notNull(permission, "Permission required");
Assert.notNull(sid, "Sid required");
if (atIndexLocation < 0) {
throw new NotFoundException("atIndexLocation must be greater than or equal to zero");
}
if (atIndexLocation > this.aces.size()) {
throw new NotFoundException("atIndexLocation must be less than or equal to the size of the AccessControlEntry collection");
}
/**
* 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 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) {
Assert.notNull(objectIdentity, "Object Identity required");
Assert.notNull(id, "Id required");
Assert.notNull(aclAuthorizationStrategy, "AclAuthorizationStrategy required");
Assert.notNull(owner, "Owner required");
this.objectIdentity = objectIdentity;
this.id = id;
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
this.parentAcl = parentAcl; // may be null
this.loadedSids = loadedSids; // may be null
this.entriesInheriting = entriesInheriting;
this.owner = owner;
this.permissionGrantingStrategy = grantingStrategy;
}
AccessControlEntryImpl ace = new AccessControlEntryImpl(null, this, sid, permission, granting, false, false);
/**
* Private no-argument constructor for use by reflection-based persistence tools along
* with field-level access.
*/
@SuppressWarnings("unused")
private AclImpl() {
}
synchronized (aces) {
this.aces.add(atIndexLocation, ace);
}
}
@Override
public void deleteAce(int aceIndex) throws NotFoundException {
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
verifyAceIndexExists(aceIndex);
synchronized (this.aces) {
this.aces.remove(aceIndex);
}
}
public List<AccessControlEntry> getEntries() {
// Can safely return AccessControlEntry directly, as they're immutable outside the ACL package
return new ArrayList<AccessControlEntry>(aces);
}
private void verifyAceIndexExists(int aceIndex) {
if (aceIndex < 0) {
throw new NotFoundException("aceIndex must be greater than or equal to zero");
}
if (aceIndex >= this.aces.size()) {
throw new NotFoundException("aceIndex must refer to an index of the AccessControlEntry list. "
+ "List size is " + this.aces.size() + ", index was " + aceIndex);
}
}
public Serializable getId() {
return this.id;
}
@Override
public void insertAce(int atIndexLocation, Permission permission, Sid sid, boolean granting)
throws NotFoundException {
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
Assert.notNull(permission, "Permission required");
Assert.notNull(sid, "Sid required");
if (atIndexLocation < 0) {
throw new NotFoundException("atIndexLocation must be greater than or equal to zero");
}
if (atIndexLocation > this.aces.size()) {
throw new NotFoundException(
"atIndexLocation must be less than or equal to the size of the AccessControlEntry collection");
}
AccessControlEntryImpl ace = new AccessControlEntryImpl(null, this, sid, permission, granting, false, false);
synchronized (this.aces) {
this.aces.add(atIndexLocation, ace);
}
}
public ObjectIdentity getObjectIdentity() {
return objectIdentity;
}
@Override
public List<AccessControlEntry> getEntries() {
// Can safely return AccessControlEntry directly, as they're immutable outside the
// ACL package
return new ArrayList<>(this.aces);
}
public boolean isEntriesInheriting() {
return entriesInheriting;
}
@Override
public Serializable getId() {
return this.id;
}
/**
* 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
*/
public boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
throws NotFoundException, UnloadedSidException {
Assert.notEmpty(permission, "Permissions required");
Assert.notEmpty(sids, "SIDs required");
@Override
public ObjectIdentity getObjectIdentity() {
return this.objectIdentity;
}
if (!this.isSidLoaded(sids)) {
throw new UnloadedSidException("ACL was not loaded for one or more SID");
}
@Override
public boolean isEntriesInheriting() {
return this.entriesInheriting;
}
AccessControlEntry firstRejection = null;
/**
* Delegates to the {@link PermissionGrantingStrategy}.
* @throws UnloadedSidException if the passed SIDs are unknown to this ACL because the
* ACL was only loaded for a subset of SIDs
* @see DefaultPermissionGrantingStrategy
*/
@Override
public boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
throws NotFoundException, UnloadedSidException {
Assert.notEmpty(permission, "Permissions required");
Assert.notEmpty(sids, "SIDs required");
if (!this.isSidLoaded(sids)) {
throw new UnloadedSidException("ACL was not loaded for one or more SID");
}
return this.permissionGrantingStrategy.isGranted(this, permission, sids, administrativeMode);
}
for (Permission p : permission) {
for (Sid sid: sids) {
// Attempt to find exact match for this permission mask and SID
boolean scanNextSid = true;
@Override
public boolean isSidLoaded(List<Sid> sids) {
// If loadedSides is null, this indicates all SIDs were loaded
// Also return true if the caller didn't specify a SID to find
if ((this.loadedSids == null) || (sids == null) || (sids.size() == 0)) {
return true;
}
for (AccessControlEntry ace : aces ) {
// This ACL applies to a SID subset only. Iterate to check it applies.
for (Sid sid : sids) {
boolean found = false;
for (Sid loadedSid : this.loadedSids) {
if (sid.equals(loadedSid)) {
// this SID is OK
found = true;
break; // out of loadedSids for loop
}
}
if (!found) {
return false;
}
}
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;
}
return true;
}
@Override
public void setEntriesInheriting(boolean entriesInheriting) {
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
this.entriesInheriting = entriesInheriting;
}
// 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;
}
@Override
public void setOwner(Sid newOwner) {
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
Assert.notNull(newOwner, "Owner required");
this.owner = newOwner;
}
scanNextSid = false; // helps break the loop
@Override
public Sid getOwner() {
return this.owner;
}
break; // exit aces loop
}
}
@Override
public void setParent(Acl newParent) {
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
Assert.isTrue(newParent == null || !newParent.equals(this), "Cannot be the parent of yourself");
this.parentAcl = newParent;
}
if (!scanNextSid) {
break; // exit SID for loop (now try next permission)
}
}
}
@Override
public Acl getParentAcl() {
return this.parentAcl;
}
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);
}
@Override
public void updateAce(int aceIndex, Permission permission) throws NotFoundException {
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
verifyAceIndexExists(aceIndex);
synchronized (this.aces) {
AccessControlEntryImpl ace = (AccessControlEntryImpl) this.aces.get(aceIndex);
ace.setPermission(permission);
}
}
return false;
}
@Override
public void updateAuditing(int aceIndex, boolean auditSuccess, boolean auditFailure) {
this.aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_AUDITING);
verifyAceIndexExists(aceIndex);
synchronized (this.aces) {
AccessControlEntryImpl ace = (AccessControlEntryImpl) this.aces.get(aceIndex);
ace.setAuditSuccess(auditSuccess);
ace.setAuditFailure(auditFailure);
}
}
// 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");
}
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || !(obj instanceof AclImpl)) {
return false;
}
AclImpl other = (AclImpl) obj;
boolean result = true;
result = result && this.aces.equals(other.aces);
result = result && ObjectUtils.nullSafeEquals(this.parentAcl, other.parentAcl);
result = result && ObjectUtils.nullSafeEquals(this.objectIdentity, other.objectIdentity);
result = result && ObjectUtils.nullSafeEquals(this.id, other.id);
result = result && ObjectUtils.nullSafeEquals(this.owner, other.owner);
result = result && this.entriesInheriting == other.entriesInheriting;
result = result && ObjectUtils.nullSafeEquals(this.loadedSids, other.loadedSids);
return result;
}
public boolean isSidLoaded(List<Sid> sids) {
// If loadedSides is null, this indicates all SIDs were loaded
// Also return true if the caller didn't specify a SID to find
if ((this.loadedSids == null) || (sids == null) || (sids.size() == 0)) {
return true;
}
@Override
public int hashCode() {
int result = (this.parentAcl != null) ? this.parentAcl.hashCode() : 0;
result = 31 * result + this.aclAuthorizationStrategy.hashCode();
result = 31 * result
+ ((this.permissionGrantingStrategy != null) ? this.permissionGrantingStrategy.hashCode() : 0);
result = 31 * result + ((this.aces != null) ? this.aces.hashCode() : 0);
result = 31 * result + this.objectIdentity.hashCode();
result = 31 * result + this.id.hashCode();
result = 31 * result + ((this.owner != null) ? this.owner.hashCode() : 0);
result = 31 * result + ((this.loadedSids != null) ? this.loadedSids.hashCode() : 0);
result = 31 * result + (this.entriesInheriting ? 1 : 0);
return result;
}
// This ACL applies to a SID subset only. Iterate to check it applies.
for (Sid sid: sids) {
boolean found = false;
@Override
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 : this.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();
}
for (Sid loadedSid : loadedSids) {
if (sid.equals(loadedSid)) {
// this SID is OK
found = true;
break; // out of loadedSids for loop
}
}
if (!found) {
return false;
}
}
return true;
}
public void setEntriesInheriting(boolean entriesInheriting) {
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
this.entriesInheriting = entriesInheriting;
}
public void setOwner(Sid newOwner) {
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_OWNERSHIP);
Assert.notNull(newOwner, "Owner required");
this.owner = newOwner;
}
public Sid getOwner() {
return this.owner;
}
public void setParent(Acl newParent) {
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
Assert.isTrue(newParent == null || !newParent.equals(this), "Cannot be the parent of yourself");
this.parentAcl = newParent;
}
public Acl getParentAcl() {
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);
verifyAceIndexExists(aceIndex);
synchronized (aces) {
AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(aceIndex);
ace.setPermission(permission);
}
}
public void updateAuditing(int aceIndex, boolean auditSuccess, boolean auditFailure) {
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_AUDITING);
verifyAceIndexExists(aceIndex);
synchronized (aces) {
AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(aceIndex);
ace.setAuditSuccess(auditSuccess);
ace.setAuditFailure(auditFailure);
}
}
public boolean equals(Object obj) {
if (obj instanceof AclImpl) {
AclImpl rhs = (AclImpl) obj;
if (this.aces.equals(rhs.aces)) {
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 != 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;
}
}
return true;
}
}
}
}
}
}
}
}
return false;
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,18 +12,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
import org.springframework.security.acls.model.AccessControlEntry;
/**
* Used by <code>AclImpl</code> to log audit events.
*
* @author Ben Alex
*
*/
public interface AuditLogger {
//~ Methods ========================================================================================================
void logIfNeeded(boolean granted, AccessControlEntry ace);
void logIfNeeded(boolean granted, AccessControlEntry ace);
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,11 +12,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
import org.springframework.security.acls.model.Permission;
/**
* A set of standard permissions.
*
@@ -29,23 +28,17 @@ import org.springframework.security.acls.model.Permission;
* @author Ben Alex
*/
public class BasePermission extends AbstractPermission {
public static final Permission READ = new BasePermission(1 << 0, 'R'); // 1
public static final Permission WRITE = new BasePermission(1 << 1, 'W'); // 2
public static final Permission CREATE = new BasePermission(1 << 2, 'C'); // 4
public static final Permission DELETE = new BasePermission(1 << 3, 'D'); // 8
public static final Permission ADMINISTRATION = new BasePermission(1 << 4, 'A'); // 16
public static final Permission READ = new BasePermission(1 << 0, 'R'); // 1
public static final Permission WRITE = new BasePermission(1 << 1, 'W'); // 2
public static final Permission CREATE = new BasePermission(1 << 2, 'C'); // 4
public static final Permission DELETE = new BasePermission(1 << 3, 'D'); // 8
public static final Permission ADMINISTRATION = new BasePermission(1 << 4, 'A'); // 16
protected BasePermission(int mask) {
super(mask);
}
protected BasePermission(int mask, char code) {
super(mask, code);
}
protected BasePermission(int mask) {
super(mask);
}
protected BasePermission(int mask, char code) {
super(mask, code);
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,32 +12,33 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
import org.springframework.security.acls.model.AccessControlEntry;
import org.springframework.security.acls.model.AuditableAccessControlEntry;
import org.springframework.util.Assert;
/**
* A basic implementation of {@link AuditLogger}.
*
* @author Ben Alex
*/
public class ConsoleAuditLogger implements AuditLogger {
//~ Methods ========================================================================================================
@Override
public void logIfNeeded(boolean granted, AccessControlEntry ace) {
Assert.notNull(ace, "AccessControlEntry required");
if (ace instanceof AuditableAccessControlEntry) {
AuditableAccessControlEntry auditableAce = (AuditableAccessControlEntry) ace;
if (granted && auditableAce.isAuditSuccess()) {
System.out.println("GRANTED due to ACE: " + ace);
}
else if (!granted && auditableAce.isAuditFailure()) {
System.out.println("DENIED due to ACE: " + ace);
}
}
}
public void logIfNeeded(boolean granted, AccessControlEntry ace) {
Assert.notNull(ace, "AccessControlEntry required");
if (ace instanceof AuditableAccessControlEntry) {
AuditableAccessControlEntry auditableAce = (AuditableAccessControlEntry) ace;
if (granted && auditableAce.isAuditSuccess()) {
System.out.println("GRANTED due to ACE: " + ace);
} else if (!granted && auditableAce.isAuditFailure()) {
System.out.println("DENIED due to ACE: " + ace);
}
}
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,50 +12,49 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
import org.springframework.security.acls.model.Permission;
/**
* Represents a <code>Permission</code> that is constructed at runtime from other
* permissions.
* Represents a <code>Permission</code> that is constructed at runtime from other permissions.
*
* <p>
* Methods return <code>this</code>, in order to facilitate method chaining.
* </p>
* <p>Methods return <code>this</code>, in order to facilitate method chaining.</p>
*
* @author Ben Alex
*/
public class CumulativePermission extends AbstractPermission {
private String pattern = THIRTY_TWO_RESERVED_OFF;
private String pattern = THIRTY_TWO_RESERVED_OFF;
public CumulativePermission() {
super(0, ' ');
}
public CumulativePermission() {
super(0, ' ');
}
public CumulativePermission clear(Permission permission) {
this.mask &= ~permission.getMask();
this.pattern = AclFormattingUtils.demergePatterns(this.pattern, permission.getPattern());
return this;
}
public CumulativePermission clear(Permission permission) {
this.mask &= ~permission.getMask();
this.pattern = AclFormattingUtils.demergePatterns(this.pattern, permission.getPattern());
public CumulativePermission clear() {
this.mask = 0;
this.pattern = THIRTY_TWO_RESERVED_OFF;
return this;
}
return this;
}
public CumulativePermission set(Permission permission) {
this.mask |= permission.getMask();
this.pattern = AclFormattingUtils.mergePatterns(this.pattern, permission.getPattern());
return this;
}
public CumulativePermission clear() {
this.mask = 0;
this.pattern = THIRTY_TWO_RESERVED_OFF;
@Override
public String getPattern() {
return this.pattern;
}
return this;
}
public CumulativePermission set(Permission permission) {
this.mask |= permission.getMask();
this.pattern = AclFormattingUtils.mergePatterns(this.pattern, permission.getPattern());
return this;
}
public String getPattern() {
return this.pattern;
}
}
@@ -1,19 +1,3 @@
/*
* Copyright 2002-2018 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
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
import java.lang.reflect.Field;
@@ -29,8 +13,8 @@ import org.springframework.util.Assert;
/**
* Default implementation of {@link PermissionFactory}.
* <p>
* Used as a strategy by classes which wish to map integer masks and permission names to
* <tt>Permission</tt> instances for use with the ACL implementation.
* Used as a strategy by classes which wish to map integer masks and permission names to <tt>Permission</tt>
* instances for use with the ACL implementation.
* <p>
* Maintains a registry of permission names and masks to <tt>Permission</tt> instances.
*
@@ -39,115 +23,124 @@ import org.springframework.util.Assert;
* @since 2.0.3
*/
public class DefaultPermissionFactory implements PermissionFactory {
private final Map<Integer, Permission> registeredPermissionsByInteger = new HashMap<Integer, Permission>();
private final Map<String, Permission> registeredPermissionsByName = new HashMap<String, Permission>();
private final Map<Integer, Permission> registeredPermissionsByInteger = new HashMap<>();
/**
* Registers the <tt>Permission</tt> fields from the <tt>BasePermission</tt> class.
*/
public DefaultPermissionFactory() {
registerPublicPermissions(BasePermission.class);
}
private final Map<String, Permission> registeredPermissionsByName = new HashMap<>();
/**
* Registers the <tt>Permission</tt> fields from the supplied class.
*/
public DefaultPermissionFactory(Class<? extends Permission> permissionClass) {
registerPublicPermissions(permissionClass);
}
/**
* Registers the <tt>Permission</tt> fields from the <tt>BasePermission</tt> class.
*/
public DefaultPermissionFactory() {
registerPublicPermissions(BasePermission.class);
}
/**
* Registers a map of named <tt>Permission</tt> instances.
*
* @param namedPermissions the map of <tt>Permission</tt>s, keyed by name.
*/
public DefaultPermissionFactory(Map<String, ? extends Permission> namedPermissions) {
for (String name : namedPermissions.keySet()) {
registerPermission(namedPermissions.get(name), name);
}
}
/**
* Registers the <tt>Permission</tt> fields from the supplied class.
*/
public DefaultPermissionFactory(Class<? extends Permission> permissionClass) {
registerPublicPermissions(permissionClass);
}
/**
* Registers the public static fields of type {@link Permission} for a give class.
* <p>
* These permissions will be registered under the name of the field. See {@link BasePermission}
* for an example.
*
* @param clazz a {@link Permission} class with public static fields to register
*/
protected void registerPublicPermissions(Class<? extends Permission> clazz) {
Assert.notNull(clazz, "Class required");
/**
* Registers a map of named <tt>Permission</tt> instances.
* @param namedPermissions the map of <tt>Permission</tt>s, keyed by name.
*/
public DefaultPermissionFactory(Map<String, ? extends Permission> namedPermissions) {
for (String name : namedPermissions.keySet()) {
registerPermission(namedPermissions.get(name), name);
}
}
Field[] fields = clazz.getFields();
/**
* Registers the public static fields of type {@link Permission} for a give class.
* <p>
* These permissions will be registered under the name of the field. See
* {@link BasePermission} for an example.
* @param clazz a {@link Permission} class with public static fields to register
*/
protected void registerPublicPermissions(Class<? extends Permission> clazz) {
Assert.notNull(clazz, "Class required");
Field[] fields = clazz.getFields();
for (Field field : fields) {
try {
Object fieldValue = field.get(null);
if (Permission.class.isAssignableFrom(fieldValue.getClass())) {
// Found a Permission static field
Permission perm = (Permission) fieldValue;
String permissionName = field.getName();
registerPermission(perm, permissionName);
}
}
catch (Exception ex) {
}
}
}
for (int i = 0; i < fields.length; i++) {
try {
Object fieldValue = fields[i].get(null);
protected void registerPermission(Permission perm, String permissionName) {
Assert.notNull(perm, "Permission required");
Assert.hasText(permissionName, "Permission name required");
Integer mask = perm.getMask();
if (Permission.class.isAssignableFrom(fieldValue.getClass())) {
// Found a Permission static field
Permission perm = (Permission) fieldValue;
String permissionName = fields[i].getName();
// Ensure no existing Permission uses this integer or code
Assert.isTrue(!this.registeredPermissionsByInteger.containsKey(mask),
() -> "An existing Permission already provides mask " + mask);
Assert.isTrue(!this.registeredPermissionsByName.containsKey(permissionName),
() -> "An existing Permission already provides name '" + permissionName + "'");
registerPermission(perm, permissionName);
}
} catch (Exception ignore) {}
}
}
// Register the new Permission
this.registeredPermissionsByInteger.put(mask, perm);
this.registeredPermissionsByName.put(permissionName, perm);
}
protected void registerPermission(Permission perm, String permissionName) {
Assert.notNull(perm, "Permission required");
Assert.hasText(permissionName, "Permission name required");
@Override
public Permission buildFromMask(int mask) {
if (this.registeredPermissionsByInteger.containsKey(mask)) {
// The requested mask has an exact match against a statically-defined
// Permission, so return it
return this.registeredPermissionsByInteger.get(mask);
}
Integer mask = new Integer(perm.getMask());
// To get this far, we have to use a CumulativePermission
CumulativePermission permission = new CumulativePermission();
for (int i = 0; i < 32; i++) {
int permissionToCheck = 1 << i;
if ((mask & permissionToCheck) == permissionToCheck) {
Permission p = this.registeredPermissionsByInteger.get(permissionToCheck);
Assert.state(p != null,
() -> "Mask '" + permissionToCheck + "' does not have a corresponding static Permission");
permission.set(p);
}
}
return permission;
}
// Ensure no existing Permission uses this integer or code
Assert.isTrue(!registeredPermissionsByInteger.containsKey(mask), "An existing Permission already provides mask " + mask);
Assert.isTrue(!registeredPermissionsByName.containsKey(permissionName), "An existing Permission already provides name '" + permissionName + "'");
@Override
public Permission buildFromName(String name) {
Permission p = this.registeredPermissionsByName.get(name);
Assert.notNull(p, "Unknown permission '" + name + "'");
return p;
}
// Register the new Permission
registeredPermissionsByInteger.put(mask, perm);
registeredPermissionsByName.put(permissionName, perm);
}
@Override
public List<Permission> buildFromNames(List<String> names) {
if ((names == null) || (names.size() == 0)) {
return Collections.emptyList();
}
List<Permission> permissions = new ArrayList<>(names.size());
for (String name : names) {
permissions.add(buildFromName(name));
}
return permissions;
}
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(new Integer(mask));
}
// To get this far, we have to use a CumulativePermission
CumulativePermission permission = new CumulativePermission();
for (int i = 0; i < 32; i++) {
int permissionToCheck = 1 << i;
if ((mask & permissionToCheck) == permissionToCheck) {
Permission p = registeredPermissionsByInteger.get(Integer.valueOf(permissionToCheck));
if (p == null) {
throw new IllegalStateException("Mask '" + permissionToCheck + "' does not have a corresponding static Permission");
}
permission.set(p);
}
}
return permission;
}
public Permission buildFromName(String name) {
Permission p = registeredPermissionsByName.get(name);
if (p == null) {
throw new IllegalArgumentException("Unknown permission '" + name + "'");
}
return p;
}
public List<Permission> buildFromNames(List<String> names) {
if ((names == null) || (names.size() == 0)) {
return Collections.emptyList();
}
List<Permission> permissions = new ArrayList<Permission>(names.size());
for (String name : names) {
permissions.add(buildFromName(name));
}
return permissions;
}
}
@@ -1,151 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
import 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
*/
@Override
public boolean isGranted(Acl acl, List<Permission> permission, List<Sid> sids, boolean administrativeMode)
throws NotFoundException {
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 (isGranted(ace, p) && ace.getSid().equals(sid)) {
// Found a matching ACE, so its authorization decision will
// prevail
if (ace.isGranting()) {
// Success
if (!administrativeMode) {
this.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) {
this.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);
}
// 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");
}
/**
* Compares an ACE Permission to the given Permission. By default, we compare the
* Permission masks for exact match. Subclasses of this strategy can override this
* behavior and implement more sophisticated comparisons, e.g. a bitwise comparison
* for ACEs that grant access. <pre>{@code
* if (ace.isGranting() && p.getMask() != 0) {
* return (ace.getPermission().getMask() & p.getMask()) != 0;
* } else {
* return ace.getPermission().getMask() == p.getMask();
* }
* }</pre>
* @param ace the ACE from the Acl holding the mask.
* @param p the Permission we are checking against.
* @return true, if the respective masks are considered to be equal.
*/
protected boolean isGranted(AccessControlEntry ace, Permission p) {
return ace.getPermission().getMask() == p.getMask();
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
import java.io.Serializable;
@@ -25,115 +23,123 @@ 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.
* Designed to handle the transient fields in {@link AclImpl}. Note that this implementation assumes all
* {@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 Ehcache cache;
private AuditLogger auditLogger;
private AclAuthorizationStrategy aclAuthorizationStrategy;
private PermissionGrantingStrategy permissionGrantingStrategy;
//~ Constructors ===================================================================================================
private AclAuthorizationStrategy aclAuthorizationStrategy;
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 ========================================================================================================
@Override
public void evictFromCache(Serializable pk) {
Assert.notNull(pk, "Primary key (identifier) required");
MutableAcl acl = getFromCache(pk);
if (acl != null) {
this.cache.remove(acl.getId());
this.cache.remove(acl.getObjectIdentity());
}
}
public void evictFromCache(Serializable pk) {
Assert.notNull(pk, "Primary key (identifier) required");
@Override
public void evictFromCache(ObjectIdentity objectIdentity) {
Assert.notNull(objectIdentity, "ObjectIdentity required");
MutableAcl acl = getFromCache(objectIdentity);
if (acl != null) {
this.cache.remove(acl.getId());
this.cache.remove(acl.getObjectIdentity());
}
}
MutableAcl acl = getFromCache(pk);
@Override
public MutableAcl getFromCache(ObjectIdentity objectIdentity) {
Assert.notNull(objectIdentity, "ObjectIdentity required");
try {
Element element = this.cache.get(objectIdentity);
return (element != null) ? initializeTransientFields((MutableAcl) element.getValue()) : null;
}
catch (CacheException ex) {
return null;
}
}
if (acl != null) {
cache.remove(acl.getId());
cache.remove(acl.getObjectIdentity());
}
}
@Override
public MutableAcl getFromCache(Serializable pk) {
Assert.notNull(pk, "Primary key (identifier) required");
try {
Element element = this.cache.get(pk);
return (element != null) ? initializeTransientFields((MutableAcl) element.getValue()) : null;
}
catch (CacheException ex) {
return null;
}
}
public void evictFromCache(ObjectIdentity objectIdentity) {
Assert.notNull(objectIdentity, "ObjectIdentity required");
@Override
public void putInCache(MutableAcl acl) {
Assert.notNull(acl, "Acl required");
Assert.notNull(acl.getObjectIdentity(), "ObjectIdentity required");
Assert.notNull(acl.getId(), "ID required");
if (this.aclAuthorizationStrategy == null) {
if (acl instanceof AclImpl) {
this.aclAuthorizationStrategy = (AclAuthorizationStrategy) FieldUtils
.getProtectedFieldValue("aclAuthorizationStrategy", acl);
this.permissionGrantingStrategy = (PermissionGrantingStrategy) FieldUtils
.getProtectedFieldValue("permissionGrantingStrategy", acl);
}
}
if ((acl.getParentAcl() != null) && (acl.getParentAcl() instanceof MutableAcl)) {
putInCache((MutableAcl) acl.getParentAcl());
}
this.cache.put(new Element(acl.getObjectIdentity(), acl));
this.cache.put(new Element(acl.getId(), acl));
}
MutableAcl acl = getFromCache(objectIdentity);
private MutableAcl initializeTransientFields(MutableAcl value) {
if (value instanceof AclImpl) {
FieldUtils.setProtectedFieldValue("aclAuthorizationStrategy", value, this.aclAuthorizationStrategy);
FieldUtils.setProtectedFieldValue("permissionGrantingStrategy", value, this.permissionGrantingStrategy);
}
if (value.getParentAcl() != null) {
initializeTransientFields((MutableAcl) value.getParentAcl());
}
return value;
}
if (acl != null) {
cache.remove(acl.getId());
cache.remove(acl.getObjectIdentity());
}
}
@Override
public void clearCache() {
this.cache.removeAll();
}
public MutableAcl getFromCache(ObjectIdentity objectIdentity) {
Assert.notNull(objectIdentity, "ObjectIdentity required");
Element element = null;
try {
element = cache.get(objectIdentity);
} catch (CacheException ignored) {}
if (element == null) {
return null;
}
return initializeTransientFields((MutableAcl)element.getValue());
}
public MutableAcl getFromCache(Serializable pk) {
Assert.notNull(pk, "Primary key (identifier) required");
Element element = null;
try {
element = cache.get(pk);
} catch (CacheException ignored) {}
if (element == null) {
return null;
}
return initializeTransientFields((MutableAcl) element.getValue());
}
public void putInCache(MutableAcl acl) {
Assert.notNull(acl, "Acl required");
Assert.notNull(acl.getObjectIdentity(), "ObjectIdentity required");
Assert.notNull(acl.getId(), "ID required");
if (this.aclAuthorizationStrategy == null) {
if (acl instanceof AclImpl) {
this.aclAuthorizationStrategy = (AclAuthorizationStrategy) FieldUtils.getProtectedFieldValue("aclAuthorizationStrategy", acl);
this.auditLogger = (AuditLogger) FieldUtils.getProtectedFieldValue("auditLogger", acl);
}
}
if ((acl.getParentAcl() != null) && (acl.getParentAcl() instanceof MutableAcl)) {
putInCache((MutableAcl) acl.getParentAcl());
}
cache.put(new Element(acl.getObjectIdentity(), acl));
cache.put(new Element(acl.getId(), acl));
}
private MutableAcl initializeTransientFields(MutableAcl value) {
if (value instanceof AclImpl) {
FieldUtils.setProtectedFieldValue("aclAuthorizationStrategy", value, this.aclAuthorizationStrategy);
FieldUtils.setProtectedFieldValue("auditLogger", value, this.auditLogger);
}
if (value.getParentAcl() != null) {
initializeTransientFields((MutableAcl) value.getParentAcl());
}
return value;
}
public void clearCache() {
cache.removeAll();
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,61 +12,60 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
import org.springframework.security.acls.model.Sid;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.util.Assert;
/**
* Represents a <code>GrantedAuthority</code> as a <code>Sid</code>.
* <p>
* This is a basic implementation that simply uses the <code>String</code>-based principal
* for <code>Sid</code> comparison. More complex principal objects may wish to provide an
* alternative <code>Sid</code> implementation that uses some other identifier.
* </p>
* Represents a <code>GrantedAuthority</code> as a <code>Sid</code>.<p>This is a basic implementation that simply
* uses the <code>String</code>-based principal for <code>Sid</code> comparison. More complex principal objects may
* wish to provide an alternative <code>Sid</code> implementation that uses some other identifier.</p>
*
* @author Ben Alex
*/
public class GrantedAuthoritySid implements Sid {
//~ Instance fields ================================================================================================
private final String grantedAuthority;
private String grantedAuthority;
public GrantedAuthoritySid(String grantedAuthority) {
Assert.hasText(grantedAuthority, "GrantedAuthority required");
this.grantedAuthority = grantedAuthority;
}
//~ Constructors ===================================================================================================
public GrantedAuthoritySid(GrantedAuthority grantedAuthority) {
Assert.notNull(grantedAuthority, "GrantedAuthority required");
Assert.notNull(grantedAuthority.getAuthority(),
"This Sid is only compatible with GrantedAuthoritys that provide a non-null getAuthority()");
this.grantedAuthority = grantedAuthority.getAuthority();
}
public GrantedAuthoritySid(String grantedAuthority) {
Assert.hasText(grantedAuthority, "GrantedAuthority required");
this.grantedAuthority = grantedAuthority;
}
@Override
public boolean equals(Object object) {
if ((object == null) || !(object instanceof GrantedAuthoritySid)) {
return false;
}
// Delegate to getGrantedAuthority() to perform actual comparison (both should be
// identical)
return ((GrantedAuthoritySid) object).getGrantedAuthority().equals(this.getGrantedAuthority());
}
public GrantedAuthoritySid(GrantedAuthority grantedAuthority) {
Assert.notNull(grantedAuthority, "GrantedAuthority required");
Assert.notNull(grantedAuthority.getAuthority(),
"This Sid is only compatible with GrantedAuthoritys that provide a non-null getAuthority()");
this.grantedAuthority = grantedAuthority.getAuthority();
}
@Override
public int hashCode() {
return this.getGrantedAuthority().hashCode();
}
//~ Methods ========================================================================================================
public String getGrantedAuthority() {
return this.grantedAuthority;
}
public boolean equals(Object object) {
if ((object == null) || !(object instanceof GrantedAuthoritySid)) {
return false;
}
@Override
public String toString() {
return "GrantedAuthoritySid[" + this.grantedAuthority + "]";
}
// Delegate to getGrantedAuthority() to perform actual comparison (both should be identical)
return ((GrantedAuthoritySid) object).getGrantedAuthority().equals(this.getGrantedAuthority());
}
public int hashCode() {
return this.getGrantedAuthority().hashCode();
}
public String getGrantedAuthority() {
return grantedAuthority;
}
public String toString() {
return "GrantedAuthoritySid[" + this.grantedAuthority + "]";
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
/**
@@ -22,23 +20,25 @@ package org.springframework.security.acls.domain;
* @author Ben Alex
*/
public class IdentityUnavailableException extends RuntimeException {
//~ Constructors ===================================================================================================
/**
* Constructs an <code>IdentityUnavailableException</code> with the specified message.
* @param msg the detail message
*/
public IdentityUnavailableException(String msg) {
super(msg);
}
/**
* Constructs an <code>IdentityUnavailableException</code> with the specified message
* and root cause.
* @param msg the detail message
* @param cause root cause
*/
public IdentityUnavailableException(String msg, Throwable cause) {
super(msg, cause);
}
/**
* Constructs an <code>IdentityUnavailableException</code> with the specified message.
*
* @param msg the detail message
*/
public IdentityUnavailableException(String msg) {
super(msg);
}
/**
* Constructs an <code>IdentityUnavailableException</code> with the specified message
* and root cause.
*
* @param msg the detail message
* @param t root cause
*/
public IdentityUnavailableException(String msg, Throwable t) {
super(msg, t);
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
import java.io.Serializable;
@@ -23,128 +21,137 @@ import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Simple implementation of {@link ObjectIdentity}.
* <p>
* Uses <code>String</code>s to store the identity of the domain object instance. Also
* offers a constructor that uses reflection to build the identity information.
* Uses <code>String</code>s to store the identity of the domain object instance. Also offers a constructor that uses
* reflection to build the identity information.
*
* @author Ben Alex
*/
public class ObjectIdentityImpl implements ObjectIdentity {
//~ Instance fields ================================================================================================
private final String type;
private final String type;
private Serializable identifier;
private Serializable identifier;
//~ Constructors ===================================================================================================
public ObjectIdentityImpl(String type, Serializable identifier) {
Assert.hasText(type, "Type required");
Assert.notNull(identifier, "identifier required");
this.identifier = identifier;
this.type = type;
}
public ObjectIdentityImpl(String type, Serializable identifier) {
Assert.hasText(type, "Type required");
Assert.notNull(identifier, "identifier required");
/**
* Constructor which uses the name of the supplied class as the <tt>type</tt>
* property.
*/
public ObjectIdentityImpl(Class<?> javaType, Serializable identifier) {
Assert.notNull(javaType, "Java Type required");
Assert.notNull(identifier, "identifier required");
this.type = javaType.getName();
this.identifier = identifier;
}
this.identifier = identifier;
this.type = type;
}
/**
* Creates the <code>ObjectIdentityImpl</code> based on the passed object instance.
* The passed object must provide a <code>getId()</code> method, otherwise an
* exception will be thrown.
* <p>
* The class name of the object passed will be considered the {@link #type}, so if
* more control is required, a different constructor should be used.
* @param object the domain object instance to create an identity for.
* @throws IdentityUnavailableException if identity could not be extracted
*/
public ObjectIdentityImpl(Object object) throws IdentityUnavailableException {
Assert.notNull(object, "object cannot be null");
Class<?> typeClass = ClassUtils.getUserClass(object.getClass());
this.type = typeClass.getName();
Object result = invokeGetIdMethod(object, typeClass);
Assert.notNull(result, "getId() is required to return a non-null value");
Assert.isInstanceOf(Serializable.class, result, "Getter must provide a return value of type Serializable");
this.identifier = (Serializable) result;
}
/**
* Constructor which uses the name of the supplied class as the <tt>type</tt> property.
*/
public ObjectIdentityImpl(Class<?> javaType, Serializable identifier) {
Assert.notNull(javaType, "Java Type required");
Assert.notNull(identifier, "identifier required");
this.type = javaType.getName();
this.identifier = identifier;
}
private Object invokeGetIdMethod(Object object, Class<?> typeClass) {
try {
Method method = typeClass.getMethod("getId", new Class[] {});
return method.invoke(object);
}
catch (Exception ex) {
throw new IdentityUnavailableException("Could not extract identity from object " + object, ex);
}
}
/**
* Creates the <code>ObjectIdentityImpl</code> based on the passed
* object instance. The passed object must provide a <code>getId()</code>
* method, otherwise an exception will be thrown.
* <p>
* The class name of the object passed will be considered the {@link #type}, so if more control is required,
* a different constructor should be used.
*
* @param object the domain object instance to create an identity for.
*
* @throws IdentityUnavailableException if identity could not be extracted
*/
public ObjectIdentityImpl(Object object) throws IdentityUnavailableException {
Assert.notNull(object, "object cannot be null");
/**
* Important so caching operates properly.
* <p>
* Considers an object of the same class equal if it has the same
* <code>classname</code> and <code>id</code> properties.
* <p>
* Numeric identities (Integer and Long values) are considered equal if they are
* numerically equal. Other serializable types are evaluated using a simple equality.
* @param obj object to compare
* @return <code>true</code> if the presented object matches this object
*/
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof ObjectIdentityImpl)) {
return false;
}
ObjectIdentityImpl other = (ObjectIdentityImpl) obj;
if (this.identifier instanceof Number && other.identifier instanceof Number) {
// Integers and Longs with same value should be considered equal
if (((Number) this.identifier).longValue() != ((Number) other.identifier).longValue()) {
return false;
}
}
else {
// Use plain equality for other serializable types
if (!this.identifier.equals(other.identifier)) {
return false;
}
}
return this.type.equals(other.type);
}
Class<?> typeClass = ClassUtils.getUserClass(object.getClass());
type = typeClass.getName();
@Override
public Serializable getIdentifier() {
return this.identifier;
}
Object result;
@Override
public String getType() {
return this.type;
}
try {
Method method = typeClass.getMethod("getId", new Class[] {});
result = method.invoke(object, new Object[] {});
} catch (Exception e) {
throw new IdentityUnavailableException("Could not extract identity from object " + object, e);
}
/**
* Important so caching operates properly.
* @return the hash
*/
@Override
public int hashCode() {
int result = this.type.hashCode();
result = 31 * result + this.identifier.hashCode();
return result;
}
Assert.notNull(result, "getId() is required to return a non-null value");
Assert.isInstanceOf(Serializable.class, result, "Getter must provide a return value of type Serializable");
this.identifier = (Serializable) result;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getName()).append("[");
sb.append("Type: ").append(this.type);
sb.append("; Identifier: ").append(this.identifier).append("]");
return sb.toString();
}
//~ Methods ========================================================================================================
/**
* Important so caching operates properly.
* <p>
* Considers an object of the same class equal if it has the same <code>classname</code> and
* <code>id</code> properties.
* <p>
* Numeric identities (Integer and Long values) are considered equal if they are numerically equal. Other
* serializable types are evaluated using a simple equality.
*
* @param arg0 object to compare
*
* @return <code>true</code> if the presented object matches this object
*/
public boolean equals(Object arg0) {
if (arg0 == null || !(arg0 instanceof ObjectIdentityImpl)) {
return false;
}
ObjectIdentityImpl other = (ObjectIdentityImpl) arg0;
if (identifier instanceof Number && other.identifier instanceof Number) {
// Integers and Longs with same value should be considered equal
if (((Number)identifier).longValue() != ((Number)other.identifier).longValue()) {
return false;
}
} else {
// Use plain equality for other serializable types
if (!identifier.equals(other.identifier)) {
return false;
}
}
return type.equals(other.type);
}
public Serializable getIdentifier() {
return identifier;
}
public String getType() {
return type;
}
/**
* Important so caching operates properly.
*
* @return the hash
*/
public int hashCode() {
int code = 31;
code ^= this.type.hashCode();
code ^= this.identifier.hashCode();
return code;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getName()).append("[");
sb.append("Type: ").append(this.type);
sb.append("; Identifier: ").append(this.identifier).append("]");
return sb.toString();
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -23,22 +22,19 @@ import org.springframework.security.acls.model.ObjectIdentityGenerator;
import org.springframework.security.acls.model.ObjectIdentityRetrievalStrategy;
/**
* Basic implementation of {@link ObjectIdentityRetrievalStrategy} and
* <tt>ObjectIdentityGenerator</tt> that uses the constructors of
* {@link ObjectIdentityImpl} to create the {@link ObjectIdentity}.
* Basic implementation of {@link ObjectIdentityRetrievalStrategy} and <tt>ObjectIdentityGenerator</tt>
* that uses the constructors of {@link ObjectIdentityImpl} to create the {@link ObjectIdentity}.
*
* @author Ben Alex
*/
public class ObjectIdentityRetrievalStrategyImpl implements ObjectIdentityRetrievalStrategy, ObjectIdentityGenerator {
//~ Methods ========================================================================================================
@Override
public ObjectIdentity getObjectIdentity(Object domainObject) {
return new ObjectIdentityImpl(domainObject);
}
@Override
public ObjectIdentity createObjectIdentity(Serializable id, String type) {
return new ObjectIdentityImpl(type, id);
}
public ObjectIdentity getObjectIdentity(Object domainObject) {
return new ObjectIdentityImpl(domainObject);
}
public ObjectIdentity createObjectIdentity(Serializable id, String type) {
return new ObjectIdentityImpl(type, id);
}
}
@@ -1,19 +1,3 @@
/*
* Copyright 2002-2016 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
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
import java.util.List;
@@ -21,24 +5,27 @@ import java.util.List;
import org.springframework.security.acls.model.Permission;
/**
* Provides a simple mechanism to retrieve {@link Permission} instances from integer
* masks.
* Provides a simple mechanism to retrieve {@link Permission} instances from integer masks.
*
* @author Ben Alex
* @since 2.0.3
*
*/
public interface PermissionFactory {
/**
* Dynamically creates a <code>CumulativePermission</code> or
* <code>BasePermission</code> representing the active bits in the passed mask.
* @param mask to build
* @return a Permission representing the requested object
*/
Permission buildFromMask(int mask);
/**
* Dynamically creates a <code>CumulativePermission</code> or <code>BasePermission</code> representing the
* active bits in the passed mask.
*
* @param mask to build
*
* @return a Permission representing the requested object
*/
Permission buildFromMask(int mask);
Permission buildFromName(String name);
List<Permission> buildFromNames(List<String> names);
Permission buildFromName(String name);
List<Permission> buildFromNames(List<String> names);
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,60 +12,66 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
import org.springframework.security.acls.model.Sid;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.Assert;
/**
* Represents an <code>Authentication.getPrincipal()</code> as a <code>Sid</code>.
* <p>
* This is a basic implementation that simply uses the <code>String</code>-based principal
* for <code>Sid</code> comparison. More complex principal objects may wish to provide an
* alternative <code>Sid</code> implementation that uses some other identifier.
* </p>
* Represents an <code>Authentication.getPrincipal()</code> as a <code>Sid</code>.<p>This is a basic implementation
* that simply uses the <code>String</code>-based principal for <code>Sid</code> comparison. More complex principal
* objects may wish to provide an alternative <code>Sid</code> implementation that uses some other identifier.</p>
*
* @author Ben Alex
*/
public class PrincipalSid implements Sid {
//~ Instance fields ================================================================================================
private final String principal;
private String principal;
public PrincipalSid(String principal) {
Assert.hasText(principal, "Principal required");
this.principal = principal;
}
//~ Constructors ===================================================================================================
public PrincipalSid(Authentication authentication) {
Assert.notNull(authentication, "Authentication required");
Assert.notNull(authentication.getPrincipal(), "Principal required");
this.principal = authentication.getName();
}
public PrincipalSid(String principal) {
Assert.hasText(principal, "Principal required");
this.principal = principal;
}
@Override
public boolean equals(Object object) {
if ((object == null) || !(object instanceof PrincipalSid)) {
return false;
}
// Delegate to getPrincipal() to perform actual comparison (both should be
// identical)
return ((PrincipalSid) object).getPrincipal().equals(this.getPrincipal());
}
public PrincipalSid(Authentication authentication) {
Assert.notNull(authentication, "Authentication required");
Assert.notNull(authentication.getPrincipal(), "Principal required");
@Override
public int hashCode() {
return this.getPrincipal().hashCode();
}
if (authentication.getPrincipal() instanceof UserDetails) {
this.principal = ((UserDetails) authentication.getPrincipal()).getUsername();
} else {
this.principal = authentication.getPrincipal().toString();
}
}
public String getPrincipal() {
return this.principal;
}
//~ Methods ========================================================================================================
@Override
public String toString() {
return "PrincipalSid[" + this.principal + "]";
}
public boolean equals(Object object) {
if ((object == null) || !(object instanceof PrincipalSid)) {
return false;
}
// Delegate to getPrincipal() to perform actual comparison (both should be identical)
return ((PrincipalSid) object).getPrincipal().equals(this.getPrincipal());
}
public int hashCode() {
return this.getPrincipal().hashCode();
}
public String getPrincipal() {
return principal;
}
public String toString() {
return "PrincipalSid[" + this.principal + "]";
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -29,38 +28,38 @@ import org.springframework.security.core.GrantedAuthority;
import org.springframework.util.Assert;
/**
* Basic implementation of {@link SidRetrievalStrategy} that creates a {@link Sid} for the
* principal, as well as every granted authority the principal holds. Can optionally have
* a <tt>RoleHierarchy</tt> injected in order to determine the extended list of
* authorities that the principal is assigned.
* Basic implementation of {@link SidRetrievalStrategy} that creates a {@link Sid} for the principal, as well as
* every granted authority the principal holds. Can optionally have a <tt>RoleHierarchy</tt> injected in order to
* determine the extended list of authorities that the principal is assigned.
* <p>
* The returned array will always contain the {@link PrincipalSid} before any
* {@link GrantedAuthoritySid} elements.
* The returned array will always contain the {@link PrincipalSid} before any {@link GrantedAuthoritySid} elements.
*
* @author Ben Alex
*/
public class SidRetrievalStrategyImpl implements SidRetrievalStrategy {
private RoleHierarchy roleHierarchy = new NullRoleHierarchy();
private RoleHierarchy roleHierarchy = new NullRoleHierarchy();
public SidRetrievalStrategyImpl() {
}
public SidRetrievalStrategyImpl() {
}
public SidRetrievalStrategyImpl(RoleHierarchy roleHierarchy) {
Assert.notNull(roleHierarchy, "RoleHierarchy must not be null");
this.roleHierarchy = roleHierarchy;
}
public SidRetrievalStrategyImpl(RoleHierarchy roleHierarchy) {
Assert.notNull(roleHierarchy, "RoleHierarchy must not be null");
this.roleHierarchy = roleHierarchy;
}
@Override
public List<Sid> getSids(Authentication authentication) {
Collection<? extends GrantedAuthority> authorities = this.roleHierarchy
.getReachableGrantedAuthorities(authentication.getAuthorities());
List<Sid> sids = new ArrayList<>(authorities.size() + 1);
sids.add(new PrincipalSid(authentication));
for (GrantedAuthority authority : authorities) {
sids.add(new GrantedAuthoritySid(authority));
}
return sids;
}
//~ Methods ========================================================================================================
public List<Sid> getSids(Authentication authentication) {
Collection<GrantedAuthority> authorities = roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
List<Sid> sids = new ArrayList<Sid>(authorities.size() + 1);
sids.add(new PrincipalSid(authentication));
for (GrantedAuthority authority : authorities) {
sids.add(new GrantedAuthoritySid(authority));
}
return sids;
}
}
@@ -1,128 +0,0 @@
/*
* Copyright 2002-2013 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
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.domain;
import java.io.Serializable;
import org.springframework.cache.Cache;
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 org.springframework.security.acls.model.AclCache} that
* delegates to {@link Cache} implementation.
* <p>
* Designed to handle the transient fields in
* {@link org.springframework.security.acls.domain.AclImpl}. Note that this implementation
* assumes all {@link org.springframework.security.acls.domain.AclImpl} instances share
* the same {@link org.springframework.security.acls.model.PermissionGrantingStrategy} and
* {@link org.springframework.security.acls.domain.AclAuthorizationStrategy} instances.
*
* @author Marten Deinum
* @since 3.2
*/
public class SpringCacheBasedAclCache implements AclCache {
private final Cache cache;
private PermissionGrantingStrategy permissionGrantingStrategy;
private AclAuthorizationStrategy aclAuthorizationStrategy;
public SpringCacheBasedAclCache(Cache 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;
}
@Override
public void evictFromCache(Serializable pk) {
Assert.notNull(pk, "Primary key (identifier) required");
MutableAcl acl = getFromCache(pk);
if (acl != null) {
this.cache.evict(acl.getId());
this.cache.evict(acl.getObjectIdentity());
}
}
@Override
public void evictFromCache(ObjectIdentity objectIdentity) {
Assert.notNull(objectIdentity, "ObjectIdentity required");
MutableAcl acl = getFromCache(objectIdentity);
if (acl != null) {
this.cache.evict(acl.getId());
this.cache.evict(acl.getObjectIdentity());
}
}
@Override
public MutableAcl getFromCache(ObjectIdentity objectIdentity) {
Assert.notNull(objectIdentity, "ObjectIdentity required");
return getFromCache((Object) objectIdentity);
}
@Override
public MutableAcl getFromCache(Serializable pk) {
Assert.notNull(pk, "Primary key (identifier) required");
return getFromCache((Object) pk);
}
@Override
public void putInCache(MutableAcl acl) {
Assert.notNull(acl, "Acl required");
Assert.notNull(acl.getObjectIdentity(), "ObjectIdentity required");
Assert.notNull(acl.getId(), "ID required");
if ((acl.getParentAcl() != null) && (acl.getParentAcl() instanceof MutableAcl)) {
putInCache((MutableAcl) acl.getParentAcl());
}
this.cache.put(acl.getObjectIdentity(), acl);
this.cache.put(acl.getId(), acl);
}
private MutableAcl getFromCache(Object key) {
Cache.ValueWrapper element = this.cache.get(key);
if (element == null) {
return null;
}
return initializeTransientFields((MutableAcl) element.get());
}
private MutableAcl initializeTransientFields(MutableAcl value) {
if (value instanceof AclImpl) {
FieldUtils.setProtectedFieldValue("aclAuthorizationStrategy", value, this.aclAuthorizationStrategy);
FieldUtils.setProtectedFieldValue("permissionGrantingStrategy", value, this.permissionGrantingStrategy);
}
if (value.getParentAcl() != null) {
initializeTransientFields((MutableAcl) value.getParentAcl());
}
return value;
}
@Override
public void clearCache() {
this.cache.clear();
}
}
@@ -1,20 +1,5 @@
/*
* Copyright 2002-2016 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
*
* https://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.
*/
/**
* Basic implementation of access control lists (ACLs) interfaces.
*/
package org.springframework.security.acls.domain;
@@ -1,168 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.jdbc;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.UUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.util.Assert;
/**
* Utility class for helping convert database representations of
* {@link ObjectIdentity#getIdentifier()} into the correct Java type as specified by
* <code>acl_class.class_id_type</code>.
*
* @author paulwheeler
*/
class AclClassIdUtils {
private static final String DEFAULT_CLASS_ID_TYPE_COLUMN_NAME = "class_id_type";
private static final Log log = LogFactory.getLog(AclClassIdUtils.class);
private ConversionService conversionService;
AclClassIdUtils() {
GenericConversionService genericConversionService = new GenericConversionService();
genericConversionService.addConverter(String.class, Long.class, new StringToLongConverter());
genericConversionService.addConverter(String.class, UUID.class, new StringToUUIDConverter());
this.conversionService = genericConversionService;
}
AclClassIdUtils(ConversionService conversionService) {
Assert.notNull(conversionService, "conversionService must not be null");
this.conversionService = conversionService;
}
/**
* Converts the raw type from the database into the right Java type. For most
* applications the 'raw type' will be Long, for some applications it could be String.
* @param identifier The identifier from the database
* @param resultSet Result set of the query
* @return The identifier in the appropriate target Java type. Typically Long or UUID.
* @throws SQLException
*/
Serializable identifierFrom(Serializable identifier, ResultSet resultSet) throws SQLException {
if (isString(identifier) && hasValidClassIdType(resultSet)
&& canConvertFromStringTo(classIdTypeFrom(resultSet))) {
return convertFromStringTo((String) identifier, classIdTypeFrom(resultSet));
}
// Assume it should be a Long type
return convertToLong(identifier);
}
private boolean hasValidClassIdType(ResultSet resultSet) {
try {
return classIdTypeFrom(resultSet) != null;
}
catch (SQLException ex) {
log.debug("Unable to obtain the class id type", ex);
return false;
}
}
private <T extends Serializable> Class<T> classIdTypeFrom(ResultSet resultSet) throws SQLException {
return classIdTypeFrom(resultSet.getString(DEFAULT_CLASS_ID_TYPE_COLUMN_NAME));
}
private <T extends Serializable> Class<T> classIdTypeFrom(String className) {
if (className == null) {
return null;
}
try {
return (Class) Class.forName(className);
}
catch (ClassNotFoundException ex) {
log.debug("Unable to find class id type on classpath", ex);
return null;
}
}
private <T> boolean canConvertFromStringTo(Class<T> targetType) {
return this.conversionService.canConvert(String.class, targetType);
}
private <T extends Serializable> T convertFromStringTo(String identifier, Class<T> targetType) {
return this.conversionService.convert(identifier, targetType);
}
/**
* Converts to a {@link Long}, attempting to use the {@link ConversionService} if
* available.
* @param identifier The identifier
* @return Long version of the identifier
* @throws NumberFormatException if the string cannot be parsed to a long.
* @throws org.springframework.core.convert.ConversionException if a conversion
* exception occurred
* @throws IllegalArgumentException if targetType is null
*/
private Long convertToLong(Serializable identifier) {
if (this.conversionService.canConvert(identifier.getClass(), Long.class)) {
return this.conversionService.convert(identifier, Long.class);
}
return Long.valueOf(identifier.toString());
}
private boolean isString(Serializable object) {
return object.getClass().isAssignableFrom(String.class);
}
void setConversionService(ConversionService conversionService) {
Assert.notNull(conversionService, "conversionService must not be null");
this.conversionService = conversionService;
}
private static class StringToLongConverter implements Converter<String, Long> {
@Override
public Long convert(String identifierAsString) {
if (identifierAsString == null) {
throw new ConversionFailedException(TypeDescriptor.valueOf(String.class),
TypeDescriptor.valueOf(Long.class), null, null);
}
return Long.parseLong(identifierAsString);
}
}
private static class StringToUUIDConverter implements Converter<String, UUID> {
@Override
public UUID convert(String identifierAsString) {
if (identifierAsString == null) {
throw new ConversionFailedException(TypeDescriptor.valueOf(String.class),
TypeDescriptor.valueOf(UUID.class), null, null);
}
return UUID.fromString(identifierAsString);
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006, 2017, 2018 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,13 +12,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.jdbc;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -27,10 +24,8 @@ import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.AclService;
@@ -39,134 +34,97 @@ import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.Sid;
import org.springframework.util.Assert;
/**
* Simple JDBC-based implementation of <code>AclService</code>.
* <p>
* Requires the "dirty" flags in {@link org.springframework.security.acls.domain.AclImpl}
* and {@link org.springframework.security.acls.domain.AccessControlEntryImpl} to be set,
* so that the implementation can detect changed parameters easily.
* Requires the "dirty" flags in {@link org.springframework.security.acls.domain.AclImpl} and
* {@link org.springframework.security.acls.domain.AccessControlEntryImpl} to be set, so that the implementation can
* detect changed parameters easily.
*
* @author Ben Alex
*/
public class JdbcAclService implements AclService {
//~ Static fields/initializers =====================================================================================
protected static final Log log = LogFactory.getLog(JdbcAclService.class);
protected static final Log log = LogFactory.getLog(JdbcAclService.class);
private static final String DEFAULT_SELECT_ACL_WITH_PARENT_SQL = "select obj.object_id_identity as obj_id, class.class as class "
+ "from acl_object_identity obj, acl_object_identity parent, acl_class class "
+ "where obj.parent_object = parent.id and obj.object_id_class = class.id "
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
+ "select id FROM acl_class where acl_class.class = ?)";
private static final String DEFAULT_SELECT_ACL_CLASS_COLUMNS = "class.class as class";
//~ Instance fields ================================================================================================
private static final String DEFAULT_SELECT_ACL_CLASS_COLUMNS_WITH_ID_TYPE = DEFAULT_SELECT_ACL_CLASS_COLUMNS
+ ", class.class_id_type as class_id_type";
protected JdbcTemplate jdbcTemplate;
private LookupStrategy lookupStrategy;
private String findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL;
private static final String DEFAULT_SELECT_ACL_WITH_PARENT_SQL = "select obj.object_id_identity as obj_id, "
+ DEFAULT_SELECT_ACL_CLASS_COLUMNS
+ " from acl_object_identity obj, acl_object_identity parent, acl_class class "
+ "where obj.parent_object = parent.id and obj.object_id_class = class.id "
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
+ "select id FROM acl_class where acl_class.class = ?)";
//~ Constructors ===================================================================================================
private static final String DEFAULT_SELECT_ACL_WITH_PARENT_SQL_WITH_CLASS_ID_TYPE = "select obj.object_id_identity as obj_id, "
+ DEFAULT_SELECT_ACL_CLASS_COLUMNS_WITH_ID_TYPE
+ " from acl_object_identity obj, acl_object_identity parent, acl_class class "
+ "where obj.parent_object = parent.id and obj.object_id_class = class.id "
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
+ "select id FROM acl_class where acl_class.class = ?)";
public JdbcAclService(DataSource dataSource, LookupStrategy lookupStrategy) {
Assert.notNull(dataSource, "DataSource required");
Assert.notNull(lookupStrategy, "LookupStrategy required");
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.lookupStrategy = lookupStrategy;
}
protected final JdbcOperations jdbcOperations;
//~ Methods ========================================================================================================
private final LookupStrategy lookupStrategy;
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
Object[] args = {parentIdentity.getIdentifier(), parentIdentity.getType()};
List<ObjectIdentity> objects = jdbcTemplate.query(findChildrenSql, args,
new RowMapper<ObjectIdentity>() {
public ObjectIdentity mapRow(ResultSet rs, int rowNum) throws SQLException {
String javaType = rs.getString("class");
Long identifier = new Long(rs.getLong("obj_id"));
private boolean aclClassIdSupported;
return new ObjectIdentityImpl(javaType, identifier);
}
});
private String findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL;
if (objects.size() == 0) {
return null;
}
private AclClassIdUtils aclClassIdUtils;
return objects;
}
public JdbcAclService(DataSource dataSource, LookupStrategy lookupStrategy) {
this(new JdbcTemplate(dataSource), lookupStrategy);
}
public Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException {
Map<ObjectIdentity, Acl> map = readAclsById(Arrays.asList(object), sids);
Assert.isTrue(map.containsKey(object), "There should have been an Acl entry for ObjectIdentity " + object);
public JdbcAclService(JdbcOperations jdbcOperations, LookupStrategy lookupStrategy) {
Assert.notNull(jdbcOperations, "JdbcOperations required");
Assert.notNull(lookupStrategy, "LookupStrategy required");
this.jdbcOperations = jdbcOperations;
this.lookupStrategy = lookupStrategy;
this.aclClassIdUtils = new AclClassIdUtils();
}
return (Acl) map.get(object);
}
@Override
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) {
Object[] args = { parentIdentity.getIdentifier().toString(), parentIdentity.getType() };
List<ObjectIdentity> objects = this.jdbcOperations.query(this.findChildrenSql, args,
(rs, rowNum) -> mapObjectIdentityRow(rs));
return (!objects.isEmpty()) ? objects : null;
}
public Acl readAclById(ObjectIdentity object) throws NotFoundException {
return readAclById(object, null);
}
private ObjectIdentity mapObjectIdentityRow(ResultSet rs) throws SQLException {
String javaType = rs.getString("class");
Serializable identifier = (Serializable) rs.getObject("obj_id");
identifier = this.aclClassIdUtils.identifierFrom(identifier, rs);
return new ObjectIdentityImpl(javaType, identifier);
}
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects) throws NotFoundException {
return readAclsById(objects, null);
}
@Override
public Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException {
Map<ObjectIdentity, Acl> map = readAclsById(Collections.singletonList(object), sids);
Assert.isTrue(map.containsKey(object),
() -> "There should have been an Acl entry for ObjectIdentity " + object);
return map.get(object);
}
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) throws NotFoundException {
Map<ObjectIdentity, Acl> result = lookupStrategy.readAclsById(objects, sids);
@Override
public Acl readAclById(ObjectIdentity object) throws NotFoundException {
return readAclById(object, null);
}
// Check every requested object identity was found (throw NotFoundException if needed)
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) + "'");
}
}
@Override
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects) throws NotFoundException {
return readAclsById(objects, null);
}
@Override
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids)
throws NotFoundException {
Map<ObjectIdentity, Acl> result = this.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 + "'");
}
}
return result;
}
/**
* Allows customization of the SQL query used to find child object identities.
* @param findChildrenSql
*/
public void setFindChildrenQuery(String findChildrenSql) {
this.findChildrenSql = findChildrenSql;
}
public void setAclClassIdSupported(boolean aclClassIdSupported) {
this.aclClassIdSupported = aclClassIdSupported;
if (aclClassIdSupported) {
// Change the default children select if it hasn't been overridden
if (this.findChildrenSql.equals(DEFAULT_SELECT_ACL_WITH_PARENT_SQL)) {
this.findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL_WITH_CLASS_ID_TYPE;
}
else {
log.debug("Find children statement has already been overridden, so not overridding the default");
}
}
}
public void setConversionService(ConversionService conversionService) {
this.aclClassIdUtils = new AclClassIdUtils(conversionService);
}
protected boolean isAclClassIdSupported() {
return this.aclClassIdSupported;
}
return result;
}
/**
* Allows customization of the SQL query used to find child object identities.
*
* @param findChildrenSql
*/
public void setFindChildrenQuery(String findChildrenSql) {
this.findChildrenSql = findChildrenSql;
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006, 2017, 2018 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.jdbc;
import java.sql.PreparedStatement;
@@ -43,434 +41,395 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
/**
* Provides a base JDBC implementation of {@link MutableAclService}.
* <p>
* The default settings are for HSQLDB. If you are using a different database you will
* probably need to set the {@link #setSidIdentityQuery(String) sidIdentityQuery} and
* {@link #setClassIdentityQuery(String) classIdentityQuery} properties appropriately. The
* other queries, SQL inserts and updates can also be customized to accomodate schema
* variations, but must produce results consistent with those expected by the defaults.
* The default settings are for HSQLDB. If you are using a different database you
* will probably need to set the {@link #setSidIdentityQuery(String) sidIdentityQuery} and
* {@link #setClassIdentityQuery(String) classIdentityQuery} properties appropriately. The other queries,
* SQL inserts and updates can also be customized to accomodate schema variations, but must produce results
* consistent with those expected by the defaults.
* <p>
* See the appendix of the Spring Security reference manual for more information on the
* expected schema and how it is used. Information on using PostgreSQL is also included.
* See the appendix of the Spring Security reference manual for more information on the expected schema
* and how it is used. Information on using PostgreSQL is also included.
*
* @author Ben Alex
* @author Johannes Zlattinger
*/
public class JdbcMutableAclService extends JdbcAclService implements MutableAclService {
private static final String DEFAULT_INSERT_INTO_ACL_CLASS = "insert into acl_class (class) values (?)";
private static final String DEFAULT_INSERT_INTO_ACL_CLASS_WITH_ID = "insert into acl_class (class, class_id_type) values (?, ?)";
private boolean foreignKeysInDatabase = true;
private final 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()";
private String sidIdentityQuery = "call identity()";
private String insertClass = DEFAULT_INSERT_INTO_ACL_CLASS;
private String insertEntry = "insert into acl_entry "
+ "(acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure)"
+ "values (?, ?, ?, ?, ?, ?, ?)";
private String insertObjectIdentity = "insert into acl_object_identity "
+ "(object_id_class, object_id_identity, owner_sid, entries_inheriting) " + "values (?, ?, ?, ?)";
private String insertSid = "insert into acl_sid (principal, sid) values (?, ?)";
private String selectClassPrimaryKey = "select id from acl_class where class=?";
private String selectObjectIdentityPrimaryKey = "select acl_object_identity.id from acl_object_identity, acl_class "
+ "where acl_object_identity.object_id_class = acl_class.id and acl_class.class=? "
+ "and acl_object_identity.object_id_identity = ?";
private String selectSidPrimaryKey = "select id from acl_sid where principal=? and sid=?";
private String updateObjectIdentity = "update acl_object_identity set "
+ "parent_object = ?, owner_sid = ?, entries_inheriting = ?" + " where id = ?";
public JdbcMutableAclService(DataSource dataSource, LookupStrategy lookupStrategy, AclCache aclCache) {
super(dataSource, lookupStrategy);
Assert.notNull(aclCache, "AclCache required");
this.aclCache = aclCache;
}
@Override
public MutableAcl createAcl(ObjectIdentity objectIdentity) throws AlreadyExistsException {
Assert.notNull(objectIdentity, "Object Identity required");
// Check this object identity hasn't already been persisted
if (retrieveObjectIdentityPrimaryKey(objectIdentity) != null) {
throw new AlreadyExistsException("Object identity '" + objectIdentity + "' already exists");
}
// Need to retrieve the current principal, in order to know who "owns" this ACL
// (can be changed later on)
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
PrincipalSid sid = new PrincipalSid(auth);
// Create the acl_object_identity row
createObjectIdentity(objectIdentity, sid);
// Retrieve the ACL via superclass (ensures cache registration, proper retrieval
// etc)
Acl acl = readAclById(objectIdentity);
Assert.isInstanceOf(MutableAcl.class, acl, "MutableAcl should be been returned");
return (MutableAcl) acl;
}
/**
* Creates a new row in acl_entry for every ACE defined in the passed MutableAcl
* object.
* @param acl containing the ACEs to insert
*/
protected void createEntries(final MutableAcl acl) {
if (acl.getEntries().isEmpty()) {
return;
}
this.jdbcOperations.batchUpdate(this.insertEntry, new BatchPreparedStatementSetter() {
@Override
public int getBatchSize() {
return acl.getEntries().size();
}
@Override
public void setValues(PreparedStatement stmt, int i) throws SQLException {
AccessControlEntry entry_ = acl.getEntries().get(i);
Assert.isTrue(entry_ instanceof AccessControlEntryImpl, "Unknown ACE class");
AccessControlEntryImpl entry = (AccessControlEntryImpl) entry_;
stmt.setLong(1, (Long) acl.getId());
stmt.setInt(2, i);
stmt.setLong(3, createOrRetrieveSidPrimaryKey(entry.getSid(), true));
stmt.setInt(4, entry.getPermission().getMask());
stmt.setBoolean(5, entry.isGranting());
stmt.setBoolean(6, entry.isAuditSuccess());
stmt.setBoolean(7, entry.isAuditFailure());
}
});
}
/**
* Creates an entry in the acl_object_identity table for the passed ObjectIdentity.
* The Sid is also necessary, as acl_object_identity has defined the sid column as
* non-null.
* @param object to represent an acl_object_identity for
* @param owner for the SID column (will be created if there is no acl_sid entry for
* this particular Sid already)
*/
protected void createObjectIdentity(ObjectIdentity object, Sid owner) {
Long sidId = createOrRetrieveSidPrimaryKey(owner, true);
Long classId = createOrRetrieveClassPrimaryKey(object.getType(), true, object.getIdentifier().getClass());
this.jdbcOperations.update(this.insertObjectIdentity, classId, object.getIdentifier().toString(), sidId,
Boolean.TRUE);
}
/**
* Retrieves the primary key from {@code acl_class}, creating a new row if needed and
* the {@code allowCreate} property is {@code true}.
* @param type to find or create an entry for (often the fully-qualified class name)
* @param allowCreate true if creation is permitted if not found
* @return the primary key or null if not found
*/
protected Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate, Class idType) {
List<Long> classIds = this.jdbcOperations.queryForList(this.selectClassPrimaryKey, new Object[] { type },
Long.class);
if (!classIds.isEmpty()) {
return classIds.get(0);
}
if (allowCreate) {
if (!isAclClassIdSupported()) {
this.jdbcOperations.update(this.insertClass, type);
}
else {
this.jdbcOperations.update(this.insertClass, type, idType.getCanonicalName());
}
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
return this.jdbcOperations.queryForObject(this.classIdentityQuery, Long.class);
}
return null;
}
/**
* Retrieves the primary key from acl_sid, creating a new row if needed and the
* allowCreate property is true.
* @param sid to find or create
* @param allowCreate true if creation is permitted if not found
* @return the primary key or null if not found
* @throws IllegalArgumentException if the <tt>Sid</tt> is not a recognized
* implementation.
*/
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
Assert.notNull(sid, "Sid required");
if (sid instanceof PrincipalSid) {
String sidName = ((PrincipalSid) sid).getPrincipal();
return createOrRetrieveSidPrimaryKey(sidName, true, allowCreate);
}
if (sid instanceof GrantedAuthoritySid) {
String sidName = ((GrantedAuthoritySid) sid).getGrantedAuthority();
return createOrRetrieveSidPrimaryKey(sidName, false, allowCreate);
}
throw new IllegalArgumentException("Unsupported implementation of Sid");
}
/**
* Retrieves the primary key from acl_sid, creating a new row if needed and the
* allowCreate property is true.
* @param sidName name of Sid to find or to create
* @param sidIsPrincipal whether it's a user or granted authority like role
* @param allowCreate true if creation is permitted if not found
* @return the primary key or null if not found
*/
protected Long createOrRetrieveSidPrimaryKey(String sidName, boolean sidIsPrincipal, boolean allowCreate) {
List<Long> sidIds = this.jdbcOperations.queryForList(this.selectSidPrimaryKey,
new Object[] { sidIsPrincipal, sidName }, Long.class);
if (!sidIds.isEmpty()) {
return sidIds.get(0);
}
if (allowCreate) {
this.jdbcOperations.update(this.insertSid, sidIsPrincipal, sidName);
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
return this.jdbcOperations.queryForObject(this.sidIdentityQuery, Long.class);
}
return null;
}
@Override
public void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren) throws ChildrenExistException {
Assert.notNull(objectIdentity, "Object Identity required");
Assert.notNull(objectIdentity.getIdentifier(), "Object Identity doesn't provide an identifier");
if (deleteChildren) {
List<ObjectIdentity> children = findChildren(objectIdentity);
if (children != null) {
for (ObjectIdentity child : children) {
deleteAcl(child, true);
}
}
}
else {
if (!this.foreignKeysInDatabase) {
// We need to perform a manual verification for what a FK would normally
// do. We generally don't do this, in the interests of deadlock management
List<ObjectIdentity> children = findChildren(objectIdentity);
if (children != null) {
throw new ChildrenExistException(
"Cannot delete '" + objectIdentity + "' (has " + children.size() + " children)");
}
}
}
Long oidPrimaryKey = retrieveObjectIdentityPrimaryKey(objectIdentity);
// Delete this ACL's ACEs in the acl_entry table
deleteEntries(oidPrimaryKey);
// Delete this ACL's acl_object_identity row
deleteObjectIdentity(oidPrimaryKey);
// Clear the cache
this.aclCache.evictFromCache(objectIdentity);
}
/**
* Deletes all ACEs defined in the acl_entry table belonging to the presented
* ObjectIdentity primary key.
* @param oidPrimaryKey the rows in acl_entry to delete
*/
protected void deleteEntries(Long oidPrimaryKey) {
this.jdbcOperations.update(this.deleteEntryByObjectIdentityForeignKey, oidPrimaryKey);
}
/**
* Deletes a single row from acl_object_identity that is associated with the presented
* ObjectIdentity primary key.
* <p>
* We do not delete any entries from acl_class, even if no classes are using that
* class any longer. This is a deadlock avoidance approach.
* @param oidPrimaryKey to delete the acl_object_identity
*/
protected void deleteObjectIdentity(Long oidPrimaryKey) {
// Delete the acl_object_identity row
this.jdbcOperations.update(this.deleteObjectIdentityByPrimaryKey, oidPrimaryKey);
}
/**
* Retrieves the primary key from the acl_object_identity table for the passed
* ObjectIdentity. Unlike some other methods in this implementation, this method will
* NOT create a row (use {@link #createObjectIdentity(ObjectIdentity, Sid)} instead).
* @param oid to find
* @return the object identity or null if not found
*/
protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
try {
return this.jdbcOperations.queryForObject(this.selectObjectIdentityPrimaryKey, Long.class, oid.getType(),
oid.getIdentifier().toString());
}
catch (DataAccessException notFound) {
return null;
}
}
/**
* This implementation will simply delete all ACEs in the database and recreate them
* on each invocation of this method. A more comprehensive implementation might use
* dirty state checking, or more likely use ORM capabilities for create, update and
* delete operations of {@link MutableAcl}.
*/
@Override
public MutableAcl updateAcl(MutableAcl acl) throws NotFoundException {
Assert.notNull(acl.getId(), "Object Identity doesn't provide an identifier");
// Delete this ACL's ACEs in the acl_entry table
deleteEntries(retrieveObjectIdentityPrimaryKey(acl.getObjectIdentity()));
// Create this ACL's ACEs in the acl_entry table
createEntries(acl);
// Change the mutable columns in acl_object_identity
updateObjectIdentity(acl);
// Clear the cache, including children
clearCacheIncludingChildren(acl.getObjectIdentity());
// Retrieve the ACL via superclass (ensures cache registration, proper retrieval
// etc)
return (MutableAcl) super.readAclById(acl.getObjectIdentity());
}
private void clearCacheIncludingChildren(ObjectIdentity objectIdentity) {
Assert.notNull(objectIdentity, "ObjectIdentity required");
List<ObjectIdentity> children = findChildren(objectIdentity);
if (children != null) {
for (ObjectIdentity child : children) {
clearCacheIncludingChildren(child);
}
}
this.aclCache.evictFromCache(objectIdentity);
}
/**
* Updates an existing acl_object_identity row, with new information presented in the
* passed MutableAcl object. Also will create an acl_sid entry if needed for the Sid
* that owns the MutableAcl.
* @param acl to modify (a row must already exist in acl_object_identity)
* @throws NotFoundException if the ACL could not be found to update.
*/
protected void updateObjectIdentity(MutableAcl acl) {
Long parentId = null;
if (acl.getParentAcl() != null) {
Assert.isInstanceOf(ObjectIdentityImpl.class, acl.getParentAcl().getObjectIdentity(),
"Implementation only supports ObjectIdentityImpl");
ObjectIdentityImpl oii = (ObjectIdentityImpl) acl.getParentAcl().getObjectIdentity();
parentId = retrieveObjectIdentityPrimaryKey(oii);
}
Assert.notNull(acl.getOwner(), "Owner is required in this implementation");
Long ownerSid = createOrRetrieveSidPrimaryKey(acl.getOwner(), true);
int count = this.jdbcOperations.update(this.updateObjectIdentity, parentId, ownerSid, acl.isEntriesInheriting(),
acl.getId());
if (count != 1) {
throw new NotFoundException("Unable to locate ACL to update");
}
}
/**
* Sets the query that will be used to retrieve the identity of a newly created row in
* the <tt>acl_class</tt> table.
* @param classIdentityQuery the query, which should return the identifier. Defaults
* to <tt>call identity()</tt>
*/
public void setClassIdentityQuery(String classIdentityQuery) {
Assert.hasText(classIdentityQuery, "New classIdentityQuery query is required");
this.classIdentityQuery = classIdentityQuery;
}
/**
* Sets the query that will be used to retrieve the identity of a newly created row in
* the <tt>acl_sid</tt> table.
* @param sidIdentityQuery the query, which should return the identifier. Defaults to
* <tt>call identity()</tt>
*/
public void setSidIdentityQuery(String sidIdentityQuery) {
Assert.hasText(sidIdentityQuery, "New sidIdentityQuery query is required");
this.sidIdentityQuery = sidIdentityQuery;
}
public void setDeleteEntryByObjectIdentityForeignKeySql(String deleteEntryByObjectIdentityForeignKey) {
this.deleteEntryByObjectIdentityForeignKey = deleteEntryByObjectIdentityForeignKey;
}
public void setDeleteObjectIdentityByPrimaryKeySql(String deleteObjectIdentityByPrimaryKey) {
this.deleteObjectIdentityByPrimaryKey = deleteObjectIdentityByPrimaryKey;
}
public void setInsertClassSql(String insertClass) {
this.insertClass = insertClass;
}
public void setInsertEntrySql(String insertEntry) {
this.insertEntry = insertEntry;
}
public void setInsertObjectIdentitySql(String insertObjectIdentity) {
this.insertObjectIdentity = insertObjectIdentity;
}
public void setInsertSidSql(String insertSid) {
this.insertSid = insertSid;
}
public void setClassPrimaryKeyQuery(String selectClassPrimaryKey) {
this.selectClassPrimaryKey = selectClassPrimaryKey;
}
public void setObjectIdentityPrimaryKeyQuery(String selectObjectIdentityPrimaryKey) {
this.selectObjectIdentityPrimaryKey = selectObjectIdentityPrimaryKey;
}
public void setSidPrimaryKeyQuery(String selectSidPrimaryKey) {
this.selectSidPrimaryKey = selectSidPrimaryKey;
}
public void setUpdateObjectIdentity(String updateObjectIdentity) {
this.updateObjectIdentity = updateObjectIdentity;
}
/**
* @param foreignKeysInDatabase if false this class will perform additional FK
* constrain checking, which may cause deadlocks (the default is true, so deadlocks
* are avoided but the database is expected to enforce FKs)
*/
public void setForeignKeysInDatabase(boolean foreignKeysInDatabase) {
this.foreignKeysInDatabase = foreignKeysInDatabase;
}
@Override
public void setAclClassIdSupported(boolean aclClassIdSupported) {
super.setAclClassIdSupported(aclClassIdSupported);
if (aclClassIdSupported) {
// Change the default insert if it hasn't been overridden
if (this.insertClass.equals(DEFAULT_INSERT_INTO_ACL_CLASS)) {
this.insertClass = DEFAULT_INSERT_INTO_ACL_CLASS_WITH_ID;
}
else {
log.debug("Insert class statement has already been overridden, so not overridding the default");
}
}
}
//~ Instance fields ================================================================================================
private boolean foreignKeysInDatabase = true;
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()";
private String sidIdentityQuery = "call identity()";
private String insertClass = "insert into acl_class (class) values (?)";
private String insertEntry = "insert into acl_entry "
+ "(acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure)"
+ "values (?, ?, ?, ?, ?, ?, ?)";
private String insertObjectIdentity = "insert into acl_object_identity "
+ "(object_id_class, object_id_identity, owner_sid, entries_inheriting) " + "values (?, ?, ?, ?)";
private String insertSid = "insert into acl_sid (principal, sid) values (?, ?)";
private String selectClassPrimaryKey = "select id from acl_class where class=?";
private String selectObjectIdentityPrimaryKey = "select acl_object_identity.id from acl_object_identity, acl_class "
+ "where acl_object_identity.object_id_class = acl_class.id and acl_class.class=? "
+ "and acl_object_identity.object_id_identity = ?";
private String selectSidPrimaryKey = "select id from acl_sid where principal=? and sid=?";
private String updateObjectIdentity = "update acl_object_identity set "
+ "parent_object = ?, owner_sid = ?, entries_inheriting = ?" + " where id = ?";
//~ Constructors ===================================================================================================
public JdbcMutableAclService(DataSource dataSource, LookupStrategy lookupStrategy, AclCache aclCache) {
super(dataSource, lookupStrategy);
Assert.notNull(aclCache, "AclCache required");
this.aclCache = aclCache;
}
//~ Methods ========================================================================================================
public MutableAcl createAcl(ObjectIdentity objectIdentity) throws AlreadyExistsException {
Assert.notNull(objectIdentity, "Object Identity required");
// Check this object identity hasn't already been persisted
if (retrieveObjectIdentityPrimaryKey(objectIdentity) != null) {
throw new AlreadyExistsException("Object identity '" + objectIdentity + "' already exists");
}
// Need to retrieve the current principal, in order to know who "owns" this ACL (can be changed later on)
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
PrincipalSid sid = new PrincipalSid(auth);
// Create the acl_object_identity row
createObjectIdentity(objectIdentity, sid);
// Retrieve the ACL via superclass (ensures cache registration, proper retrieval etc)
Acl acl = readAclById(objectIdentity);
Assert.isInstanceOf(MutableAcl.class, acl, "MutableAcl should be been returned");
return (MutableAcl) acl;
}
/**
* Creates a new row in acl_entry for every ACE defined in the passed MutableAcl object.
*
* @param acl containing the ACEs to insert
*/
protected void createEntries(final MutableAcl acl) {
jdbcTemplate.batchUpdate(insertEntry,
new BatchPreparedStatementSetter() {
public int getBatchSize() {
return acl.getEntries().size();
}
public void setValues(PreparedStatement stmt, int i) throws SQLException {
AccessControlEntry entry_ = acl.getEntries().get(i);
Assert.isTrue(entry_ instanceof AccessControlEntryImpl, "Unknown ACE class");
AccessControlEntryImpl entry = (AccessControlEntryImpl) entry_;
stmt.setLong(1, ((Long) acl.getId()).longValue());
stmt.setInt(2, i);
stmt.setLong(3, createOrRetrieveSidPrimaryKey(entry.getSid(), true).longValue());
stmt.setInt(4, entry.getPermission().getMask());
stmt.setBoolean(5, entry.isGranting());
stmt.setBoolean(6, entry.isAuditSuccess());
stmt.setBoolean(7, entry.isAuditFailure());
}
});
}
/**
* Creates an entry in the acl_object_identity table for the passed ObjectIdentity. The Sid is also
* necessary, as acl_object_identity has defined the sid column as non-null.
*
* @param object to represent an acl_object_identity for
* @param owner for the SID column (will be created if there is no acl_sid entry for this particular Sid already)
*/
protected void createObjectIdentity(ObjectIdentity object, Sid owner) {
Long sidId = createOrRetrieveSidPrimaryKey(owner, true);
Long classId = createOrRetrieveClassPrimaryKey(object.getType(), true);
jdbcTemplate.update(insertObjectIdentity, classId, object.getIdentifier(), sidId, Boolean.TRUE);
}
/**
* Retrieves the primary key from {@code acl_class}, creating a new row if needed and the
* {@code allowCreate} property is {@code true}.
*
* @param type to find or create an entry for (often the fully-qualified class name)
* @param allowCreate true if creation is permitted if not found
*
* @return the primary key or null if not found
*/
protected Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate) {
List<Long> classIds = jdbcTemplate.queryForList(selectClassPrimaryKey, new Object[] {type}, Long.class);
if (!classIds.isEmpty()) {
return classIds.get(0);
}
if (allowCreate) {
jdbcTemplate.update(insertClass, type);
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
"Transaction must be running");
return new Long(jdbcTemplate.queryForLong(classIdentityQuery));
}
return null;
}
/**
* Retrieves the primary key from acl_sid, creating a new row if needed and the allowCreate property is
* true.
*
* @param sid to find or create
* @param allowCreate true if creation is permitted if not found
*
* @return the primary key or null if not found
*
* @throws IllegalArgumentException if the <tt>Sid</tt> is not a recognized implementation.
*/
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
Assert.notNull(sid, "Sid required");
String sidName = null;
boolean sidIsPrincipal = true;
if (sid instanceof PrincipalSid) {
sidName = ((PrincipalSid) sid).getPrincipal();
} else if (sid instanceof GrantedAuthoritySid) {
sidName = ((GrantedAuthoritySid) sid).getGrantedAuthority();
sidIsPrincipal = false;
} else {
throw new IllegalArgumentException("Unsupported implementation of Sid");
}
List<Long> sidIds = jdbcTemplate.queryForList(selectSidPrimaryKey,
new Object[] {Boolean.valueOf(sidIsPrincipal), sidName}, Long.class);
if (!sidIds.isEmpty()) {
return sidIds.get(0);
}
if (allowCreate) {
jdbcTemplate.update(insertSid, new Object[] {Boolean.valueOf(sidIsPrincipal), sidName});
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
return new Long(jdbcTemplate.queryForLong(sidIdentityQuery));
}
return null;
}
public void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren) throws ChildrenExistException {
Assert.notNull(objectIdentity, "Object Identity required");
Assert.notNull(objectIdentity.getIdentifier(), "Object Identity doesn't provide an identifier");
if (deleteChildren) {
List<ObjectIdentity> children = findChildren(objectIdentity);
if (children != null) {
for (int i = 0; i < children.size(); i++) {
deleteAcl(children.get(i), true);
}
}
} else {
if (!foreignKeysInDatabase) {
// We need to perform a manual verification for what a FK would normally do
// We generally don't do this, in the interests of deadlock management
List<ObjectIdentity> children = findChildren(objectIdentity);
if (children != null) {
throw new ChildrenExistException("Cannot delete '" + objectIdentity + "' (has " + children.size()
+ " children)");
}
}
}
Long oidPrimaryKey = retrieveObjectIdentityPrimaryKey(objectIdentity);
// Delete this ACL's ACEs in the acl_entry table
deleteEntries(oidPrimaryKey);
// Delete this ACL's acl_object_identity row
deleteObjectIdentity(oidPrimaryKey);
// Clear the cache
aclCache.evictFromCache(objectIdentity);
}
/**
* Deletes all ACEs defined in the acl_entry table belonging to the presented ObjectIdentity primary key.
*
* @param oidPrimaryKey the rows in acl_entry to delete
*/
protected void deleteEntries(Long oidPrimaryKey) {
jdbcTemplate.update(deleteEntryByObjectIdentityForeignKey,
new Object[] {oidPrimaryKey});
}
/**
* Deletes a single row from acl_object_identity that is associated with the presented ObjectIdentity primary key.
* <p>
* We do not delete any entries from acl_class, even if no classes are using that class any longer. This is a
* deadlock avoidance approach.
*
* @param oidPrimaryKey to delete the acl_object_identity
*/
protected void deleteObjectIdentity(Long oidPrimaryKey) {
// Delete the acl_object_identity row
jdbcTemplate.update(deleteObjectIdentityByPrimaryKey, new Object[] {oidPrimaryKey});
}
/**
* Retrieves the primary key from the acl_object_identity table for the passed ObjectIdentity. Unlike some
* other methods in this implementation, this method will NOT create a row (use {@link
* #createObjectIdentity(ObjectIdentity, Sid)} instead).
*
* @param oid to find
*
* @return the object identity or null if not found
*/
protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
try {
return new Long(jdbcTemplate.queryForLong(selectObjectIdentityPrimaryKey,
new Object[] {oid.getType(), oid.getIdentifier()}));
} catch (DataAccessException notFound) {
return null;
}
}
/**
* This implementation will simply delete all ACEs in the database and recreate them on each invocation of
* this method. A more comprehensive implementation might use dirty state checking, or more likely use ORM
* capabilities for create, update and delete operations of {@link MutableAcl}.
*/
public MutableAcl updateAcl(MutableAcl acl) throws NotFoundException {
Assert.notNull(acl.getId(), "Object Identity doesn't provide an identifier");
// Delete this ACL's ACEs in the acl_entry table
deleteEntries(retrieveObjectIdentityPrimaryKey(acl.getObjectIdentity()));
// Create this ACL's ACEs in the acl_entry table
createEntries(acl);
// Change the mutable columns in acl_object_identity
updateObjectIdentity(acl);
// Clear the cache, including children
clearCacheIncludingChildren(acl.getObjectIdentity());
// Retrieve the ACL via superclass (ensures cache registration, proper retrieval etc)
return (MutableAcl) super.readAclById(acl.getObjectIdentity());
}
private void clearCacheIncludingChildren(ObjectIdentity objectIdentity) {
Assert.notNull(objectIdentity, "ObjectIdentity required");
List<ObjectIdentity> children = findChildren(objectIdentity);
if (children != null) {
for (int i = 0; i < children.size(); i++) {
clearCacheIncludingChildren(children.get(i));
}
}
aclCache.evictFromCache(objectIdentity);
}
/**
* Updates an existing acl_object_identity row, with new information presented in the passed MutableAcl
* object. Also will create an acl_sid entry if needed for the Sid that owns the MutableAcl.
*
* @param acl to modify (a row must already exist in acl_object_identity)
*
* @throws NotFoundException if the ACL could not be found to update.
*/
protected void updateObjectIdentity(MutableAcl acl) {
Long parentId = null;
if (acl.getParentAcl() != null) {
Assert.isInstanceOf(ObjectIdentityImpl.class, acl.getParentAcl().getObjectIdentity(),
"Implementation only supports ObjectIdentityImpl");
ObjectIdentityImpl oii = (ObjectIdentityImpl) acl.getParentAcl().getObjectIdentity();
parentId = retrieveObjectIdentityPrimaryKey(oii);
}
Assert.notNull(acl.getOwner(), "Owner is required in this implementation");
Long ownerSid = createOrRetrieveSidPrimaryKey(acl.getOwner(), true);
int count = jdbcTemplate.update(updateObjectIdentity,
new Object[] {parentId, ownerSid, new Boolean(acl.isEntriesInheriting()), acl.getId()});
if (count != 1) {
throw new NotFoundException("Unable to locate ACL to update");
}
}
/**
* Sets the query that will be used to retrieve the identity of a newly created row in the <tt>acl_class</tt>
* table.
*
* @param classIdentityQuery the query, which should return the identifier. Defaults to <tt>call identity()</tt>
*/
public void setClassIdentityQuery(String classIdentityQuery) {
Assert.hasText(classIdentityQuery, "New classIdentityQuery query is required");
this.classIdentityQuery = classIdentityQuery;
}
/**
* Sets the query that will be used to retrieve the identity of a newly created row in the <tt>acl_sid</tt>
* table.
*
* @param sidIdentityQuery the query, which should return the identifier. Defaults to <tt>call identity()</tt>
*/
public void setSidIdentityQuery(String sidIdentityQuery) {
Assert.hasText(sidIdentityQuery, "New sidIdentityQuery query is required");
this.sidIdentityQuery = sidIdentityQuery;
}
public void setDeleteEntryByObjectIdentityForeignKeySql(String deleteEntryByObjectIdentityForeignKey) {
this.deleteEntryByObjectIdentityForeignKey = deleteEntryByObjectIdentityForeignKey;
}
public void setDeleteObjectIdentityByPrimaryKeySql(String deleteObjectIdentityByPrimaryKey) {
this.deleteObjectIdentityByPrimaryKey = deleteObjectIdentityByPrimaryKey;
}
public void setInsertClassSql(String insertClass) {
this.insertClass = insertClass;
}
public void setInsertEntrySql(String insertEntry) {
this.insertEntry = insertEntry;
}
public void setInsertObjectIdentitySql(String insertObjectIdentity) {
this.insertObjectIdentity = insertObjectIdentity;
}
public void setInsertSidSql(String insertSid) {
this.insertSid = insertSid;
}
public void setClassPrimaryKeyQuery(String selectClassPrimaryKey) {
this.selectClassPrimaryKey = selectClassPrimaryKey;
}
public void setObjectIdentityPrimaryKeyQuery(String selectObjectIdentityPrimaryKey) {
this.selectObjectIdentityPrimaryKey = selectObjectIdentityPrimaryKey;
}
public void setSidPrimaryKeyQuery(String selectSidPrimaryKey) {
this.selectSidPrimaryKey = selectSidPrimaryKey;
}
public void setUpdateObjectIdentity(String updateObjectIdentity) {
this.updateObjectIdentity = updateObjectIdentity;
}
/**
* @param foreignKeysInDatabase if false this class will perform additional FK constrain checking, which may
* cause deadlocks (the default is true, so deadlocks are avoided but the database is expected to enforce FKs)
*/
public void setForeignKeysInDatabase(boolean foreignKeysInDatabase) {
this.foreignKeysInDatabase = foreignKeysInDatabase;
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,35 +12,36 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.jdbc;
import java.util.List;
import java.util.Map;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.Sid;
import java.util.List;
import java.util.Map;
/**
* Performs lookups for {@link org.springframework.security.acls.model.AclService}.
*
* @author Ben Alex
*/
public interface LookupStrategy {
//~ Methods ========================================================================================================
/**
* Perform database-specific optimized lookup.
* @param objects the identities to lookup (required)
* @param sids the SIDs for which identities are required (may be <tt>null</tt> -
* implementations may elect not to provide SID optimisations)
* @return a <tt>Map</tt> where keys represent the {@link ObjectIdentity} of the
* located {@link Acl} and values are the located {@link Acl} (never <tt>null</tt>
* although some entries may be missing; this method should not throw
* {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used to
* automatically create entries if required)
*/
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids);
/**
* Perform database-specific optimized lookup.
*
* @param objects the identities to lookup (required)
* @param sids the SIDs for which identities are required (may be <tt>null</tt> - implementations may elect not
* to provide SID optimisations)
*
* @return a <tt>Map</tt> where keys represent the {@link ObjectIdentity} of the located {@link Acl} and values
* are the located {@link Acl} (never <tt>null</tt> although some entries may be missing; this method
* should not throw {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used
* to automatically create entries if required)
*/
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids);
}
@@ -1,20 +1,5 @@
/*
* Copyright 2002-2016 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
*
* https://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.
*/
/**
* JDBC-based persistence of ACL information
*/
package org.springframework.security.acls.jdbc;
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,40 +12,44 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.model;
import java.io.Serializable;
/**
* Represents an individual permission assignment within an {@link Acl}.
*
* <p>
* Instances MUST be immutable, as they are returned by <code>Acl</code> and should not
* allow client modification.
* Instances MUST be immutable, as they are returned by <code>Acl</code>
* and should not allow client modification.
* </p>
*
* @author Ben Alex
*
*/
public interface AccessControlEntry extends Serializable {
//~ Methods ========================================================================================================
Acl getAcl();
Acl getAcl();
/**
* Obtains an identifier that represents this ACE.
* @return the identifier, or <code>null</code> if unsaved
*/
Serializable getId();
/**
* Obtains an identifier that represents this ACE.
*
* @return the identifier, or <code>null</code> if unsaved
*/
Serializable getId();
Permission getPermission();
Permission getPermission();
Sid getSid();
/**
* Indicates the permission is being granted to the relevant Sid. If false, indicates
* the permission is being revoked/blocked.
* @return true if being granted, false otherwise
*/
boolean isGranting();
Sid getSid();
/**
* Indicates the a Permission is being granted to the relevant Sid. If false, indicates the permission is
* being revoked/blocked.
*
* @return true if being granted, false otherwise
*/
boolean isGranting();
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,182 +12,157 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.model;
import java.io.Serializable;
import java.util.List;
/**
* Represents an access control list (ACL) for a domain object.
*
* <p>
* An <tt>Acl</tt> represents all ACL entries for a given domain object. In order to avoid
* needing references to the domain object itself, this interface handles indirection
* between a domain object and an ACL object identity via the
* {@link org.springframework.security.acls.model.ObjectIdentity} interface.
* An <tt>Acl</tt> represents all ACL entries for a given domain object. In
* order to avoid needing references to the domain object itself, this
* interface handles indirection between a domain object and an ACL object
* identity via the {@link
* org.springframework.security.acls.model.ObjectIdentity} interface.
* </p>
*
* <p>
* Implementing classes may elect to return instances that represent
* {@link org.springframework.security.acls.model.Permission} information for either some
* OR all {@link org.springframework.security.acls.model.Sid} instances. Therefore, an
* instance may NOT necessarily contain ALL <tt>Sid</tt>s for a given domain object.
* {@link org.springframework.security.acls.model.Permission} information for either
* some OR all {@link org.springframework.security.acls.model.Sid}
* instances. Therefore, an instance may NOT necessarily contain ALL <tt>Sid</tt>s
* for a given domain object.
* </p>
*
* @author Ben Alex
*/
public interface Acl extends Serializable {
/**
* Returns all of the entries represented by the present <tt>Acl</tt>. Entries
* associated with the <tt>Acl</tt> parents are not returned.
*
* <p>
* This method is typically used for administrative purposes.
* </p>
*
* <p>
* The order that entries appear in the array is important for methods declared in the
* {@link MutableAcl} interface. Furthermore, some implementations MAY use ordering as
* part of advanced permission checking.
* </p>
*
* <p>
* Do <em>NOT</em> use this method for making authorization decisions. Instead use
* {@link #isGranted(List, List, boolean)}.
* </p>
*
* <p>
* This method must operate correctly even if the <tt>Acl</tt> only represents a
* subset of <tt>Sid</tt>s. The caller is responsible for correctly handling the
* result if only a subset of <tt>Sid</tt>s is represented.
* </p>
* @return the list of entries represented by the <tt>Acl</tt>, or <tt>null</tt> if
* there are no entries presently associated with this <tt>Acl</tt>.
*/
List<AccessControlEntry> getEntries();
/**
* Returns all of the entries represented by the present <tt>Acl</tt>. Entries associated with
* the <tt>Acl</tt> parents are not returned.
*
* <p>This method is typically used for administrative purposes.</p>
*
* <p>The order that entries appear in the array is important for methods declared in the
* {@link MutableAcl} interface. Furthermore, some implementations MAY use ordering as
* part of advanced permission checking.</p>
*
* <p>Do <em>NOT</em> use this method for making authorization decisions. Instead use {@link
* #isGranted(List, List, boolean)}.</p>
*
* <p>This method must operate correctly even if the <tt>Acl</tt> only represents a subset of
* <tt>Sid</tt>s. The caller is responsible for correctly handling the result if only a subset of
* <tt>Sid</tt>s is represented.</p>
*
* @return the list of entries represented by the <tt>Acl</tt>, or <tt>null</tt> if there are
* no entries presently associated with this <tt>Acl</tt>.
*/
List<AccessControlEntry> getEntries();
/**
* Obtains the domain object this <tt>Acl</tt> provides entries for. This is immutable
* once an <tt>Acl</tt> is created.
* @return the object identity (never <tt>null</tt>)
*/
ObjectIdentity getObjectIdentity();
/**
* Obtains the domain object this <tt>Acl</tt> provides entries for. This is immutable once an
* <tt>Acl</tt> is created.
*
* @return the object identity (never <tt>null</tt>)
*/
ObjectIdentity getObjectIdentity();
/**
* Determines the owner of the <tt>Acl</tt>. The meaning of ownership varies by
* implementation and is unspecified.
* @return the owner (may be <tt>null</tt> if the implementation does not use
* ownership concepts)
*/
Sid getOwner();
/**
* Determines the owner of the <tt>Acl</tt>. The meaning of ownership varies by implementation and is
* unspecified.
*
* @return the owner (may be <tt>null</tt> if the implementation does not use ownership concepts)
*/
Sid getOwner();
/**
* A domain object may have a parent for the purpose of ACL inheritance. If there is a
* parent, its ACL can be accessed via this method. In turn, the parent's parent
* (grandparent) can be accessed and so on.
*
* <p>
* This method solely represents the presence of a navigation hierarchy between the
* parent <tt>Acl</tt> and this <tt>Acl</tt>. For actual inheritance to take place,
* the {@link #isEntriesInheriting()} must also be <tt>true</tt>.
* </p>
*
* <p>
* This method must operate correctly even if the <tt>Acl</tt> only represents a
* subset of <tt>Sid</tt>s. The caller is responsible for correctly handling the
* result if only a subset of <tt>Sid</tt>s is represented.
* </p>
* @return the parent <tt>Acl</tt> (may be <tt>null</tt> if this <tt>Acl</tt> does not
* have a parent)
*/
Acl getParentAcl();
/**
* A domain object may have a parent for the purpose of ACL inheritance. If there is a parent, its ACL can
* be accessed via this method. In turn, the parent's parent (grandparent) can be accessed and so on.
*
* <p>This method solely represents the presence of a navigation hierarchy between the parent <tt>Acl</tt> and this
* <tt>Acl</tt>. For actual inheritance to take place, the {@link #isEntriesInheriting()} must also be
* <tt>true</tt>.</p>
*
* <p>This method must operate correctly even if the <tt>Acl</tt> only represents a subset of
* <tt>Sid</tt>s. The caller is responsible for correctly handling the result if only a subset of
* <tt>Sid</tt>s is represented.</p>
*
* @return the parent <tt>Acl</tt> (may be <tt>null</tt> if this <tt>Acl</tt> does not have a parent)
*/
Acl getParentAcl();
/**
* Indicates whether the ACL entries from the {@link #getParentAcl()} should flow down
* into the current <tt>Acl</tt>.
* <p>
* The mere link between an <tt>Acl</tt> and a parent <tt>Acl</tt> on its own is
* insufficient to cause ACL entries to inherit down. This is because a domain object
* may wish to have entirely independent entries, but maintain the link with the
* parent for navigation purposes. Thus, this method denotes whether or not the
* navigation relationship also extends to the actual inheritance of entries.
* </p>
* @return <tt>true</tt> if parent ACL entries inherit into the current <tt>Acl</tt>
*/
boolean isEntriesInheriting();
/**
* Indicates whether the ACL entries from the {@link #getParentAcl()} should flow down into the current
* <tt>Acl</tt>.<p>The mere link between an <tt>Acl</tt> and a parent <tt>Acl</tt> on its own
* is insufficient to cause ACL entries to inherit down. This is because a domain object may wish to have entirely
* independent entries, but maintain the link with the parent for navigation purposes. Thus, this method denotes
* whether or not the navigation relationship also extends to the actual inheritance of entries.</p>
*
* @return <tt>true</tt> if parent ACL entries inherit into the current <tt>Acl</tt>
*/
boolean isEntriesInheriting();
/**
* This is the actual authorization logic method, and must be used whenever ACL
* authorization decisions are required.
*
* <p>
* An array of <tt>Sid</tt>s are presented, representing security identifies of the
* current principal. In addition, an array of <tt>Permission</tt>s is presented which
* will have one or more bits set in order to indicate the permissions needed for an
* affirmative authorization decision. An array is presented because holding
* <em>any</em> of the <tt>Permission</tt>s inside the array will be sufficient for an
* affirmative authorization.
* </p>
*
* <p>
* The actual approach used to make authorization decisions is left to the
* implementation and is not specified by this interface. For example, an
* implementation <em>MAY</em> search the current ACL in the order the ACL entries
* have been stored. If a single entry is found that has the same active bits as are
* shown in a passed <tt>Permission</tt>, that entry's grant or deny state may
* determine the authorization decision. If the case of a deny state, the deny
* decision will only be relevant if all other <tt>Permission</tt>s passed in the
* array have also been unsuccessfully searched. If no entry is found that match the
* bits in the current ACL, provided that {@link #isEntriesInheriting()} is
* <tt>true</tt>, the authorization decision may be passed to the parent ACL. If there
* is no matching entry, the implementation MAY throw an exception, or make a
* predefined authorization decision.
* </p>
*
* <p>
* This method must operate correctly even if the <tt>Acl</tt> only represents a
* subset of <tt>Sid</tt>s, although the implementation is permitted to throw one of
* the signature-defined exceptions if the method is called requesting an
* authorization decision for a {@link Sid} that was never loaded in this <tt>Acl</tt>
* .
* </p>
* @param permission the permission or permissions required (at least one entry
* required)
* @param sids the security identities held by the principal (at least one entry
* required)
* @param administrativeMode if <tt>true</tt> denotes the query is for administrative
* purposes and no logging or auditing (if supported by the implementation) should be
* undertaken
* @return <tt>true</tt> if authorization is granted
* @throws NotFoundException MUST be thrown if an implementation cannot make an
* authoritative authorization decision, usually because there is no ACL information
* for this particular permission and/or SID
* @throws UnloadedSidException thrown if the <tt>Acl</tt> does not have details for
* one or more of the <tt>Sid</tt>s passed as arguments
*/
boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
throws NotFoundException, UnloadedSidException;
/**
* For efficiency reasons an <tt>Acl</tt> may be loaded and <em>not</em> contain
* entries for every <tt>Sid</tt> in the system. If an <tt>Acl</tt> has been loaded
* and does not represent every <tt>Sid</tt>, all methods of the <tt>Acl</tt> can only
* be used within the limited scope of the <tt>Sid</tt> instances it actually
* represents.
* <p>
* It is normal to load an <tt>Acl</tt> for only particular <tt>Sid</tt>s if read-only
* authorization decisions are being made. However, if user interface reporting or
* modification of <tt>Acl</tt>s are desired, an <tt>Acl</tt> should be loaded with
* all <tt>Sid</tt>s. This method denotes whether or not the specified <tt>Sid</tt>s
* have been loaded or not.
* </p>
* @param sids one or more security identities the caller is interest in knowing
* whether this <tt>Sid</tt> supports
* @return <tt>true</tt> if every passed <tt>Sid</tt> is represented by this
* <tt>Acl</tt> instance
*/
boolean isSidLoaded(List<Sid> sids);
/**
* This is the actual authorization logic method, and must be used whenever ACL authorization decisions are
* required.
*
* <p>An array of <tt>Sid</tt>s are presented, representing security identifies of the current
* principal. In addition, an array of <tt>Permission</tt>s is presented which will have one or more bits set
* in order to indicate the permissions needed for an affirmative authorization decision. An array is presented
* because holding <em>any</em> of the <tt>Permission</tt>s inside the array will be sufficient for an
* affirmative authorization.</p>
*
* <p>The actual approach used to make authorization decisions is left to the implementation and is not
* specified by this interface. For example, an implementation <em>MAY</em> search the current ACL in the order
* the ACL entries have been stored. If a single entry is found that has the same active bits as are shown in a
* passed <tt>Permission</tt>, that entry's grant or deny state may determine the authorization decision. If
* the case of a deny state, the deny decision will only be relevant if all other <tt>Permission</tt>s passed
* in the array have also been unsuccessfully searched. If no entry is found that match the bits in the current
* ACL, provided that {@link #isEntriesInheriting()} is <tt>true</tt>, the authorization decision may be
* passed to the parent ACL. If there is no matching entry, the implementation MAY throw an exception, or make a
* predefined authorization decision.</p>
*
* <p>This method must operate correctly even if the <tt>Acl</tt> only represents a subset of <tt>Sid</tt>s,
* although the implementation is permitted to throw one of the signature-defined exceptions if the method
* is called requesting an authorization decision for a {@link Sid} that was never loaded in this <tt>Acl</tt>.
* </p>
*
* @param permission the permission or permissions required (at least one entry required)
* @param sids the security identities held by the principal (at least one entry required)
* @param administrativeMode if <tt>true</tt> denotes the query is for administrative purposes and no logging
* or auditing (if supported by the implementation) should be undertaken
*
* @return <tt>true</tt> if authorization is granted
*
* @throws NotFoundException MUST be thrown if an implementation cannot make an authoritative authorization
* decision, usually because there is no ACL information for this particular permission and/or SID
* @throws UnloadedSidException thrown if the <tt>Acl</tt> does not have details for one or more of the
* <tt>Sid</tt>s passed as arguments
*/
boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
throws NotFoundException, UnloadedSidException;
/**
* For efficiency reasons an <tt>Acl</tt> may be loaded and <em>not</em> contain entries for every
* <tt>Sid</tt> in the system. If an <tt>Acl</tt> has been loaded and does not represent every
* <tt>Sid</tt>, all methods of the <tt>Acl</tt> can only be used within the limited scope of the
* <tt>Sid</tt> instances it actually represents.
* <p>
* It is normal to load an <tt>Acl</tt> for only particular <tt>Sid</tt>s if read-only authorization
* decisions are being made. However, if user interface reporting or modification of <tt>Acl</tt>s are
* desired, an <tt>Acl</tt> should be loaded with all <tt>Sid</tt>s. This method denotes whether or
* not the specified <tt>Sid</tt>s have been loaded or not.
* </p>
*
* @param sids one or more security identities the caller is interest in knowing whether this <tt>Sid</tt>
* supports
*
* @return <tt>true</tt> if every passed <tt>Sid</tt> is represented by this <tt>Acl</tt> instance
*/
boolean isSidLoaded(List<Sid> sids);
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,30 +12,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.model;
import org.springframework.security.acls.jdbc.JdbcAclService;
import java.io.Serializable;
import org.springframework.security.acls.jdbc.JdbcAclService;
/**
* A caching layer for {@link JdbcAclService}.
*
* @author Ben Alex
*
*/
public interface AclCache {
//~ Methods ========================================================================================================
void evictFromCache(Serializable pk);
void evictFromCache(Serializable pk);
void evictFromCache(ObjectIdentity objectIdentity);
void evictFromCache(ObjectIdentity objectIdentity);
MutableAcl getFromCache(ObjectIdentity objectIdentity);
MutableAcl getFromCache(ObjectIdentity objectIdentity);
MutableAcl getFromCache(Serializable pk);
MutableAcl getFromCache(Serializable pk);
void putInCache(MutableAcl acl);
void clearCache();
void putInCache(MutableAcl acl);
void clearCache();
}
@@ -1,19 +1,3 @@
/*
* Copyright 2002-2016 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
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.model;
/**
@@ -24,23 +8,24 @@ package org.springframework.security.acls.model;
*/
public abstract class AclDataAccessException extends RuntimeException {
/**
* Constructs an <code>AclDataAccessException</code> with the specified message and
* root cause.
* @param msg the detail message
* @param cause the root cause
*/
public AclDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
/**
* Constructs an <code>AclDataAccessException</code> with the specified message and no
* root cause.
* @param msg the detail message
*/
public AclDataAccessException(String msg) {
super(msg);
}
/**
* Constructs an <code>AclDataAccessException</code> with the specified
* message and root cause.
*
* @param msg the detail message
* @param cause the root cause
*/
public AclDataAccessException(String msg, Throwable cause) {
super(msg, cause);
}
/**
* Constructs an <code>AclDataAccessException</code> with the specified
* message and no root cause.
*
* @param msg the detail message
*/
public AclDataAccessException(String msg) {
super(msg);
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,91 +12,87 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.model;
import java.util.List;
import java.util.Map;
/**
* Provides retrieval of {@link Acl} instances.
*
* @author Ben Alex
*/
public interface AclService {
//~ Methods ========================================================================================================
/**
* Locates all object identities that use the specified parent. This is useful for
* administration tools.
* @param parentIdentity to locate children of
* @return the children (or <tt>null</tt> if none were found)
*/
List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity);
/**
* Locates all object identities that use the specified parent. This is useful for administration tools.
*
* @param parentIdentity to locate children of
*
* @return the children (or <tt>null</tt> if none were found)
*/
List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity);
/**
* Same as {@link #readAclsById(List)} except it returns only a single Acl.
* <p>
* This method should not be called as it does not leverage the underlying
* implementation's potential ability to filter <tt>Acl</tt> entries based on a
* {@link Sid} parameter.
* </p>
* @param object to locate an {@link Acl} for
* @return the {@link Acl} for the requested {@link ObjectIdentity} (never
* <tt>null</tt>)
* @throws NotFoundException if an {@link Acl} was not found for the requested
* {@link ObjectIdentity}
*/
Acl readAclById(ObjectIdentity object) throws NotFoundException;
/**
* Same as {@link #readAclsById(List)} except it returns only a single Acl.
* <p>
* This method should not be called as it does not leverage the underlying implementation's potential ability to
* filter <tt>Acl</tt> entries based on a {@link Sid} parameter.</p>
*
* @param object to locate an {@link Acl} for
*
* @return the {@link Acl} for the requested {@link ObjectIdentity} (never <tt>null</tt>)
*
* @throws NotFoundException if an {@link Acl} was not found for the requested {@link ObjectIdentity}
*/
Acl readAclById(ObjectIdentity object) throws NotFoundException;
/**
* Same as {@link #readAclsById(List, List)} except it returns only a single Acl.
* @param object to locate an {@link Acl} for
* @param sids the security identities for which {@link Acl} information is required
* (may be <tt>null</tt> to denote all entries)
* @return the {@link Acl} for the requested {@link ObjectIdentity} (never
* <tt>null</tt>)
* @throws NotFoundException if an {@link Acl} was not found for the requested
* {@link ObjectIdentity}
*/
Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException;
/**
* Same as {@link #readAclsById(List, List)} except it returns only a single Acl.
*
* @param object to locate an {@link Acl} for
* @param sids the security identities for which {@link Acl} information is required
* (may be <tt>null</tt> to denote all entries)
*
* @return the {@link Acl} for the requested {@link ObjectIdentity} (never <tt>null</tt>)
*
* @throws NotFoundException if an {@link Acl} was not found for the requested {@link ObjectIdentity}
*/
Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException;
/**
* Obtains all the <tt>Acl</tt>s that apply for the passed <tt>Object</tt>s.
* <p>
* The returned map is keyed on the passed objects, with the values being the
* <tt>Acl</tt> instances. Any unknown objects will not have a map key.
* </p>
* @param objects the objects to find {@link Acl} information for
* @return a map with exactly one element for each {@link ObjectIdentity} passed as an
* argument (never <tt>null</tt>)
* @throws NotFoundException if an {@link Acl} was not found for each requested
* {@link ObjectIdentity}
*/
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects) throws NotFoundException;
/**
* Obtains all the <tt>Acl</tt>s that apply for the passed <tt>Object</tt>s, but only
* for the security identifies passed.
* <p>
* Implementations <em>MAY</em> provide a subset of the ACLs via this method although
* this is NOT a requirement. This is intended to allow performance optimisations
* within implementations. Callers should therefore use this method in preference to
* the alternative overloaded version which does not have performance optimisation
* opportunities.
* </p>
* <p>
* The returned map is keyed on the passed objects, with the values being the
* <tt>Acl</tt> instances. Any unknown objects (or objects for which the interested
* <tt>Sid</tt>s do not have entries) will not have a map key.
* </p>
* @param objects the objects to find {@link Acl} information for
* @param sids the security identities for which {@link Acl} information is required
* (may be <tt>null</tt> to denote all entries)
* @return a map with exactly one element for each {@link ObjectIdentity} passed as an
* argument (never <tt>null</tt>)
* @throws NotFoundException if an {@link Acl} was not found for each requested
* {@link ObjectIdentity}
*/
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) throws NotFoundException;
/**
* Obtains all the <tt>Acl</tt>s that apply for the passed <tt>Object</tt>s.<p>The returned map is
* keyed on the passed objects, with the values being the <tt>Acl</tt> instances. Any unknown objects will not
* have a map key.</p>
*
* @param objects the objects to find {@link Acl} information for
*
* @return a map with exactly one element for each {@link ObjectIdentity} passed as an argument (never <tt>null</tt>)
*
* @throws NotFoundException if an {@link Acl} was not found for each requested {@link ObjectIdentity}
*/
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects) throws NotFoundException;
/**
* Obtains all the <tt>Acl</tt>s that apply for the passed <tt>Object</tt>s, but only for the
* security identifies passed.<p>Implementations <em>MAY</em> provide a subset of the ACLs via this method
* although this is NOT a requirement. This is intended to allow performance optimisations within implementations.
* Callers should therefore use this method in preference to the alternative overloaded version which does not
* have performance optimisation opportunities.</p>
* <p>The returned map is keyed on the passed objects, with the values being the <tt>Acl</tt>
* instances. Any unknown objects (or objects for which the interested <tt>Sid</tt>s do not have entries) will
* not have a map key.</p>
*
* @param objects the objects to find {@link Acl} information for
* @param sids the security identities for which {@link Acl} information is required
* (may be <tt>null</tt> to denote all entries)
*
* @return a map with exactly one element for each {@link ObjectIdentity} passed as an argument (never <tt>null</tt>)
*
* @throws NotFoundException if an {@link Acl} was not found for each requested {@link ObjectIdentity}
*/
Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) throws NotFoundException;
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,32 +12,34 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.model;
/**
* Thrown if an <code>Acl</code> entry already exists for the object.
*
* @author Ben Alex
*/
public class AlreadyExistsException extends AclDataAccessException {
//~ Constructors ===================================================================================================
/**
* Constructs an <code>AlreadyExistsException</code> with the specified message.
* @param msg the detail message
*/
public AlreadyExistsException(String msg) {
super(msg);
}
/**
* Constructs an <code>AlreadyExistsException</code> with the specified message and
* root cause.
* @param msg the detail message
* @param cause root cause
*/
public AlreadyExistsException(String msg, Throwable cause) {
super(msg, cause);
}
/**
* Constructs an <code>AlreadyExistsException</code> with the specified message.
*
* @param msg the detail message
*/
public AlreadyExistsException(String msg) {
super(msg);
}
/**
* Constructs an <code>AlreadyExistsException</code> with the specified message
* and root cause.
*
* @param msg the detail message
* @param t root cause
*/
public AlreadyExistsException(String msg, Throwable t) {
super(msg, t);
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,18 +12,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.model;
/**
* Represents an ACE that provides auditing information.
*
* @author Ben Alex
*
*/
public interface AuditableAccessControlEntry extends AccessControlEntry {
//~ Methods ========================================================================================================
boolean isAuditFailure();
boolean isAuditSuccess();
boolean isAuditFailure();
boolean isAuditSuccess();
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,16 +12,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.model;
/**
* A mutable ACL that provides audit capabilities.
*
* @author Ben Alex
*
*/
public interface AuditableAcl extends MutableAcl {
//~ Methods ========================================================================================================
void updateAuditing(int aceIndex, boolean auditSuccess, boolean auditFailure);
void updateAuditing(int aceIndex, boolean auditSuccess, boolean auditFailure);
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,32 +12,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.model;
/**
* Thrown if an {@link Acl} cannot be deleted because children <code>Acl</code>s exist.
*
* @author Ben Alex
*/
public class ChildrenExistException extends AclDataAccessException {
//~ Constructors ===================================================================================================
/**
* Constructs an <code>ChildrenExistException</code> with the specified message.
* @param msg the detail message
*/
public ChildrenExistException(String msg) {
super(msg);
}
/**
* Constructs an <code>ChildrenExistException</code> with the specified message and
* root cause.
* @param msg the detail message
* @param cause root cause
*/
public ChildrenExistException(String msg, Throwable cause) {
super(msg, cause);
}
/**
* Constructs an <code>ChildrenExistException</code> with the specified
* message.
*
* @param msg the detail message
*/
public ChildrenExistException(String msg) {
super(msg);
}
/**
* Constructs an <code>ChildrenExistException</code> with the specified
* message and root cause.
*
* @param msg the detail message
* @param t root cause
*/
public ChildrenExistException(String msg, Throwable t) {
super(msg, t);
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,49 +12,56 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.model;
import java.io.Serializable;
/**
* A mutable <tt>Acl</tt>.
* <p>
* A mutable ACL must ensure that appropriate security checks are performed before
* allowing access to its methods.
* A mutable ACL must ensure that appropriate security checks are performed
* before allowing access to its methods.
*
* @author Ben Alex
*/
public interface MutableAcl extends Acl {
//~ Methods ========================================================================================================
void deleteAce(int aceIndex) throws NotFoundException;
void deleteAce(int aceIndex) throws NotFoundException;
/**
* Obtains an identifier that represents this <tt>MutableAcl</tt>.
* @return the identifier, or <tt>null</tt> if unsaved
*/
Serializable getId();
/**
* Obtains an identifier that represents this <tt>MutableAcl</tt>.
*
* @return the identifier, or <tt>null</tt> if unsaved
*/
Serializable getId();
void insertAce(int atIndexLocation, Permission permission, Sid sid, boolean granting) throws NotFoundException;
void insertAce(int atIndexLocation, Permission permission, Sid sid, boolean granting)
throws NotFoundException;
/**
* Changes the present owner to a different owner.
* @param newOwner the new owner (mandatory; cannot be null)
*/
void setOwner(Sid newOwner);
/**
* Changes the present owner to a different owner.
*
* @param newOwner the new owner (mandatory; cannot be null)
*/
void setOwner(Sid newOwner);
/**
* Change the value returned by {@link Acl#isEntriesInheriting()}.
* @param entriesInheriting the new value
*/
void setEntriesInheriting(boolean entriesInheriting);
/**
* Change the value returned by {@link Acl#isEntriesInheriting()}.
*
* @param entriesInheriting the new value
*/
void setEntriesInheriting(boolean entriesInheriting);
/**
* Changes the parent of this ACL.
* @param newParent the new parent
*/
void setParent(Acl newParent);
void updateAce(int aceIndex, Permission permission) throws NotFoundException;
/**
* Changes the parent of this ACL.
*
* @param newParent the new parent
*/
void setParent(Acl newParent);
void updateAce(int aceIndex, Permission permission)
throws NotFoundException;
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,41 +12,50 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.model;
/**
* Provides support for creating and storing <code>Acl</code> instances.
*
* @author Ben Alex
*/
public interface MutableAclService extends AclService {
//~ Methods ========================================================================================================
/**
* Creates an empty <code>Acl</code> object in the database. It will have no entries.
* The returned object will then be used to add entries.
* @param objectIdentity the object identity to create
* @return an ACL object with its ID set
* @throws AlreadyExistsException if the passed object identity already has a record
*/
MutableAcl createAcl(ObjectIdentity objectIdentity) throws AlreadyExistsException;
/**
* Creates an empty <code>Acl</code> object in the database. It will have no entries. The returned object
* will then be used to add entries.
*
* @param objectIdentity the object identity to create
*
* @return an ACL object with its ID set
*
* @throws AlreadyExistsException if the passed object identity already has a record
*/
MutableAcl createAcl(ObjectIdentity objectIdentity)
throws AlreadyExistsException;
/**
* Removes the specified entry from the database.
* @param objectIdentity the object identity to remove
* @param deleteChildren whether to cascade the delete to children
* @throws ChildrenExistException if the deleteChildren argument was
* <code>false</code> but children exist
*/
void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren) throws ChildrenExistException;
/**
* Changes an existing <code>Acl</code> in the database.
* @param acl to modify
* @throws NotFoundException if the relevant record could not be found (did you
* remember to use {@link #createAcl(ObjectIdentity)} to create the object, rather
* than creating it with the <code>new</code> keyword?)
*/
MutableAcl updateAcl(MutableAcl acl) throws NotFoundException;
/**
* Removes the specified entry from the database.
*
* @param objectIdentity the object identity to remove
* @param deleteChildren whether to cascade the delete to children
*
* @throws ChildrenExistException if the deleteChildren argument was <code>false</code> but children exist
*/
void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren)
throws ChildrenExistException;
/**
* Changes an existing <code>Acl</code> in the database.
*
* @param acl to modify
*
* @throws NotFoundException if the relevant record could not be found (did you remember to use {@link
* #createAcl(ObjectIdentity)} to create the object, rather than creating it with the <code>new</code>
* keyword?)
*/
MutableAcl updateAcl(MutableAcl acl) throws NotFoundException;
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,32 +12,34 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.model;
/**
* Thrown if an ACL-related object cannot be found.
*
* @author Ben Alex
*/
public class NotFoundException extends AclDataAccessException {
//~ Constructors ===================================================================================================
/**
* Constructs an <code>NotFoundException</code> with the specified message.
* @param msg the detail message
*/
public NotFoundException(String msg) {
super(msg);
}
/**
* Constructs an <code>NotFoundException</code> with the specified message and root
* cause.
* @param msg the detail message
* @param cause root cause
*/
public NotFoundException(String msg, Throwable cause) {
super(msg, cause);
}
/**
* Constructs an <code>NotFoundException</code> with the specified message.
*
* @param msg the detail message
*/
public NotFoundException(String msg) {
super(msg);
}
/**
* Constructs an <code>NotFoundException</code> with the specified message
* and root cause.
*
* @param msg the detail message
* @param t root cause
*/
public NotFoundException(String msg, Throwable t) {
super(msg, t);
}
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,62 +12,60 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.model;
import java.io.Serializable;
/**
* Represents the identity of an individual domain object instance.
*
* <p>
* As implementations of <tt>ObjectIdentity</tt> are used as the key to represent domain
* objects in the ACL subsystem, it is essential that implementations provide methods so
* that object-equality rather than reference-equality can be relied upon reliably. In
* other words, the ACL subsystem can consider two <tt>ObjectIdentity</tt>s equal if
* <tt>identity1.equals(identity2)</tt>, rather than reference-equality of
* <tt>identity1==identity2</tt>.
* As implementations of <tt>ObjectIdentity</tt> are used as the key to represent
* domain objects in the ACL subsystem, it is essential that implementations provide
* methods so that object-equality rather than reference-equality can be relied upon
* reliably. In other words, the ACL subsystem can consider two
* <tt>ObjectIdentity</tt>s equal if <tt>identity1.equals(identity2)</tt>, rather than
* reference-equality of <tt>identity1==identity2</tt>.
* </p>
*
* @author Ben Alex
*/
public interface ObjectIdentity extends Serializable {
//~ Methods ========================================================================================================
/**
* @param obj to be compared
* @return <tt>true</tt> if the objects are equal, <tt>false</tt> otherwise
* @see Object#equals(Object)
*/
@Override
boolean equals(Object obj);
/**
* @param obj to be compared
*
* @return <tt>true</tt> if the objects are equal, <tt>false</tt> otherwise
* @see Object#equals(Object)
*/
boolean equals(Object obj);
/**
* Obtains the actual identifier. This identifier must not be reused to represent
* other domain objects with the same <tt>javaType</tt>.
*
* <p>
* Because ACLs are largely immutable, it is strongly recommended to use a synthetic
* identifier (such as a database sequence number for the primary key). Do not use an
* identifier with business meaning, as that business meaning may change in the future
* such change will cascade to the ACL subsystem data.
* </p>
* @return the identifier (unique within this <tt>type</tt>; never <tt>null</tt>)
*/
Serializable getIdentifier();
/**
* Obtains the actual identifier. This identifier must not be reused to represent other domain objects with
* the same <tt>javaType</tt>.
*
* <p>Because ACLs are largely immutable, it is strongly recommended to use
* a synthetic identifier (such as a database sequence number for the primary key). Do not use an identifier with
* business meaning, as that business meaning may change in the future such change will cascade to the ACL
* subsystem data.</p>
*
* @return the identifier (unique within this <tt>type</tt>; never <tt>null</tt>)
*/
Serializable getIdentifier();
/**
* Obtains the "type" metadata for the domain object. This will often be a Java type
* name (an interface or a class) &ndash; traditionally it is the name of the domain
* object implementation class.
* @return the "type" of the domain object (never <tt>null</tt>).
*/
String getType();
/**
* @return a hash code representation of the <tt>ObjectIdentity</tt>
* @see Object#hashCode()
*/
@Override
int hashCode();
/**
* Obtains the "type" metadata for the domain object. This will often be a Java type name (an interface or a class)
* &ndash; traditionally it is the name of the domain object implementation class.
*
* @return the "type" of the domain object (never <tt>null</tt>).
*/
String getType();
/**
* @return a hash code representation of the <tt>ObjectIdentity</tt>
* @see Object#hashCode()
*/
int hashCode();
}
@@ -1,41 +1,26 @@
/*
* Copyright 2002-2016 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
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.model;
import java.io.Serializable;
/**
* Strategy which creates an {@link ObjectIdentity} from an object identifier (such as a
* primary key) and type information.
* Strategy which creates an {@link ObjectIdentity} from an object identifier (such as a primary key)
* and type information.
* <p>
* Differs from {@link ObjectIdentityRetrievalStrategy} in that it is used in situations
* when the actual object instance isn't available.
* Differs from {@link ObjectIdentityRetrievalStrategy} in that it is used in situations when the actual object
* instance isn't available.
*
* @author Luke Taylor
* @since 3.0
*/
public interface ObjectIdentityGenerator {
/**
* @param id the identifier of the domain object, not null
* @param type the type of the object (often a class name), not null
* @return the identity constructed using the supplied identifier and type
* information.
*/
ObjectIdentity createObjectIdentity(Serializable id, String type);
/**
*
* @param id the identifier of the domain object, not null
* @param type the type of the object (often a class name), not null
* @return the identity constructed using the supplied identifier and type information.
*/
ObjectIdentity createObjectIdentity(Serializable id, String type);
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -16,14 +15,16 @@
package org.springframework.security.acls.model;
/**
* Strategy interface that provides the ability to determine which {@link ObjectIdentity}
* will be returned for a particular domain object
*
* @author Ben Alex
*
*/
public interface ObjectIdentityRetrievalStrategy {
//~ Methods ========================================================================================================
ObjectIdentity getObjectIdentity(Object domainObject);
ObjectIdentity getObjectIdentity(Object domainObject);
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,21 +12,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.model;
/**
* A mutable ACL that provides ownership capabilities.
*
* <p>
* Generally the owner of an ACL is able to call any ACL mutator method, as well as assign
* a new owner.
* Generally the owner of an ACL is able to call any ACL mutator method, as
* well as assign a new owner.
*
* @author Ben Alex
*/
public interface OwnershipAcl extends MutableAcl {
//~ Methods ========================================================================================================
@Override
void setOwner(Sid newOwner);
void setOwner(Sid newOwner);
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.model;
import java.io.Serializable;
@@ -24,37 +22,36 @@ import java.io.Serializable;
* @author Ben Alex
*/
public interface Permission extends Serializable {
//~ Static fields/initializers =====================================================================================
char RESERVED_ON = '~';
char RESERVED_ON = '~';
char RESERVED_OFF = '.';
String THIRTY_TWO_RESERVED_OFF = "................................";
char RESERVED_OFF = '.';
//~ Methods ========================================================================================================
String THIRTY_TWO_RESERVED_OFF = "................................";
/**
* Returns the bits that represents the permission.
* @return the bits that represent the permission
*/
int getMask();
/**
* Returns a 32-character long bit pattern <code>String</code> representing this
* permission.
* <p>
* Implementations are free to format the pattern as they see fit, although under no
* circumstances may {@link #RESERVED_OFF} or {@link #RESERVED_ON} be used within the
* pattern. An exemption is in the case of {@link #RESERVED_OFF} which is used to
* denote a bit that is off (clear). Implementations may also elect to use
* {@link #RESERVED_ON} internally for computation purposes, although this method may
* not return any <code>String</code> containing {@link #RESERVED_ON}.
* <p>
* The returned String must be 32 characters in length.
* <p>
* This method is only used for user interface and logging purposes. It is not used in
* any permission calculations. Therefore, duplication of characters within the output
* is permitted.
* @return a 32-character bit pattern
*/
String getPattern();
/**
* Returns the bits that represents the permission.
*
* @return the bits that represent the permission
*/
int getMask();
/**
* Returns a 32-character long bit pattern <code>String</code> representing this permission.
* <p>
* Implementations are free to format the pattern as they see fit, although under no circumstances may
* {@link #RESERVED_OFF} or {@link #RESERVED_ON} be used within the pattern. An exemption is in the case of
* {@link #RESERVED_OFF} which is used to denote a bit that is off (clear).
* Implementations may also elect to use {@link #RESERVED_ON} internally for computation purposes,
* although this method may not return any <code>String</code> containing {@link #RESERVED_ON}.
* <p>
* The returned String must be 32 characters in length.
* <p>
* This method is only used for user interface and logging purposes. It is not used in any permission
* calculations. Therefore, duplication of characters within the output is permitted.
*
* @return a 32-character bit pattern
*/
String getPattern();
}
@@ -1,36 +0,0 @@
/*
* Copyright 2002-2016 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
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.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 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,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.model;
import java.io.Serializable;
@@ -22,32 +20,32 @@ import java.io.Serializable;
* A security identity recognised by the ACL system.
*
* <p>
* This interface provides indirection between actual security objects (eg principals,
* roles, groups etc) and what is stored inside an <code>Acl</code>. This is because an
* <code>Acl</code> will not store an entire security object, but only an abstraction of
* it. This interface therefore provides a simple way to compare these abstracted security
* This interface provides indirection between actual security objects (eg
* principals, roles, groups etc) and what is stored inside an
* <code>Acl</code>. This is because an <code>Acl</code> will not store an
* entire security object, but only an abstraction of it. This interface
* therefore provides a simple way to compare these abstracted security
* identities with other security identities and actual security objects.
* </p>
*
* @author Ben Alex
*/
public interface Sid extends Serializable {
//~ Methods ========================================================================================================
/**
* Refer to the <code>java.lang.Object</code> documentation for the interface
* contract.
* @param obj to be compared
* @return <code>true</code> if the objects are equal, <code>false</code> otherwise
*/
@Override
boolean equals(Object obj);
/**
* Refer to the <code>java.lang.Object</code> documentation for the interface
* contract.
* @return a hash code representation of this object
*/
@Override
int hashCode();
/**
* Refer to the <code>java.lang.Object</code> documentation for the interface contract.
*
* @param obj to be compared
*
* @return <code>true</code> if the objects are equal, <code>false</code> otherwise
*/
boolean equals(Object obj);
/**
* Refer to the <code>java.lang.Object</code> documentation for the interface contract.
*
* @return a hash code representation of this object
*/
int hashCode();
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -20,14 +19,15 @@ import java.util.List;
import org.springframework.security.core.Authentication;
/**
* Strategy interface that provides an ability to determine the {@link Sid} instances
* applicable for an {@link Authentication}.
* Strategy interface that provides an ability to determine the {@link Sid} instances applicable
* for an {@link Authentication}.
*
* @author Ben Alex
*/
public interface SidRetrievalStrategy {
//~ Methods ========================================================================================================
List<Sid> getSids(Authentication authentication);
List<Sid> getSids(Authentication authentication);
}
@@ -1,11 +1,10 @@
/*
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
* 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,
@@ -13,34 +12,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.acls.model;
/**
* Thrown if an {@link Acl} cannot perform an operation because it only loaded a subset of
* <code>Sid</code>s and the caller has requested details for an unloaded <code>Sid</code>
* .
* Thrown if an {@link Acl} cannot perform an operation because it only loaded a subset of <code>Sid</code>s and
* the caller has requested details for an unloaded <code>Sid</code>.
*
* @author Ben Alex
*/
public class UnloadedSidException extends AclDataAccessException {
//~ Constructors ===================================================================================================
/**
* Constructs an <code>NotFoundException</code> with the specified message.
* @param msg the detail message
*/
public UnloadedSidException(String msg) {
super(msg);
}
/**
* Constructs an <code>NotFoundException</code> with the specified message and root
* cause.
* @param msg the detail message
* @param cause root cause
*/
public UnloadedSidException(String msg, Throwable cause) {
super(msg, cause);
}
/**
* Constructs an <code>NotFoundException</code> with the specified message.
*
* @param msg the detail message
*/
public UnloadedSidException(String msg) {
super(msg);
}
/**
* Constructs an <code>NotFoundException</code> with the specified message
* and root cause.
*
* @param msg the detail message
* @param t root cause
*/
public UnloadedSidException(String msg, Throwable t) {
super(msg, t);
}
}
@@ -1,21 +1,5 @@
/*
* Copyright 2002-2016 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
*
* https://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.
*/
/**
* Interfaces and shared classes to manage access control lists (ACLs) for domain object
* instances.
* Interfaces and shared classes to manage access control lists (ACLs) for domain object instances.
*/
package org.springframework.security.acls.model;

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