1
0
mirror of synced 2026-07-10 05:10:03 +00:00

Compare commits

...

196 Commits

Author SHA1 Message Date
Ben Alex 6fe569556c Use type in same module (Maven requirement). 2006-11-17 03:18:07 +00:00
Ben Alex 197a011ac5 Relocate resource files to comply with Maven directory conventions. 2006-11-17 03:06:30 +00:00
Ben Alex aff04805e7 Prepare for 1.0.3. 2006-11-17 02:58:17 +00:00
Ben Alex 3e3db43b37 SEC-239: New ACL module. 2006-11-17 02:29:28 +00:00
Ben Alex 44cae6b2ee SEC-274: Correctly handle bridge methods, using AnnotationUtils when on classpath. 2006-11-17 02:17:45 +00:00
Ben Alex 1081c267d9 SEC-239: New ACL module. 2006-11-17 02:03:23 +00:00
Ben Alex 9f512c384e SEC-239: New ACL module. 2006-11-17 02:01:21 +00:00
Ben Alex 2984913051 SEC-393: More elegantly deal with setProviders(List) type safety enforcement. 2006-11-16 02:15:43 +00:00
Carlos Sanchez 5e819af782 SEC-388: Upgrade other Spring dependencies to 1.2.8. 2006-11-15 22:54:54 +00:00
Ben Alex 0044400ca6 SEC-388: Ensure Acegi Security 1.0.3 operates against Spring 1.2.8. 2006-11-14 22:09:49 +00:00
Ben Alex 1b4a098760 SEC-354: Add label-based voter. 2006-11-14 22:07:36 +00:00
Ben Alex 4d166a6867 SEC-333: Error in last commit, should default to regexp processor, not Ant Path processor, in the case of empty or null strings. 2006-11-14 21:52:51 +00:00
Ben Alex 780130d0f3 SEC-333: Eliminate dependecy on ORO when Ant Paths being used instead of Regular Expressions. 2006-11-14 20:55:24 +00:00
Ben Alex 89e95310f3 Version number. 2006-11-14 06:03:01 +00:00
Ben Alex 775840a565 SEC-374: Allow GrantedAuthority[]s assigned to switched user identity to be filtered. 2006-11-14 05:49:56 +00:00
Ben Alex 13ef76801f Add Sanjiv Jivan's blod entry. 2006-11-14 04:58:37 +00:00
Ben Alex b941577198 SEC-274: Reproduce bug report. 2006-11-14 04:26:12 +00:00
Ben Alex f5ce0250b4 SEC-310: Add AbstractProcessingFilter.getAuthenticationDetailsSource(). 2006-11-14 03:30:04 +00:00
Ben Alex e179574077 Fix JavaDocs. 2006-11-14 03:19:16 +00:00
Ben Alex 508966f0c7 SEC-313: Add integration test for Contacts. 2006-11-14 03:18:42 +00:00
Ben Alex 84671f9d68 SEC-382: Clean up resource bundle errors. 2006-11-14 02:30:00 +00:00
Ben Alex 8dda52eeaa SEC-322: Workaround bug in WebSphere. 2006-11-14 02:21:27 +00:00
Ben Alex 5640eb0511 SEC-378: Use trim instead of replacement for space removal. 2006-11-14 01:55:44 +00:00
Ben Alex ad6c501379 SEC-360: Minor correction in patch applied yesterday. 2006-11-14 01:09:35 +00:00
Ben Alex 2a65d386d5 SEC-384: Remove Commons-Lang dependency. 2006-11-14 00:59:17 +00:00
Ben Alex 59bf8602d2 SEC-356: Add cloneFromHttpSession property. 2006-11-14 00:43:00 +00:00
Ben Alex 5911234f65 SEC-359: Logout even if not logged in. 2006-11-13 06:05:28 +00:00
Ben Alex fa6b4480b1 SEC-360: Provide server side forward option instead of redirection. 2006-11-13 00:17:07 +00:00
Ben Alex f0ae6f53a7 SEC-327: Add includeDetailsObject property. 2006-11-12 23:55:50 +00:00
Ben Alex f28ce39bde SEC-365: Provide an alwaysRemember property, together with an abstract method so subclasses can determine custom behaviour. 2006-11-12 23:28:57 +00:00
Ben Alex 71eba94cf2 SEC-371: Use AbstractTicketValidator for logger. 2006-11-12 23:10:09 +00:00
Ben Alex 380daacd15 SEC-383: Correct missing comma in acl_permission create statement. 2006-11-12 23:03:16 +00:00
Ben Alex 0f517cb8e2 SEC-375: Publish AuthorizationFailureEvent event when AccessDeniedException thrown by AfterInvocationProvider. 2006-11-12 22:06:37 +00:00
Ben Alex b8d0722251 SEC-367: Added clarification of immutability contract. 2006-11-12 21:36:52 +00:00
Ben Alex 43dbe6c991 SEC-364: Fix context path handling. 2006-11-12 21:31:31 +00:00
Ben Alex 5ef0a1a4e6 Remove Domain sub-project. 2006-11-12 21:15:22 +00:00
Luke Taylor 4c8029d234 Corrected coverage link 2006-11-02 22:13:30 +00:00
Luke Taylor 61c786013d Added apt version of standalone.html 2006-10-30 19:36:47 +00:00
Luke Taylor 06ef71f44e Remove section on checking out code using maven. Plain subverson is much easier. 2006-10-30 18:33:15 +00:00
Luke Taylor 7969510d95 removed html versions of files converted to apt 2006-10-29 20:11:09 +00:00
Luke Taylor 6445be9532 Converted petclinic tutorial file to apt. 2006-10-29 20:08:26 +00:00
Luke Taylor efc8a98a4c Converted "downloads.html" file to apt. 2006-10-29 18:50:57 +00:00
Luke Taylor 368fc4372a Converted "suggested steps" file to apt. Removed upgrade links prior to 0.7. 2006-10-29 18:36:35 +00:00
Luke Taylor 5005e9c973 Remove index.xml (again?) 2006-10-28 19:26:32 +00:00
Luke Taylor 4d46213a59 removed index.html in favour of generated one 2006-10-28 17:21:44 +00:00
Luke Taylor 7852a830a3 Initial attempt at converting site sources to be mvn 2 compatible. 2006-10-28 16:06:36 +00:00
Carlos Sanchez 10d6859dad Added ACL table SQL for some databases 2006-10-17 22:24:57 +00:00
Ben Alex 172026f875 SEC-377: Remove Commons Lang dependency. 2006-10-14 00:17:19 +00:00
Ben Alex c89582652a Add Alan Stewart. 2006-10-14 00:14:13 +00:00
Ben Alex b1ac45320f Version change. 2006-10-08 08:39:39 +00:00
Ben Alex c292826475 SEC-373: Add byte array encryption/decryption support. 2006-10-07 09:45:51 +00:00
Carlos Sanchez 59572e2168 [maven-release-plugin] prepare for next development iteration 2006-10-04 22:07:51 +00:00
Carlos Sanchez 36fdbe0c97 [maven-release-plugin] prepare release acegi-security-webwork-0.1 2006-10-04 22:07:18 +00:00
Carlos Sanchez 52b10d6d34 Use latest parent 2006-10-04 22:06:03 +00:00
Carlos Sanchez b7595a6165 Bump to next version 2006-10-04 22:05:33 +00:00
Carlos Sanchez 02526b1461 Use latest release 2006-10-04 22:03:16 +00:00
Ben Alex 335e2c9848 Make ready for 1.0.3-SNAPSHOT. 2006-10-04 10:55:31 +00:00
Ben Alex 459b1d1cde Prepare to release 1.0.2. 2006-10-04 08:57:11 +00:00
Ben Alex bcd1c3eeef Fix URL. 2006-10-04 08:55:59 +00:00
Ben Alex 23e2338800 Prepare to release 1.0.2. 2006-10-04 08:55:13 +00:00
Ben Alex d150b1aad2 Note that JAR files are no longer signed. 2006-10-04 08:35:19 +00:00
Ben Alex 21dd050d7b SEC-348: Limit Basic automatic reauthentication scope to UsernamePasswordAuthenticationToken (specifically avoid CasAuthenticationToken). 2006-09-29 08:41:25 +00:00
Ben Alex ab7816db41 SEC-8: Removed from sandbox as development will continue via code drops in the JIRA task. 2006-09-29 08:13:33 +00:00
Ben Alex d2fb473a4e Formatting only. 2006-09-29 07:33:45 +00:00
Ben Alex 49a2de8f0f SEC-366: Initial commit. 2006-09-29 07:29:13 +00:00
Ben Alex cc03675776 SEC-340: Invalidate HttpSession on logout. 2006-09-29 06:45:40 +00:00
Scott McCrory db96650d99 SEC-319: Reverted to 1.0.1 version to delay these changes to 1.1.0, based on small breakage of backward compatability. 2006-09-23 19:48:39 +00:00
Ben Alex ef6d6cd03e SEC-347: Describe requirements for login page when using secure channels. 2006-09-23 06:20:29 +00:00
Ben Alex 2fdf96e7cf Change Ben's blog URL. 2006-09-18 02:16:31 +00:00
Carlos Sanchez 558fd5d75d Add scm info because we don't use artifactid as folder name 2006-09-17 21:06:22 +00:00
Ben Alex 0c7a342fdf Add sandbox contains ACLs. 2006-09-16 01:31:14 +00:00
Ben Alex c5aa605068 More JavaDocs as per discussion on acegisecurity-developer list 16 Sep 06. 2006-09-15 22:25:31 +00:00
Ben Alex 55b7b2129d Add Plazma. 2006-09-15 10:53:40 +00:00
Ben Alex b0056568f0 SEC-338: Serializable and serialVersionUID missing for Authentication-related objects. 2006-09-15 08:38:11 +00:00
Ben Alex 7313d5def0 SEC-324: Ensure IllegalStateException no longer occurs. 2006-09-15 07:55:57 +00:00
Ben Alex 324789d544 SEC-311: Must observe symmetry requirement of Object.equals(Object) contract. 2006-09-15 06:27:45 +00:00
Ben Alex 9e3ce85dd5 SEC-330: Make UserMap work with UserDetails, not User concrete class. 2006-09-15 03:47:17 +00:00
Ben Alex f0b259a32e SEC-349: GrantedAuthority constructor argument can be null. 2006-09-15 03:42:11 +00:00
Ben Alex 58d3f0c56f SEC-290: Correct bug with generation of SimpleMethodInvocation. 2006-09-15 03:38:36 +00:00
Ben Alex 5364db2c27 SEC-328: Avoid unnecessarily hitting backend a second time, if the cache wasn't used in first place. 2006-09-15 03:36:51 +00:00
Ben Alex 53beadb7bf SEC-290: Correct bug with generation of SimpleMethodInvocation. 2006-09-15 03:27:26 +00:00
Ben Alex 03df6a90eb SEC-293: Modified collection remove logic to use removeList. 2006-09-15 03:20:08 +00:00
Ben Alex e0108f3982 SEC-283: Docs correction for ConcuressSessionFilter. 2006-09-15 03:13:13 +00:00
Ben Alex d4b4cd68d2 Remove old sandbox locations. NB: New locations NOT added back in due to missing import errors. 2006-09-15 03:10:21 +00:00
Ben Alex 1292420476 SEC-311: Must observe symmetry requirement of Object.equals(Object) contract. 2006-09-15 03:09:05 +00:00
Ray Krueger cf91104b69 Made parameters case-insensitive 2006-09-14 20:47:17 +00:00
Ray Krueger 6779d97546 Made parameters case-insensitive 2006-09-14 20:39:37 +00:00
Carlos Sanchez 757062e8f9 Initialization of exceptionMappings was broken in last commit 2006-09-13 08:20:08 +00:00
Ben Alex 5e56d6f6ea Add JTrac. 2006-09-08 22:53:49 +00:00
Carlos Sanchez 30f6871124 Take another apporach and throw all unhandled exceptions wrapped in a ServletException 2006-09-06 17:18:36 +00:00
Carlos Sanchez e8de53b87c Add more info about the problem 2006-09-06 17:12:17 +00:00
Carlos Sanchez 6c0ddbfa9d Add WebWork support to handle Acegi exceptions 2006-09-06 16:54:18 +00:00
Carlos Sanchez 881d50e2a6 Split sandbox in subprojects 2006-09-06 16:37:28 +00:00
Carlos Sanchez 87c1117b47 Remove outdated m1 build 2006-09-06 16:36:52 +00:00
Carlos Sanchez 1554ae4cc6 Splitting sandbox in subpojects 2006-09-06 16:29:50 +00:00
Carlos Sanchez 3226a90fcd Split sandbox in subprojects 2006-09-06 16:27:39 +00:00
Ray Krueger 73cea493c6 Fixing unit test issues 2006-09-06 03:11:13 +00:00
Ray Krueger d88adf3f9e Fixed Java 1.3 incompatible IllegalStateException constructor.
Also fixed a potential NPE in getAccessibleField
2006-09-06 03:02:29 +00:00
Carlos Sanchez 3c223fd193 Explicitly set source plugin version, 2.0.1 seems to have a problem 2006-09-04 22:44:58 +00:00
Carlos Sanchez 4d070eab25 Add setAuthoritiesAsString to UserAttribute 2006-09-04 21:54:15 +00:00
Luke Taylor 000f9ab7ac SEC-321: truncate from first question mark, not last. 2006-09-03 22:12:13 +00:00
Ben Alex 9769394c92 Fixes to new ACL implementation. Thanks to Nathan Sarr. 2006-08-30 22:15:29 +00:00
Ben Alex a33ce2e7f0 Add Tapestry. 2006-08-30 11:57:10 +00:00
Ben Alex e5fd83624d Add Grails. 2006-08-30 08:30:26 +00:00
Ben Alex 265b719a39 Add Grails link. 2006-08-30 07:50:15 +00:00
Luke Taylor 557cf75745 Moved to branch 2006-08-28 22:03:20 +00:00
Luke Taylor 4e65b24253 SEC-245: Add mapPassword method to allow customized translation of password attribute. 2006-08-28 20:58:26 +00:00
Luke Taylor 1149da6137 Changed test server details. 2006-08-28 20:10:34 +00:00
Luke Taylor 5b414ddef5 Remove duplicate classes. 2006-08-25 19:16:41 +00:00
Luke Taylor e2a83b6822 Changed version of spring-mock to 1.2.7 for consistency. 2006-08-25 16:23:27 +00:00
Luke Taylor 308212febc Moved ppolicy test to correct package. 2006-08-25 16:18:58 +00:00
Luke Taylor 760a858be6 An oracle OID specific version of BindAuthenticator which parses password policy OID exception messages. 2006-08-25 16:17:12 +00:00
Luke Taylor 139d8c2f65 Experimental UserDetailsManager interface and some ldap implementation classes. 2006-08-25 16:14:50 +00:00
Luke Taylor 1b66467f70 Added ldaptemplate, ehcache and spring-mock dependencies. 2006-08-25 16:13:44 +00:00
Luke Taylor 54fb402e60 added package for password-policy specific classes and an ldaptemplate compatible context factory. 2006-08-25 16:12:26 +00:00
Luke Taylor 57a8d2adb3 Added handleBindException method to allow subclasses to inspect the reason for bind failure. 2006-08-25 16:06:20 +00:00
Luke Taylor dc13f25dee Tidied up formatting. 2006-08-25 16:04:27 +00:00
Luke Taylor 8dd1177c02 Added property to force use of LdapContext instead of DirContext 2006-08-25 16:03:50 +00:00
Luke Taylor 92dcf694b4 added createTarget method on Essence class to allow subclassing. 2006-08-25 15:32:39 +00:00
Luke Taylor b5cbc977e1 Javadoc correction 2006-08-24 10:56:26 +00:00
Luke Taylor 3889894d16 Added extra mapping of OperationNotSupportedException to BadCredentialsException as some servers return a 53 code (unwilling to perform) when attempting a bind (e.g. is password has expired). This shouldn't be treated as an outright failure. 2006-08-24 10:32:38 +00:00
Luke Taylor 67fcf426eb Close returned context in nameExists method 2006-08-24 10:10:24 +00:00
Luke Taylor e96fee6ec1 Updated apacheds version to RC3 and slf4j to 1.0.1 2006-08-24 10:07:39 +00:00
Carlos Sanchez 27d2db9e22 Ensure that array of valid permissions can't be modified outside the class 2006-08-22 17:57:18 +00:00
Carlos Sanchez 38ec0f0d30 SEC-286: Reverted rev# 1588 as build fails without log4j (class not found exception) 2006-08-22 16:17:46 +00:00
Carlos Sanchez 69ec903088 Add MethodDefinitionSourceMapping for easier configuration 2006-08-22 16:02:44 +00:00
Carlos Sanchez 0298851ca3 Allow setting ACLs by its name 2006-08-22 16:01:34 +00:00
Carlos Sanchez 3487da0e85 Added javadoc 2006-08-22 15:53:41 +00:00
Carlos Sanchez 773a0d6969 Add clirr plugin and build test-jar 2006-08-22 15:45:18 +00:00
Luke Taylor 3498b36c14 SEC-285: Removed duplicate commons-lang dependency from pom.xml 2006-08-19 20:03:58 +00:00
Luke Taylor 5de0939b03 SEC-334: Incorrect filter name. 2006-08-19 19:39:45 +00:00
Scott McCrory 8d3a2b42d9 SEC-319: Improvements to Siteminder integration: Create its own authentication provider & reeval strategy. Note that documentation not yet complete, but code is functional, test-covered and validated in a Siteminder environment. 2006-07-27 01:13:46 +00:00
Luke Taylor 52a167acfa SEC-286: removed log4j dep as it is in the parent pom and tests run fine without it.. 2006-07-25 23:53:42 +00:00
Luke Taylor 1f89d153b2 SEC-312: wrong chapter number in Chinese book. 2006-07-25 23:07:58 +00:00
Carlos Sanchez f7cb31a301 Fix broken test 2006-07-20 18:43:58 +00:00
Carlos Sanchez 9a337d2fea Removed default constructors added in rev# 1573 2006-07-20 13:15:55 +00:00
Carlos Sanchez 85a67c6b7c Use better repository ids 2006-07-18 17:34:27 +00:00
Luke Taylor 4930657e57 Remove typo in method name "getAuthoritiesPopulator" 2006-07-16 20:17:20 +00:00
Scott McCrory 442c51bb30 SEC-318: Rename AuthenticationDao to UserDetailsService in local variables and logging messages 2006-07-15 15:18:51 +00:00
Ray Krueger d485e30fd5 SavedCookieTest was renamed to SavedCookieTests 2006-07-12 10:33:14 +00:00
Ray Krueger ca863ce4f7 http://opensource.atlassian.com/projects/spring/browse/SEC-308
Headers should remain case-insensitive.
2006-07-12 10:25:32 +00:00
Carlos Sanchez 91799c9290 Added missing resources 2006-07-11 21:42:42 +00:00
Carlos Sanchez 156af5b8b6 Added missing tld and notice file to jar 2006-07-11 18:54:04 +00:00
Carlos Sanchez e5c2ef2d98 Update TLD uri to new acegisecurity.org location 2006-07-11 18:47:47 +00:00
Carlos Sanchez 5d15856ccc Use 1.1-SNAPSHOT as parent version 2006-07-11 18:27:36 +00:00
Carlos Sanchez 288fdb3df8 Fixed M2 pom 2006-07-11 18:22:21 +00:00
Carlos Sanchez 94a9acedad Added checks to ensure object is properly initialized 2006-07-10 11:48:35 +00:00
Carlos Sanchez 488abe58fb Added default constructor for easier use 2006-07-10 11:24:18 +00:00
Carlos Sanchez 80c1ae3bde fix problems when not loaded through Spring context 2006-07-09 22:08:21 +00:00
Carlos Sanchez 00b73e8331 Fix failing tests keeping old behaviour. 2006-07-06 17:56:50 +00:00
Carlos Sanchez 46af400466 Added FilterInvocationDefinition interface to unify FilterInvocationDefinitionSource and FilterInvocationDefinitionMap 2006-07-06 17:05:08 +00:00
Carlos Sanchez 9e87bd6789 Add javadocs 2006-07-06 17:03:48 +00:00
Carlos Sanchez aa52124d72 Simplify configuration of FilterInvocationDefinitionMap 2006-07-05 22:00:21 +00:00
Carlos Sanchez 9560636380 Simplify configuration of FilterInvocationDefinitionMap 2006-07-05 20:58:50 +00:00
Carlos Sanchez 9d539a13d9 Use accessor instead of field 2006-07-05 20:03:52 +00:00
Carlos Sanchez 0edb75d4aa Added setUsers and setAuthorities for easier configuration 2006-07-05 16:16:13 +00:00
Carlos Sanchez 41f7bb3755 Improve javadoc formatting 2006-07-05 16:00:51 +00:00
Carlos Sanchez 27de814d54 Prevent NullPointerException when not loaded from application context 2006-07-05 15:59:17 +00:00
Carlos Sanchez d847772c81 Prevent NullPointerException when not loaded from application context 2006-07-05 15:58:20 +00:00
Luke Taylor ae55e04522 SEC-297: Stop prepending of context path to full url default targets. Also added more stringent checks on format of injected defaultTargetUrl property. 2006-06-27 23:26:25 +00:00
Luke Taylor 55f7960e5c SEC-292: Corrected ldap package names 2006-06-27 21:48:49 +00:00
Carlos Sanchez 2c1ba76027 Bump version to 1.1-SNAPSHOT 2006-06-22 17:51:32 +00:00
Carlos Sanchez 18c6838bec [maven-release-plugin] prepare for next development iteration 2006-06-22 17:29:52 +00:00
Carlos Sanchez c7bcbe1b35 [maven-release-plugin] prepare release release_1_0_1 2006-06-22 17:27:29 +00:00
Carlos Sanchez f2ff448071 Fork tests 2006-06-22 16:56:09 +00:00
Carlos Sanchez 4a48cd4425 Set pmd jdk to 1.5 2006-06-22 16:55:22 +00:00
Carlos Sanchez d332b5ce18 Maven 2 improvements, added a bunch of reports 2006-06-19 23:24:06 +00:00
Carlos Sanchez e9b961d0f8 Apache snapshot repo was moved 2006-06-16 17:49:55 +00:00
Carlos Sanchez 9255004495 Prepare release of 1.0.1 2006-06-16 17:48:05 +00:00
Carlos Sanchez 4e612922ac SEC-281: Go back to spring 1.2.7 to prevent backwards compatibility issues 2006-06-16 17:25:05 +00:00
Luke Taylor a2c3635d78 Moved class to test treee 2006-06-15 00:41:53 +00:00
Luke Taylor 552c275e8f Accidentally checked into source tree rather than test source 2006-06-15 00:37:18 +00:00
Luke Taylor aaf51c4bee Added test for non-String role. 2006-06-14 23:20:51 +00:00
Luke Taylor 49da801096 SEC-303: Check from null role attribute in LdapUserDetailsMapper 2006-06-14 22:44:39 +00:00
Luke Taylor eb3e954ae4 Added chained append call in toString method 2006-06-14 21:46:21 +00:00
Luke Taylor b0caa72e80 Added template method for role creation, as requested in the forum. 2006-06-13 13:18:45 +00:00
Luke Taylor 7475906218 Remove Javadoc errors 2006-06-12 22:32:59 +00:00
Luke Taylor 18680e8fab Remove Jalopy mistakes 2006-06-12 22:31:10 +00:00
Ray Krueger cada23f57d Synchronized MockFilterConfig uses for Spring 1.2.6 and 1.2.8 2006-06-11 01:20:29 +00:00
Ray Krueger fa3c61b19b Call to getCookies() should return Cookies, not SavedCookies 2006-06-11 01:19:44 +00:00
Luke Taylor 88825089a7 Removed "final" from getGroupMembershipRoles 2006-06-07 13:31:11 +00:00
Luke Taylor 2a7caff95f SEC-295: Changed to use getDefaultTargetUrl() accessor internally rather than accessing property directly. Allows for overriding method to supply different Urls. 2006-06-04 15:14:33 +00:00
Ray Krueger 9fd0bbd694 Added Serializable check just to be sure... 2006-06-03 13:40:39 +00:00
Ray Krueger 1a9629b197 http://opensource.atlassian.com/projects/spring/browse/SEC-289
Wraps disassembles cookies into a SavedCookie that is serializable
2006-06-03 13:36:51 +00:00
Ben Alex f7020755be SEC-291: Avoid unnecessary creation of SecurityContextHolderStrategy. 2006-06-01 14:02:56 +00:00
Luke Taylor da780e4567 Tidy up XML formatting in comment 2006-05-31 21:56:16 +00:00
Luke Taylor 9f41b9f470 Wrap any DataAccessExceptions thrown by the Ldaptemplate with AuthenticationServiceFailureExceptions 2006-05-31 21:46:16 +00:00
Luke Taylor 5d7a75a421 SEC-284: Removed allowEmptyPassword flag.. 2006-05-31 20:12:12 +00:00
Luke Taylor d2ee383e06 Changed to reject empty passwords by default. 2006-05-31 18:22:05 +00:00
Luke Taylor ee50d6e334 SEC-281: Modified to use Spring 1.2 compatible exception class for incorrect search results size. 2006-05-31 16:54:27 +00:00
Luke Taylor 02e7bbb982 SEC-284: added allowEmptyPasswords property with default value "true" 2006-05-31 15:00:59 +00:00
Ben Alex 7957d54d67 SEC-282: Tutorial for securing Petclinic using Acegi Security. 2006-05-31 07:40:45 +00:00
Ray Krueger 00620b6992 http://opensource.atlassian.com/projects/spring/browse/SEC-96
Refactored Digest encoding for better support of all MessageDigest algorithms, such as the SHA family.
2006-05-31 03:03:18 +00:00
Carlos Sanchez 35093e09f6 Bump version to 1.1.0-SNAPSHOT 2006-05-31 00:52:26 +00:00
Scott McCrory 0eab6903e8 SEC-280: Fixed Eclipse classpath to correctly point to Maven's Spring Framework jars 2006-05-30 22:45:22 +00:00
Luke Taylor b6282423e3 Added info on Ldap changes and fixed HTML. 2006-05-30 20:37:29 +00:00
361 changed files with 14966 additions and 10126 deletions
+19 -22
View File
@@ -1,27 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="samples/attributes/src/main/java"/>
<classpathentry kind="src" path="samples/acegifier/src/test/resources"/>
<classpathentry kind="src" path="samples/acegifier/src/main/resources"/>
<classpathentry kind="src" path="core/src/main/java"/>
<classpathentry kind="src" path="core/src/main/resources"/>
<classpathentry kind="src" path="core/src/test/java"/>
<classpathentry kind="src" path="core/src/test/resources"/>
<classpathentry kind="src" path="sandbox/other/src/main/java"/>
<classpathentry kind="src" path="sandbox/other/src/test/java"/>
<classpathentry kind="src" path="samples/contacts/src/main/java"/>
<classpathentry kind="src" path="samples/contacts/src/main/resources"/>
<classpathentry kind="src" path="samples/contacts/src/test/java"/>
<classpathentry kind="src" path="samples/contacts/src/test/resources"/>
<classpathentry kind="src" path="samples/acegifier/src/main/java"/>
<classpathentry kind="src" path="samples/acegifier/src/main/resources"/>
<classpathentry kind="src" path="samples/acegifier/src/test/java"/>
<classpathentry kind="src" path="domain/src/main/java"/>
<classpathentry kind="src" path="domain/src/main/resource"/>
<classpathentry kind="src" path="domain/src/test/java"/>
<classpathentry kind="src" path="domain/src/test/resources"/>
<classpathentry kind="src" path="adapters/catalina/src/main/resources"/>
<classpathentry kind="src" path="samples/acegifier/src/test/resources"/>
<classpathentry kind="src" path="samples/attributes/src/main/java"/>
<classpathentry kind="src" path="samples/attributes/src/main/resources"/>
<classpathentry kind="src" path="samples/attributes/src/test/java"/>
<classpathentry kind="src" path="adapters/cas/src/test/resources"/>
<classpathentry kind="src" path="adapters/cas/src/main/resources"/>
<classpathentry kind="src" path="core/src/main/resources"/>
<classpathentry kind="src" path="core/src/test/resources"/>
<classpathentry kind="src" path="samples/contacts/src/main/java"/>
<classpathentry kind="src" path="sandbox/src/main/java"/>
<classpathentry kind="src" path="sandbox/src/test/java"/>
<classpathentry kind="src" path="adapters/cas/src/main/java"/>
<classpathentry kind="src" path="adapters/cas/src/test/java"/>
<classpathentry kind="src" path="adapters/catalina/src/main/java"/>
<classpathentry kind="src" path="adapters/catalina/src/main/resources"/>
<classpathentry kind="src" path="adapters/catalina/src/test/java"/>
<classpathentry kind="src" path="adapters/jboss/src/main/java"/>
<classpathentry kind="src" path="adapters/jboss/src/test/java"/>
@@ -29,12 +30,10 @@
<classpathentry kind="src" path="adapters/jetty/src/test/java"/>
<classpathentry kind="src" path="adapters/resin/src/main/java"/>
<classpathentry kind="src" path="adapters/resin/src/test/java"/>
<classpathentry kind="src" path="core/src/main/java"/>
<classpathentry kind="src" path="core/src/test/java"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="MAVEN_REPO/com.caucho/jars/resin-3.0.9.jar"/>
<classpathentry sourcepath="/MAVEN_REPO/springframework/src/spring-2.0-m2.zip" kind="var" path="MAVEN_REPO/springframework/jars/spring-2.0-m2.jar"/>
<classpathentry sourcepath="/MAVEN_REPO/springframework/src/spring-2.0-m2.zip" kind="var" path="MAVEN_REPO/springframework/jars/spring-mock-2.0-m2.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/org.springframework/jars/spring-1.2.8.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/org.springframework/jars/spring-mock-1.2.8.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/aopalliance/jars/aopalliance-1.0.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/aspectj/jars/aspectjrt-1.2.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/cas/jars/casclient-2.0.11.jar"/>
@@ -42,7 +41,7 @@
<classpathentry kind="var" path="MAVEN_REPO/commons-codec/jars/commons-codec-1.3.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/commons-collections/jars/commons-collections-3.1.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/commons-logging/jars/commons-logging-1.0.4.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/hsqldb/jars/hsqldb-1.7.3.0.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/hsqldb/jars/hsqldb-1.8.0.4.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/oro/jars/oro-2.0.8.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/javax.servlet/jars/servlet-api-2.4.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/tomcat/jars/catalina-4.1.9.jar"/>
@@ -53,16 +52,15 @@
<classpathentry kind="var" path="MAVEN_REPO/ehcache/jars/ehcache-1.1.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/javax.servlet/jars/jsp-api-2.0.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/hibernate/jars/hibernate-3.0.3.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/commons-lang/jars/commons-lang-2.0.jar"/>
<classpathentry sourcepath="DIST_BASE/commons-beanutils-1.6.1-src/src/java" kind="var" path="MAVEN_REPO/commons-beanutils/jars/commons-beanutils-1.6.1.jar"/>
<classpathentry kind="src" path="samples/contacts-tiger/src/main/java"/>
<classpathentry kind="src" path="core-tiger/src/main/java"/>
<classpathentry kind="src" path="core-tiger/src/test/java"/>
<classpathentry kind="src" path="core-tiger/src/main/resources"/>
<classpathentry kind="src" path="core-tiger/src/test/java"/>
<classpathentry kind="src" path="core-tiger/src/test/resources"/>
<classpathentry kind="src" path="samples/annotations/src/main/java"/>
<classpathentry kind="src" path="samples/annotations/src/main/resources"/>
<classpathentry kind="src" path="samples/annotations/src/test/java"/>
<classpathentry kind="src" path="samples/contacts-tiger/src/main/java"/>
<classpathentry kind="var" path="MAVEN_REPO/org.samba.jcifs/jars/jcifs-1.2.6.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/dom4j/jars/dom4j-1.6.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/xerces/jars/xercesImpl-2.6.2.jar"/>
@@ -76,7 +74,6 @@
<classpathentry kind="var" path="MAVEN_REPO/org.apache.directory.shared/jars/shared-ldap-0.9.5.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/antlr/jars/antlr-2.7.2.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/ldapsdk/jars/ldapsdk-4.1.jar"/>
<classpathentry sourcepath="/MAVEN_REPO/springframework/src/spring-2.0-m2.zip" kind="var" path="MAVEN_REPO/springframework/jars/spring-hibernate3-2.0-m2.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/cas/jars/cas-server-3.0.4.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/net.sourceforge.retroweaver/jars/retroweaver-1.0fcs.jar"/>
<classpathentry kind="var" path="MAVEN_REPO/taglibs/jars/standard-1.0.6.jar"/>
+3 -6
View File
@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<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">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security-adapters</artifactId>
<version>1.0.0</version>
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>acegi-security-cas</artifactId>
<name>Acegi Security System for Spring - CAS adapter</name>
@@ -22,4 +19,4 @@
<version>2.0.12</version>
</dependency>
</dependencies>
</project>
</project>
+3 -6
View File
@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<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">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security-adapters</artifactId>
<version>1.0.0</version>
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>acegi-security-catalina</artifactId>
<name>Acegi Security System for Spring - Catalina adapter</name>
@@ -17,4 +14,4 @@
<version>4.1.9</version>
</dependency>
</dependencies>
</project>
</project>
+3 -6
View File
@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<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">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security-adapters</artifactId>
<version>1.0.0</version>
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>acegi-security-jboss</artifactId>
<name>Acegi Security System for Spring - JBoss adapter</name>
@@ -23,4 +20,4 @@
<scope>provided</scope>
</dependency>
</dependencies>
</project>
</project>
+3 -6
View File
@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<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">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security-adapters</artifactId>
<version>1.0.0</version>
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>acegi-security-jetty</artifactId>
<name>Acegi Security System for Spring - Jetty adapter</name>
@@ -17,4 +14,4 @@
<version>4.2.22</version>
</dependency>
</dependencies>
</project>
</project>
@@ -31,6 +31,7 @@ import org.mortbay.http.UserPrincipal;
public class JettyAcegiUserToken extends AbstractAdapterAuthenticationToken implements UserPrincipal {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private String password;
private String username;
+3 -6
View File
@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<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">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security-parent</artifactId>
<version>1.0.0</version>
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>acegi-security-adapters</artifactId>
<name>Acegi Security System for Spring - Adapters</name>
@@ -30,4 +27,4 @@
<module>jetty</module>
<module>resin</module>
</modules>
</project>
</project>
+1 -1
View File
@@ -13,7 +13,7 @@
<dependency>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security</artifactId>
<version>1.0.0</version>
<version>1.0.3</version>
<type>jar</type>
<url>http://acegisecurity.org</url>
<properties>
+3 -6
View File
@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<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">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security-adapters</artifactId>
<version>1.0.0</version>
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>acegi-security-resin</artifactId>
<name>Acegi Security System for Spring - Resin adapter</name>
@@ -23,4 +20,4 @@
<scope>provided</scope>
</dependency>
</dependencies>
</project>
</project>
+23 -7
View File
@@ -1,15 +1,19 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<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">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security-parent</artifactId>
<version>1.0.0</version>
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>acegi-security-tiger</artifactId>
<name>Acegi Security System for Spring - Java 5 (Tiger)</name>
<scm>
<connection>scm:svn:https://svn.sourceforge.net/svnroot/acegisecurity/trunk/acegisecurity/core-tiger</connection>
<developerConnection>scm:svn:https://svn.sourceforge.net/svnroot/acegisecurity/trunk/acegisecurity/core-tiger</developerConnection>
<url>http://svn.sourceforge.net/viewcvs.cgi/acegisecurity/trunk/acegisecurity/core-tiger/</url>
</scm>
<dependencies>
<dependency>
<groupId>org.acegisecurity</groupId>
@@ -19,9 +23,10 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>1.2.6</version>
<version>1.2.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
@@ -34,4 +39,15 @@
</plugin>
</plugins>
</build>
</project>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<configuration>
<targetJdk>1.5</targetJdk>
</configuration>
</plugin>
</plugins>
</reporting>
</project>
+1 -1
View File
@@ -14,7 +14,7 @@
<dependency>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security</artifactId>
<version>1.0.0</version>
<version>1.0.3</version>
<type>jar</type>
</dependency>
</dependencies>
@@ -12,13 +12,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.annotation;
import org.acegisecurity.SecurityConfig;
import org.springframework.metadata.Attributes;
import org.springframework.util.ClassUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@@ -43,6 +44,8 @@ import java.util.Set;
* &lt;/bean></pre></p>
* <p>These security annotations are similiar to the Commons Attributes approach, however they are using Java 5
* language-level metadata support.</p>
* <p>This class should be used with Spring 2.0 or above, as it relies upon utility classes in Spring 2.0 for
* correct introspection of annotations on bridge methods.</p>
*
* @author Mark St.Godard
* @version $Id$
@@ -96,7 +99,19 @@ public class SecurityAnnotationAttributes implements Attributes {
public Collection getAttributes(Method method) {
Set<SecurityConfig> attributes = new HashSet<SecurityConfig>();
for (Annotation annotation : method.getAnnotations()) {
Annotation[] annotations = null;
// Use AnnotationUtils if in classpath (ie Spring 1.2.9+ deployment)
try {
Class clazz = ClassUtils.forName("org.springframework.core.annotation.AnnotationUtils");
Method m = clazz.getMethod("getAnnotations", new Class[] {Method.class});
annotations = (Annotation[]) m.invoke(null, new Object[] {method});
} catch (Exception ex) {
// Fallback to manual retrieval if no AnnotationUtils available
annotations = method.getAnnotations();
}
for (Annotation annotation : annotations) {
// check for Secured annotations
if (annotation instanceof Secured) {
Secured attr = (Secured) annotation;
@@ -0,0 +1,28 @@
package org.acegisecurity.annotation;
/**
*
* @author Joe Scalise
*/
public class BusinessServiceImpl<E extends Entity> implements BusinessService {
@Secured({"ROLE_USER"})
public void someUserMethod1() {
}
@Secured({"ROLE_USER"})
public void someUserMethod2() {
}
@Secured({"ROLE_USER", "ROLE_ADMIN"})
public void someUserAndAdminMethod() {
}
@Secured({"ROLE_ADMIN"})
public void someAdminMethod() {
}
public E someUserMethod3(final E entity) {
return entity;
}
}
@@ -0,0 +1,28 @@
package org.acegisecurity.annotation;
/**
*
* @author Joe Scalise
*/
public class Department extends Entity {
//~ Instance fields ========================================================
private boolean active = true;
//~ Constructors ===========================================================
public Department(String name) {
super(name);
}
//~ Methods ================================================================
public boolean isActive() {
return this.active;
}
void deactive() {
this.active = true;
}
}
@@ -0,0 +1,11 @@
package org.acegisecurity.annotation;
/**
*
* @author Joe Scalise
*/
public interface DepartmentService extends BusinessService {
@Secured({"ROLE_USER"})
Department someUserMethod3(Department dept);
}
@@ -0,0 +1,12 @@
package org.acegisecurity.annotation;
/**
* @author Joe Scalise
*/
public class DepartmentServiceImpl extends BusinessServiceImpl <Department> implements DepartmentService {
@Secured({"ROLE_ADMIN"})
public Department someUserMethod3(final Department dept) {
return super.someUserMethod3(dept);
}
}
@@ -0,0 +1,11 @@
package org.acegisecurity.annotation;
/**
* Class to act as a superclass for annotations testing.
*
* @author Ben Alex
*
*/
public class Entity {
public Entity(String someParameter) {}
}
@@ -12,13 +12,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.annotation;
import junit.framework.TestCase;
import org.acegisecurity.SecurityConfig;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.metadata.Attributes;
import java.lang.reflect.Field;
@@ -31,12 +33,14 @@ import java.util.Collection;
* Tests for {@link org.acegisecurity.annotation.SecurityAnnotationAttributes}
*
* @author Mark St.Godard
* @version $Revision$
* @author Joe Scalise
* @version $Id$
*/
public class SecurityAnnotationAttributesTests extends TestCase {
//~ Instance fields ================================================================================================
private Attributes attributes;
private Log logger = LogFactory.getLog(SecurityAnnotationAttributesTests.class);
//~ Methods ========================================================================================================
@@ -45,6 +49,67 @@ public class SecurityAnnotationAttributesTests extends TestCase {
this.attributes = new SecurityAnnotationAttributes();
}
public void testGenericsSuperclassDeclarationsAreIncludedWhenSubclassesOverride() {
Method method = null;
try {
method = DepartmentServiceImpl.class.getMethod("someUserMethod3", new Class[] {Department.class});
} catch (NoSuchMethodException unexpected) {
fail("Should be a superMethod called 'someUserMethod3' on class!");
}
Collection attrs = this.attributes.getAttributes(method);
if (logger.isDebugEnabled()) {
logger.debug("attrs: ");
logger.debug(attrs);
}
assertNotNull(attrs);
// expect 1 attribute
assertTrue("Did not find 1 attribute", attrs.size() == 1);
// should have 1 SecurityConfig
for (Object obj : attrs) {
assertTrue(obj instanceof SecurityConfig);
SecurityConfig sc = (SecurityConfig) obj;
assertEquals("Found an incorrect role", "ROLE_ADMIN", sc.getAttribute());
}
Method superMethod = null;
try {
superMethod = DepartmentServiceImpl.class.getMethod("someUserMethod3", new Class[] {Entity.class});
} catch (NoSuchMethodException unexpected) {
fail("Should be a superMethod called 'someUserMethod3' on class!");
}
System.out.println(superMethod);
Collection superAttrs = this.attributes.getAttributes(superMethod);
if (logger.isDebugEnabled()) {
logger.debug("superAttrs: ");
logger.debug(superAttrs);
}
assertNotNull(superAttrs);
// TODO: Enable this part of the test once we can build against Spring 2.0+ and above only (SEC-274)
/*
// expect 1 attribute
assertTrue("Did not find 1 attribute", superAttrs.size() == 1);
// should have 1 SecurityConfig
for (Object obj : superAttrs) {
assertTrue(obj instanceof SecurityConfig);
SecurityConfig sc = (SecurityConfig) obj;
assertEquals("Found an incorrect role", "ROLE_ADMIN", sc.getAttribute());
}
*/
}
public void testGetAttributesClass() {
Collection attrs = this.attributes.getAttributes(BusinessService.class);
+42 -22
View File
@@ -1,30 +1,33 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<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">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acegisecurity</groupId>
<artifactId>acegi-security-parent</artifactId>
<version>1.0.0</version>
<version>1.1-SNAPSHOT</version>
</parent>
<artifactId>acegi-security</artifactId>
<name>Acegi Security System for Spring</name>
<scm>
<connection>scm:svn:https://svn.sourceforge.net/svnroot/acegisecurity/trunk/acegisecurity/core</connection>
<developerConnection>scm:svn:https://svn.sourceforge.net/svnroot/acegisecurity/trunk/acegisecurity/core</developerConnection>
<url>http://svn.sourceforge.net/viewcvs.cgi/acegisecurity/trunk/acegisecurity/core/</url>
</scm>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-remoting</artifactId>
<version>2.0-m2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>2.0-m2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-support</artifactId>
<version>2.0-m2</version>
<scope>runtime</scope>
</dependency>
<dependency>
@@ -54,11 +57,6 @@
<artifactId>commons-logging</artifactId>
<version>1.0.4</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
@@ -95,25 +93,19 @@
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.7.3.0</version>
<version>1.8.0.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.directory.server</groupId>
<artifactId>apacheds-core</artifactId>
<version>1.0-RC1</version>
<version>1.0-RC3</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>nlog4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.0-rc5</version>
<version>1.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -126,7 +118,35 @@
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>${basedir}/../</directory>
<targetPath>META-INF</targetPath>
<includes>
<include>notice.txt</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>${basedir}/src/main/resources/org/acegisecurity/taglibs</directory>
<targetPath>META-INF</targetPath>
<includes>
<include>*.tld</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>${basedir}/src/main/resources</directory>
<targetPath>/</targetPath>
<includes>
<include>**/*</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
@@ -29,7 +29,7 @@ public class BadCredentialsException extends AuthenticationException {
//~ Constructors ===================================================================================================
/**
/**
* Constructs a <code>BadCredentialsException</code> with the specified
* message.
*
@@ -44,7 +44,7 @@ public class BadCredentialsException extends AuthenticationException {
this.extraInformation = extraInformation;
}
/**
/**
* Constructs a <code>BadCredentialsException</code> with the specified
* message and root cause.
*
@@ -15,6 +15,8 @@
package org.acegisecurity;
import java.io.Serializable;
/**
* Represents an authority granted to an {@link Authentication} object.
*
@@ -27,7 +29,7 @@ package org.acegisecurity;
* @author Ben Alex
* @version $Id$
*/
public interface GrantedAuthority {
public interface GrantedAuthority extends Serializable {
//~ Methods ========================================================================================================
/**
@@ -28,6 +28,7 @@ import java.io.Serializable;
public class GrantedAuthorityImpl implements GrantedAuthority, Serializable {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private String role;
//~ Constructors ===================================================================================================
@@ -35,10 +35,6 @@ public class SecurityConfig implements ConfigAttribute {
//~ Methods ========================================================================================================
public boolean equals(Object obj) {
if (obj instanceof String) {
return obj.equals(this.attrib);
}
if (obj instanceof ConfigAttribute) {
ConfigAttribute attr = (ConfigAttribute) obj;
@@ -18,7 +18,6 @@ package org.acegisecurity.acl.basic;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Stores some privileges typical of a domain object.
*
@@ -45,14 +44,18 @@ public class SimpleAclEntry extends AbstractBasicAclEntry {
public static final int READ_WRITE_DELETE = READ | WRITE | DELETE;
// Array required by the abstract superclass via getValidPermissions()
private static final int[] validPermissions = {
private static final int[] VALID_PERMISSIONS = {
NOTHING, ADMINISTRATION, READ, WRITE, CREATE, DELETE, READ_WRITE_CREATE_DELETE, READ_WRITE_CREATE,
READ_WRITE, READ_WRITE_DELETE
};
private static final String[] VALID_PERMISSIONS_AS_STRING = {
"NOTHING", "ADMINISTRATION", "READ", "WRITE", "CREATE", "DELETE", "READ_WRITE_CREATE_DELETE", "READ_WRITE_CREATE",
"READ_WRITE", "READ_WRITE_DELETE" };
//~ Constructors ===================================================================================================
/**
/**
* Allows {@link BasicAclDao} implementations to construct this object
* using <code>newInstance()</code>.
*
@@ -71,8 +74,11 @@ public class SimpleAclEntry extends AbstractBasicAclEntry {
//~ Methods ========================================================================================================
/**
* @return a copy of the permissions array, changes to the values won't affect this class.
*/
public int[] getValidPermissions() {
return validPermissions;
return (int[]) VALID_PERMISSIONS.clone();
}
public String printPermissionsBlock(int i) {
@@ -110,4 +116,35 @@ public class SimpleAclEntry extends AbstractBasicAclEntry {
return sb.toString();
}
/**
* Parse a permission {@link String} literal and return associated value.
*
* @param permission one of the field names that represent a permission: <code>ADMINISTRATION</code>,
* <code>READ</code>, <code>WRITE</code>,...
* @return the value associated to that permission
* @throws IllegalArgumentException if argument is not a valid permission
*/
public static int parsePermission(String permission) {
for (int i = 0; i < VALID_PERMISSIONS_AS_STRING.length; i++) {
if (VALID_PERMISSIONS_AS_STRING[i].equalsIgnoreCase(permission)) {
return VALID_PERMISSIONS[i];
}
}
throw new IllegalArgumentException("Permission provided does not exist: " + permission);
}
/**
* Parse a list of permission {@link String} literals and return associated values.
*
* @param permissions array with permissions as {@link String}
* @see #parsePermission(String) for valid values
*/
public static int[] parsePermissions(String[] permissions) {
int[] requirepermissionAsIntArray = new int[permissions.length];
for (int i = 0; i < requirepermissionAsIntArray.length; i++) {
requirepermissionAsIntArray[i] = parsePermission(permissions[i]);
}
return requirepermissionAsIntArray;
}
}
@@ -1,25 +1,24 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.acls.sid.Sid;
import java.io.Serializable;
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.acls.sid.Sid;
import java.io.Serializable;
/**
* Represents an individual permission assignment within an {@link Acl}.
*
@@ -30,22 +29,28 @@ import java.io.Serializable;
* @author Ben Alex
* @version $Id$
*
*/
public interface AccessControlEntry {
//~ Methods ========================================================================================================
public Acl getAcl();
/**
* Obtains an identifier that represents this ACE.
*
* @return the identifier, or <code>null</code> if unsaved
*/
public Serializable getId();
public Permission getPermission();
public Sid getSid();
public boolean isGranting();
}
*/
public interface AccessControlEntry {
//~ Methods ========================================================================================================
public Acl getAcl();
/**
* Obtains an identifier that represents this ACE.
*
* @return the identifier, or <code>null</code> if unsaved
*/
public Serializable getId();
public Permission getPermission();
public 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
*/
public boolean isGranting();
}
@@ -1,26 +1,25 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.sid.Sid;
import java.io.Serializable;
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.sid.Sid;
import java.io.Serializable;
/**
* Represents an access control list (ACL) for a domain object.
*
@@ -40,105 +39,114 @@ import java.io.Serializable;
*
* @author Ben Alex
* @version $Id$
*/
public interface Acl extends Serializable {
//~ Methods ========================================================================================================
/**
* Returns all of the entries represented by the present <code>Acl</code> (not parents).<p>This method is
* typically used for administrative purposes.</p>
* <p>The order that entries appear in the array is unspecified. However, if implementations use
* particular ordering logic in authorization decisions, the entries returned by this method <em>MUST</em> be
* ordered in that manner.</p>
* <p>Do <em>NOT</em> use this method for making authorization decisions. Instead use {@link
* #isGranted(Permission[], Sid[])}.</p>
* <p>This method must operate correctly even if the <code>Acl</code> only represents a subset of
* <code>Sid</code>s. The caller is responsible for correctly handling the result if only a subset of
* <code>Sid</code>s is represented.</p>
*
* @return the list of entries represented by the <code>Acl</code>
*/
public AccessControlEntry[] getEntries();
/**
* Obtains the domain object this <code>Acl</code> provides entries for. This is immutable once an
* <code>Acl</code> is created.
*
* @return the object identity
*/
public ObjectIdentity getObjectIdentity();
/**
* 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 <code>Acl</code> and this
* <code>Acl</code>. For actual inheritance to take place, the {@link #isEntriesInheriting()} must also be
* <code>true</code>.</p>
* <p>This method must operate correctly even if the <code>Acl</code> only represents a subset of
* <code>Sid</code>s. The caller is responsible for correctly handling the result if only a subset of
* <code>Sid</code>s is represented.</p>
*
* @return the parent <code>Acl</code>
*/
public Acl getParentAcl();
/**
* Indicates whether the ACL entries from the {@link #getParentAcl()} should flow down into the current
* <code>Acl</code>.<p>The mere link between an <code>Acl</code> and a parent <code>Acl</code> 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 inheritence of entries.</p>
*
* @return <code>true</code> if parent ACL entries inherit into the current <code>Acl</code>
*/
public boolean isEntriesInheriting();
/**
* This is the actual authorization logic method, and must be used whenever ACL authorization decisions are
* required.<p>An array of <code>Sid</code>s are presented, representing security identifies of the current
* principal. In addition, an array of <code>Permission</code>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 <code>Permission</code>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 <code>Permission</code>, 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 <code>Permission</code>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 <code>true</code>, 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 <code>Acl</code> only represents a subset of
* <code>Sid</code>s. The caller is responsible for correctly handling the result if only a subset of
* <code>Sid</code>s is represented.</p>
*
* @param permission the permission or permissions required
* @param sids the security identities held by the principal
* @param administrativeMode if <code>true</code> denotes the query is for administrative purposes and no logger or
* auditing (if supported by the implementation) should be undertaken
*
* @return <code>true</code> is authorization is granted
*
* @throws NotFoundException MAY be thrown if an implementation cannot make an authoritative authorization decision
* @throws UnloadedSidException thrown if the <code>Acl</code> does not have details for one or more of the
* <code>Sid</code>s passed as arguments
*/
public boolean isGranted(Permission[] permission, Sid[] sids, boolean administrativeMode)
throws NotFoundException, UnloadedSidException;
/**
* For efficiency reasons an <code>Acl</code> may be loaded and <em>not</em> contain entries for every
* <code>Sid</code> in the system. If an <code>Acl</code> has been loaded and does not represent every
* <code>Sid</code>, all methods of the <code>Sid</code> can only be used within the limited scope of the
* <code>Sid</code> instances it actually represents.<p>It is normal to load an <code>Acl</code> for only
* particular <code>Sid</code>s if read-only authorization decisions are being made. However, if user interface
* reporting or modification of <code>Acl</code>s are desired, an <code>Acl</code> should be loaded with all
* <code>Sid</code>s. This method denotes whether or not the specified <code>Sid</code>s have been loaded or not.</p>
*
* @param sids DOCUMENT ME!
*
* @return <code>true</code> if every passed <code>Sid</code> is represented by this <code>Acl</code> instance
*/
public boolean isSidLoaded(Sid[] sids);
}
*/
public interface Acl extends Serializable {
//~ Methods ========================================================================================================
/**
* Returns all of the entries represented by the present <code>Acl</code> (not parents).<p>This method is
* typically used for administrative purposes.</p>
* <p>The order that entries appear in the array is unspecified. However, if implementations use
* particular ordering logic in authorization decisions, the entries returned by this method <em>MUST</em> be
* ordered in that manner.</p>
* <p>Do <em>NOT</em> use this method for making authorization decisions. Instead use {@link
* #isGranted(Permission[], Sid[])}.</p>
* <p>This method must operate correctly even if the <code>Acl</code> only represents a subset of
* <code>Sid</code>s. The caller is responsible for correctly handling the result if only a subset of
* <code>Sid</code>s is represented.</p>
*
* @return the list of entries represented by the <code>Acl</code>
*/
public AccessControlEntry[] getEntries();
/**
* Obtains the domain object this <code>Acl</code> provides entries for. This is immutable once an
* <code>Acl</code> is created.
*
* @return the object identity
*/
public ObjectIdentity getObjectIdentity();
/**
* Determines the owner of the <code>Acl</code>. The meaning of ownership varies by implementation and is
* unspecified.
*
* @return the owner (may be null if the implementation does not use ownership concepts)
*/
public 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 <code>Acl</code> and this
* <code>Acl</code>. For actual inheritance to take place, the {@link #isEntriesInheriting()} must also be
* <code>true</code>.</p>
* <p>This method must operate correctly even if the <code>Acl</code> only represents a subset of
* <code>Sid</code>s. The caller is responsible for correctly handling the result if only a subset of
* <code>Sid</code>s is represented.</p>
*
* @return the parent <code>Acl</code>
*/
public Acl getParentAcl();
/**
* Indicates whether the ACL entries from the {@link #getParentAcl()} should flow down into the current
* <code>Acl</code>.<p>The mere link between an <code>Acl</code> and a parent <code>Acl</code> 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 inheritence of entries.</p>
*
* @return <code>true</code> if parent ACL entries inherit into the current <code>Acl</code>
*/
public boolean isEntriesInheriting();
/**
* This is the actual authorization logic method, and must be used whenever ACL authorization decisions are
* required.<p>An array of <code>Sid</code>s are presented, representing security identifies of the current
* principal. In addition, an array of <code>Permission</code>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 <code>Permission</code>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 <code>Permission</code>, 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 <code>Permission</code>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 <code>true</code>, 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 <code>Acl</code> only represents a subset of
* <code>Sid</code>s.</p>
*
* @param permission the permission or permissions required
* @param sids the security identities held by the principal
* @param administrativeMode if <code>true</code> denotes the query is for administrative purposes and no logging
* or auditing (if supported by the implementation) should be undertaken
*
* @return <code>true</code> is 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 <code>Acl</code> does not have details for one or more of the
* <code>Sid</code>s passed as arguments
*/
public boolean isGranted(Permission[] permission, Sid[] sids, boolean administrativeMode)
throws NotFoundException, UnloadedSidException;
/**
* For efficiency reasons an <code>Acl</code> may be loaded and <em>not</em> contain entries for every
* <code>Sid</code> in the system. If an <code>Acl</code> has been loaded and does not represent every
* <code>Sid</code>, all methods of the <code>Sid</code> can only be used within the limited scope of the
* <code>Sid</code> instances it actually represents.<p>It is normal to load an <code>Acl</code> for only
* particular <code>Sid</code>s if read-only authorization decisions are being made. However, if user interface
* reporting or modification of <code>Acl</code>s are desired, an <code>Acl</code> should be loaded with all
* <code>Sid</code>s. This method denotes whether or not the specified <code>Sid</code>s have been loaded or not.</p>
*
* @param sids one or more security identities the caller is interest in knowing whether this <code>Sid</code>
* supports
*
* @return <code>true</code> if every passed <code>Sid</code> is represented by this <code>Acl</code> instance
*/
public boolean isSidLoaded(Sid[] sids);
}
@@ -1,106 +1,105 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.springframework.util.Assert;
/**
* Utility methods for displaying ACL information.
*
* @author Ben Alex
* @version $Id$
*/
public class AclFormattingUtils {
//~ Methods ========================================================================================================
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 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);
}
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);
}
/**
* 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}.</p>
*
* @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 AclFormattingUtils.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}.</p>
*
* @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(new Character(code).toString(), new Character(Permission.RESERVED_ON).toString(),
Permission.RESERVED_ON + " is a reserved character code");
Assert.doesNotContain(new Character(code).toString(), new Character(Permission.RESERVED_OFF).toString(),
Permission.RESERVED_OFF + " is a reserved character code");
return AclFormattingUtils.printBinary(mask, Permission.RESERVED_ON, Permission.RESERVED_OFF)
.replace(Permission.RESERVED_ON, code);
}
}
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.springframework.util.Assert;
/**
* Utility methods for displaying ACL information.
*
* @author Ben Alex
* @version $Id$
*/
public class AclFormattingUtils {
//~ Methods ========================================================================================================
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 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);
}
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);
}
/**
* 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}.</p>
*
* @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 AclFormattingUtils.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}.</p>
*
* @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(new Character(code).toString(), new Character(Permission.RESERVED_ON).toString(),
Permission.RESERVED_ON + " is a reserved character code");
Assert.doesNotContain(new Character(code).toString(), new Character(Permission.RESERVED_OFF).toString(),
Permission.RESERVED_OFF + " is a reserved character code");
return AclFormattingUtils.printBinary(mask, Permission.RESERVED_ON, Permission.RESERVED_OFF)
.replace(Permission.RESERVED_ON, code);
}
}
@@ -1,66 +1,100 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.sid.Sid;
import java.util.Map;
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.sid.Sid;
import java.util.Map;
/**
* Provides retrieval of {@link Acl} instances.
*
* @author Ben Alex
* @version $Id$
*/
public interface AclService {
//~ Methods ========================================================================================================
/**
* Obtains all the <code>Acl</code>s that apply for the passed <code>Object</code>s.<p>The returned map is
* keyed on the passed objects, with the values being the <code>Acl</code> instances. Any unknown objects will not
* have a map key.</p>
*
* @param objects the objects to find ACL information for
*
* @return a map with zero or more elements (never <code>null</code>)
*
* @throws NotFoundException DOCUMENT ME!
*/
public Map readAclsById(ObjectIdentity[] objects) throws NotFoundException;
/**
* Obtains all the <code>Acl</code>s that apply for the passed <code>Object</code>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 <code>Acl</code>
* instances. Any unknown objects (or objects for which the interested <code>Sid</code>s do not have entries) will
* not have a map key.</p>
*
* @param objects the objects to find ACL information for
* @param sids the security identities for which ACL information is required (may be <code>null</code> to denote
* all entries)
*
* @return a map with zero or more elements (never <code>null</code>)
*
* @throws NotFoundException DOCUMENT ME!
*/
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids)
throws NotFoundException;
}
*/
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 <code>null</code> if none were found)
*/
public ObjectIdentity[] findChildren(ObjectIdentity parentIdentity);
/**
* Same as {@link #readAclsById(ObjectIdentity[])} except it returns only a single Acl.<p>This method
* should not be called as it does not leverage the underlaying implementation's potential ability to filter
* <code>Acl</code> entries based on a {@link Sid} parameter.</p>
*
* @param object DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws NotFoundException DOCUMENT ME!
*/
public Acl readAclById(ObjectIdentity object) throws NotFoundException;
/**
* Same as {@link #readAclsById(ObjectIdentity[], Sid[])} except it returns only a single Acl.
*
* @param object DOCUMENT ME!
* @param sids DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws NotFoundException DOCUMENT ME!
*/
public Acl readAclById(ObjectIdentity object, Sid[] sids)
throws NotFoundException;
/**
* Obtains all the <code>Acl</code>s that apply for the passed <code>Object</code>s.<p>The returned map is
* keyed on the passed objects, with the values being the <code>Acl</code> instances. Any unknown objects will not
* have a map key.</p>
*
* @param objects the objects to find ACL information for
*
* @return a map with zero or more elements (never <code>null</code>)
*
* @throws NotFoundException DOCUMENT ME!
*/
public Map readAclsById(ObjectIdentity[] objects) throws NotFoundException;
/**
* Obtains all the <code>Acl</code>s that apply for the passed <code>Object</code>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 <code>Acl</code>
* instances. Any unknown objects (or objects for which the interested <code>Sid</code>s do not have entries) will
* not have a map key.</p>
*
* @param objects the objects to find ACL information for
* @param sids the security identities for which ACL information is required (may be <code>null</code> to denote
* all entries)
*
* @return a map with zero or more elements (never <code>null</code>)
*
* @throws NotFoundException DOCUMENT ME!
*/
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids)
throws NotFoundException;
}
@@ -1,49 +1,48 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.AcegiSecurityException;
/**
* Thrown if an <code>Acl</code> entry already exists for the object.
*
* @author Ben Alex
* @version $Id$
*/
public class AlreadyExistsException extends AcegiSecurityException {
//~ Constructors ===================================================================================================
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.AcegiSecurityException;
/**
* Thrown if an <code>Acl</code> entry already exists for the object.
*
* @author Ben Alex
* @version $Id$
*/
public class AlreadyExistsException extends AcegiSecurityException {
//~ Constructors ===================================================================================================
/**
* Constructs an <code>AlreadyExistsException</code> with the specified message.
*
* @param msg the detail message
*/
public AlreadyExistsException(String msg) {
super(msg);
}
*/
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);
}
}
*/
public AlreadyExistsException(String msg, Throwable t) {
super(msg, t);
}
}
@@ -1,31 +1,30 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
/**
* Represents an ACE that provides auditing information.
*
* @author Ben Alex
* @version $Id$
*
*/
public interface AuditableAccessControlEntry extends AccessControlEntry {
//~ Methods ========================================================================================================
public boolean isAuditFailure();
public boolean isAuditSuccess();
}
*/
public interface AuditableAccessControlEntry extends AccessControlEntry {
//~ Methods ========================================================================================================
public boolean isAuditFailure();
public boolean isAuditSuccess();
}
@@ -1,29 +1,31 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import java.io.Serializable;
/**
* A mutable ACL that provides audit capabilities.
*
* @author Ben Alex
* @version $Id$
*
*/
public interface AuditableAcl extends MutableAcl {
//~ Methods ========================================================================================================
public void updateAuditing(Long aceId, boolean auditSuccess, boolean auditFailure);
}
*/
public interface AuditableAcl extends MutableAcl {
//~ Methods ========================================================================================================
public void updateAuditing(Serializable aceId, boolean auditSuccess, boolean auditFailure);
}
@@ -1,50 +1,49 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.AcegiSecurityException;
/**
* Thrown if an {@link Acl} cannot be deleted because children <code>Acl</code>s exist.
*
* @author Ben Alex
* @version $Id$
*/
public class ChildrenExistException extends AcegiSecurityException {
//~ Constructors ===================================================================================================
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.AcegiSecurityException;
/**
* Thrown if an {@link Acl} cannot be deleted because children <code>Acl</code>s exist.
*
* @author Ben Alex
* @version $Id$
*/
public class ChildrenExistException extends AcegiSecurityException {
//~ Constructors ===================================================================================================
/**
* Constructs an <code>ChildrenExistException</code> with the specified
* message.
*
* @param msg the detail message
*/
public ChildrenExistException(String msg) {
super(msg);
}
*/
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);
}
}
*/
public ChildrenExistException(String msg, Throwable t) {
super(msg, t);
}
}
@@ -1,49 +1,48 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.AcegiSecurityException;
/**
* Thrown if an ACL identity could not be extracted from an object.
*
* @author Ben Alex
* @version $Id$
*/
public class IdentityUnavailableException extends AcegiSecurityException {
//~ Constructors ===================================================================================================
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.AcegiSecurityException;
/**
* Thrown if an ACL identity could not be extracted from an object.
*
* @author Ben Alex
* @version $Id$
*/
public class IdentityUnavailableException extends AcegiSecurityException {
//~ Constructors ===================================================================================================
/**
* Constructs an <code>IdentityUnavailableException</code> with the specified message.
*
* @param msg the detail message
*/
public IdentityUnavailableException(String msg) {
super(msg);
}
*/
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);
}
}
*/
public IdentityUnavailableException(String msg, Throwable t) {
super(msg, t);
}
}
@@ -1,25 +1,24 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.acls.sid.Sid;
import java.io.Serializable;
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.acls.sid.Sid;
import java.io.Serializable;
/**
* A mutable <code>Acl</code>.
*
@@ -30,31 +29,47 @@ import java.io.Serializable;
*
* @author Ben Alex
* @version $Id$
*/
public interface MutableAcl extends Acl {
//~ Methods ========================================================================================================
public void deleteAce(Long aceId) throws NotFoundException;
/**
* Obtains an identifier that represents this <code>MutableAcl</code>.
*
* @return the identifier, or <code>null</code> if unsaved
*/
public Serializable getId();
public void insertAce(Long afterAceId, Permission permission, Sid sid, boolean granting)
throws NotFoundException;
public void setEntriesInheriting(boolean entriesInheriting);
/**
* Changes the parent of this ACL.
*
* @param newParent the new parent
*/
public void setParent(MutableAcl newParent);
public void updateAce(Long aceId, Permission permission)
throws NotFoundException;
}
*/
public interface MutableAcl extends Acl {
//~ Methods ========================================================================================================
public void deleteAce(Serializable aceId) throws NotFoundException;
/**
* Retrieves all of the non-deleted {@link AccessControlEntry} instances currently stored by the
* <code>MutableAcl</code>. The returned objects should be immutable outside the package, and therefore it is safe
* to return them to the caller for informational purposes. The <code>AccessControlEntry</code> information is
* needed so that invocations of update and delete methods on the <code>MutableAcl</code> can refer to a valid
* {@link AccessControlEntry#getId()}.
*
* @return DOCUMENT ME!
*/
public AccessControlEntry[] getEntries();
/**
* Obtains an identifier that represents this <code>MutableAcl</code>.
*
* @return the identifier, or <code>null</code> if unsaved
*/
public Serializable getId();
public void insertAce(Serializable afterAceId, Permission permission, Sid sid, boolean granting)
throws NotFoundException;
/**
* Change the value returned by {@link Acl#isEntriesInheriting()}.
*
* @param entriesInheriting the new value
*/
public void setEntriesInheriting(boolean entriesInheriting);
/**
* Changes the parent of this ACL.
*
* @param newParent the new parent
*/
public void setParent(MutableAcl newParent);
public void updateAce(Serializable aceId, Permission permission)
throws NotFoundException;
}
@@ -1,74 +1,65 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
/**
* Provides support for creating and storing <code>Acl</code> instances.
*
* @author Ben Alex
* @version $Id$
*/
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 object the object identity to create
*
* @return an ACL object with its ID set
*
* @throws AlreadyExistsException if the passed object identity already has a record
*/
public MutableAcl createAcl(ObjectIdentity object)
throws AlreadyExistsException;
/**
* Removes the specified entry from the database.
*
* @param object 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
*/
public void deleteAcl(ObjectIdentity object, boolean deleteChildren)
throws ChildrenExistException;
/**
* Locates all object identities that use the specified parent. This is useful for administration tools,
* and before issuing a {@link #deleteAcl(ObjectIdentity, boolean)}.
*
* @param parentIdentity to locate children of
*
* @return the children (or <code>null</code> if none were found)
*/
public ObjectIdentity[] findChildren(ObjectIdentity parentIdentity);
/**
* 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?)
*/
public void updateAcl(MutableAcl acl) throws NotFoundException;
}
*/
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
*/
public 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
*/
public void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren)
throws ChildrenExistException;
/**
* Changes an existing <code>Acl</code> in the database.
*
* @param acl to modify
*
* @return DOCUMENT ME!
*
* @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?)
*/
public MutableAcl updateAcl(MutableAcl acl) throws NotFoundException;
}
@@ -1,49 +1,48 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.AcegiSecurityException;
/**
* Thrown if an ACL-related object cannot be found.
*
* @author Ben Alex
* @version $Id$
*/
public class NotFoundException extends AcegiSecurityException {
//~ Constructors ===================================================================================================
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.AcegiSecurityException;
/**
* Thrown if an ACL-related object cannot be found.
*
* @author Ben Alex
* @version $Id$
*/
public class NotFoundException extends AcegiSecurityException {
//~ Constructors ===================================================================================================
/**
* Constructs an <code>NotFoundException</code> with the specified message.
*
* @param msg the detail message
*/
public NotFoundException(String msg) {
super(msg);
}
*/
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);
}
}
*/
public NotFoundException(String msg, Throwable t) {
super(msg, t);
}
}
@@ -1,23 +1,22 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.acls.sid.Sid;
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.acls.sid.Sid;
/**
* A mutable ACL that provides ownership capabilities.
*
@@ -28,11 +27,9 @@ import org.acegisecurity.acls.sid.Sid;
*
* @author Ben Alex
* @version $Id$
*/
public interface OwnershipAcl extends MutableAcl {
//~ Methods ========================================================================================================
public Sid getOwner();
public void setOwner(Sid newOwner);
}
*/
public interface OwnershipAcl extends MutableAcl {
//~ Methods ========================================================================================================
public void setOwner(Sid newOwner);
}
@@ -1,57 +1,56 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.acls.sid.Sid;
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.acls.sid.Sid;
/**
* Represents a permission granted to a {@link Sid} for a given domain object.
*
* @author Ben Alex
* @version $Id$
*/
public interface Permission {
//~ Static fields/initializers =====================================================================================
public static final char RESERVED_ON = '~';
public static final char RESERVED_OFF = '.';
public static final String THIRTY_TWO_RESERVED_OFF = "................................";
//~ Methods ========================================================================================================
/**
* Returns the bits that represents the permission.
*
* @return the bits that represent the permission
*/
public 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>
* <p>The returned String must be 32 characters in length.</p>
* <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.</p>
*
* @return a 32-character bit pattern
*/
public String getPattern();
}
*/
public interface Permission {
//~ Static fields/initializers =====================================================================================
public static final char RESERVED_ON = '~';
public static final char RESERVED_OFF = '.';
public static final String THIRTY_TWO_RESERVED_OFF = "................................";
//~ Methods ========================================================================================================
/**
* Returns the bits that represents the permission.
*
* @return the bits that represent the permission
*/
public 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>
* <p>The returned String must be 32 characters in length.</p>
* <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.</p>
*
* @return a 32-character bit pattern
*/
public String getPattern();
}
@@ -1,50 +1,49 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.AcegiSecurityException;
/**
* 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
* @version $Id$
*/
public class UnloadedSidException extends AcegiSecurityException {
//~ Constructors ===================================================================================================
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls;
import org.acegisecurity.AcegiSecurityException;
/**
* 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
* @version $Id$
*/
public class UnloadedSidException extends AcegiSecurityException {
//~ Constructors ===================================================================================================
/**
* Constructs an <code>NotFoundException</code> with the specified message.
*
* @param msg the detail message
*/
public UnloadedSidException(String msg) {
super(msg);
}
*/
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);
}
}
*/
public UnloadedSidException(String msg, Throwable t) {
super(msg, t);
}
}
@@ -1,149 +1,133 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.domain;
import org.acegisecurity.acls.AccessControlEntry;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.AuditableAccessControlEntry;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.sid.Sid;
import org.springframework.util.Assert;
import java.io.Serializable;
/**
* An immutable default implementation of <code>AccessControlEntry</code>.
*
* @author Ben Alex
* @version $Id$
*/
public class AccessControlEntryImpl implements AccessControlEntry, AuditableAccessControlEntry {
//~ Instance fields ================================================================================================
private Acl acl;
private Permission permission;
private Serializable id;
private Sid sid;
private boolean aceDirty = false;
private boolean auditFailure = false;
private boolean auditSuccess = false;
private boolean granting;
//~ Constructors ===================================================================================================
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;
}
//~ Methods ========================================================================================================
public void clearDirtyFlags() {
this.aceDirty = false;
}
public boolean equals(Object arg0) {
if (!(arg0 instanceof AccessControlEntryImpl)) {
return false;
}
AccessControlEntryImpl rhs = (AccessControlEntryImpl) arg0;
if ((this.aceDirty != rhs.isAceDirty()) || (this.auditFailure != rhs.isAuditFailure())
|| (this.auditSuccess != rhs.isAuditSuccess()) || (this.granting != rhs.isGranting())
|| !this.acl.equals(rhs.getAcl()) || !this.id.equals(rhs.getId())
|| !this.permission.equals(rhs.getPermission()) || !this.sid.equals(rhs.getSid())) {
return false;
}
return true;
}
public Acl getAcl() {
return acl;
}
public Serializable getId() {
return id;
}
public Permission getPermission() {
return permission;
}
public Sid getSid() {
return sid;
}
public boolean isAceDirty() {
return aceDirty;
}
public boolean isAuditFailure() {
return auditFailure;
}
public boolean isAuditSuccess() {
return auditSuccess;
}
public boolean isGranting() {
return granting;
}
void setAuditFailure(boolean auditFailure) {
this.auditFailure = auditFailure;
this.aceDirty = true;
}
void setAuditSuccess(boolean auditSuccess) {
this.auditSuccess = auditSuccess;
this.aceDirty = true;
}
void setId(Serializable id) {
this.id = id;
}
void setPermission(Permission permission) {
Assert.notNull(permission, "Permission required");
this.permission = permission;
this.aceDirty = true;
}
public String toString() {
StringBuffer sb = new StringBuffer();
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);
sb.append("]");
return sb.toString();
}
}
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.domain;
import org.acegisecurity.acls.AccessControlEntry;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.AuditableAccessControlEntry;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.sid.Sid;
import org.springframework.util.Assert;
import java.io.Serializable;
/**
* An immutable default implementation of <code>AccessControlEntry</code>.
*
* @author Ben Alex
* @version $Id$
*/
public class AccessControlEntryImpl implements AccessControlEntry, AuditableAccessControlEntry {
//~ Instance fields ================================================================================================
private Acl acl;
private Permission permission;
private Serializable id;
private Sid sid;
private boolean auditFailure = false;
private boolean auditSuccess = false;
private boolean granting;
//~ Constructors ===================================================================================================
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;
}
//~ Methods ========================================================================================================
public boolean equals(Object arg0) {
if (!(arg0 instanceof AccessControlEntryImpl)) {
return false;
}
AccessControlEntryImpl rhs = (AccessControlEntryImpl) arg0;
if ((this.auditFailure != rhs.isAuditFailure()) || (this.auditSuccess != rhs.isAuditSuccess())
|| (this.granting != rhs.isGranting()) || !this.acl.equals(rhs.getAcl()) || !this.id.equals(rhs.getId())
|| !this.permission.equals(rhs.getPermission()) || !this.sid.equals(rhs.getSid())) {
return false;
}
return true;
}
public Acl getAcl() {
return acl;
}
public Serializable getId() {
return id;
}
public Permission getPermission() {
return permission;
}
public Sid getSid() {
return sid;
}
public boolean isAuditFailure() {
return auditFailure;
}
public boolean isAuditSuccess() {
return auditSuccess;
}
public boolean isGranting() {
return granting;
}
void setAuditFailure(boolean auditFailure) {
this.auditFailure = auditFailure;
}
void setAuditSuccess(boolean auditSuccess) {
this.auditSuccess = auditSuccess;
}
void setPermission(Permission permission) {
Assert.notNull(permission, "Permission required");
this.permission = permission;
}
public String toString() {
StringBuffer sb = new StringBuffer();
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();
}
}
@@ -13,39 +13,26 @@
* limitations under the License.
*/
package org.acegisecurity.domain.impl;
package org.acegisecurity.acls.domain;
import java.io.Serializable;
import org.acegisecurity.acls.Acl;
/**
* A persistable entity that uses a <code>Long</code> based identity.
*
* Strategy used by {@link AclImpl} to determine whether a principal is permitted to call
* adminstrative methods on the <code>AclImpl</code>.
*
* @author Ben Alex
* @version $Id$
*/
public abstract class PersistableEntityLong extends AbstractPersistableEntity {
//~ Instance fields ================================================================================================
public interface AclAuthorizationStrategy {
//~ Static fields/initializers =====================================================================================
private Long id;
public static final int CHANGE_OWNERSHIP = 0;
public static final int CHANGE_AUDITING = 1;
public static final int CHANGE_GENERAL = 2;
//~ Methods ========================================================================================================
/**
* Obtains the persistence identity of this instance.
*
* @return DOCUMENT ME!
*/
public Long getId() {
return this.id;
}
/**
* Required solely because Hibernate
*
* @return DOCUMENT ME!
*/
public Serializable getInternalId() {
return this.id;
}
public void securityCheck(Acl acl, int changeType);
}
@@ -0,0 +1,125 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.domain;
import org.acegisecurity.AccessDeniedException;
import org.acegisecurity.Authentication;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.sid.PrincipalSid;
import org.acegisecurity.acls.sid.Sid;
import org.acegisecurity.acls.sid.SidRetrievalStrategy;
import org.acegisecurity.acls.sid.SidRetrievalStrategyImpl;
import org.acegisecurity.context.SecurityContextHolder;
import org.springframework.util.Assert;
/**
* Default implementation of {@link AclAuthorizationStrategy}.<p>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.</p>
*
* @author Ben Alex
* @version $Id$
*/
public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
//~ Instance fields ================================================================================================
private GrantedAuthority gaGeneralChanges;
private GrantedAuthority gaModifyAuditing;
private GrantedAuthority gaTakeOwnership;
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
//~ Constructors ===================================================================================================
/**
* 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.notEmpty(auths, "GrantedAuthority[] with three elements required");
Assert.isTrue(auths.length == 3, "GrantedAuthority[] with three elements required");
this.gaTakeOwnership = auths[0];
this.gaModifyAuditing = auths[1];
this.gaGeneralChanges = auths[2];
}
//~ Methods ========================================================================================================
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 = new PrincipalSid(authentication);
if (currentUser.equals(acl.getOwner()) && ((changeType == CHANGE_GENERAL) || (changeType == CHANGE_OWNERSHIP))) {
return;
}
// Not authorized by ACL ownership; try via adminstrative permissions
GrantedAuthority requiredAuthority = null;
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");
}
// Iterate this principal's authorities to determine right
GrantedAuthority[] auths = authentication.getAuthorities();
for (int i = 0; i < auths.length; i++) {
if (requiredAuthority.equals(auths[i])) {
return;
}
}
// Try to get permission via ACEs within the ACL
Sid[] sids = sidRetrievalStrategy.getSids(authentication);
if (acl.isGranted(new Permission[] {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,500 +1,407 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.domain;
import org.acegisecurity.AccessDeniedException;
import org.acegisecurity.Authentication;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.acls.AccessControlEntry;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.AuditableAcl;
import org.acegisecurity.acls.MutableAcl;
import org.acegisecurity.acls.NotFoundException;
import org.acegisecurity.acls.OwnershipAcl;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.UnloadedSidException;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.sid.PrincipalSid;
import org.acegisecurity.acls.sid.Sid;
import org.acegisecurity.context.SecurityContextHolder;
import org.springframework.util.Assert;
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
/**
* Base implementation of <code>Acl</code>.
*
* @author Ben Alex
* @version $Id
*/
public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
//~ Static fields/initializers =====================================================================================
private static final int CHANGE_OWNERSHIP = 0;
private static final int CHANGE_AUDITING = 1;
private static final int CHANGE_GENERAL = 2;
//~ Instance fields ================================================================================================
private Acl parentAcl;
private AuditLogger auditLogger = new ConsoleAuditLogger(); // AuditableAcl
private GrantedAuthority gaGeneralChanges;
private GrantedAuthority gaModifyAuditing;
private GrantedAuthority gaTakeOwnership;
private List aces = new Vector();
private List deletedAces = new Vector();
private Long id;
private ObjectIdentity objectIdentity;
private Sid owner; // OwnershipAcl
private Sid[] loadedSids = null; // includes all SIDs the WHERE clause covered, even if there was no ACE for a SID
private boolean aclDirty = false; // for snapshot detection
private boolean addedAces = false; // for snapshot detection
private boolean entriesInheriting = false;
private boolean updatedAces = false; // for snapshot detection
//~ Constructors ===================================================================================================
/**
* Minimal constructor, which should be used {@link
* org.acegisecurity.acls.MutableAclService#createAcl(ObjectIdentity)}.
*
* @param objectIdentity the object identity this ACL relates to (required)
* @param id the primary key assigned to this ACL (required)
* @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 AclImpl(ObjectIdentity objectIdentity, Long id, GrantedAuthority[] auths) {
Assert.notNull(objectIdentity, "Object Identity required");
Assert.notNull(id, "Id required");
this.objectIdentity = objectIdentity;
this.id = id;
this.setAuthorities(auths);
}
/**
* 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 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)
* @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, Long id, Acl parentAcl, GrantedAuthority[] auths, Sid[] loadedSids,
boolean entriesInheriting, Sid owner) {
Assert.notNull(objectIdentity, "Object Identity required");
Assert.notNull(id, "Id required");
Assert.notNull(owner, "Owner required");
this.objectIdentity = objectIdentity;
this.id = id;
setAuthorities(auths);
this.parentAcl = parentAcl; // may be null
this.loadedSids = loadedSids; // may be null
this.entriesInheriting = entriesInheriting;
this.owner = owner;
}
/**
* Private no-argument constructor for use by reflection-based persistence
* tools along with field-level access.
*/
private AclImpl() {}
//~ Methods ========================================================================================================
/**
* Clears the dirty flags on the <code>Acl</code>, but not any associated ACEs.
*/
public void clearDirtyFlags() {
this.aclDirty = false;
this.addedAces = false;
this.updatedAces = false;
}
public void deleteAce(Long aceId) throws NotFoundException {
securityCheck(CHANGE_GENERAL);
synchronized (aces) {
int offset = findAceOffset(aceId);
if (offset == 1) {
throw new NotFoundException("Requested ACE ID not found");
}
aces.remove(offset);
deletedAces.add(aceId);
}
}
private int findAceOffset(Long aceId) {
Assert.notNull(aceId, "ACE ID is required");
synchronized (aces) {
for (int i = 0; i < aces.size(); i++) {
AccessControlEntry ace = (AccessControlEntry) aces.get(i);
if (ace.getId().equals(aceId)) {
return i;
}
}
}
return -1;
}
public AccessControlEntry[] getEntries() {
// Can safely return AccessControlEntry directly, as they're immutable
return (AccessControlEntry[]) aces.toArray(new AccessControlEntry[] {});
}
public Serializable getId() {
return this.id;
}
public ObjectIdentity getObjectIdentity() {
return objectIdentity;
}
public Sid getOwner() {
return this.owner;
}
public Acl getParentAcl() {
return parentAcl;
}
public void insertAce(Long afterAceId, Permission permission, Sid sid, boolean granting)
throws NotFoundException {
securityCheck(CHANGE_GENERAL);
Assert.notNull(permission, "Permission required");
Assert.notNull(sid, "Sid required");
AccessControlEntryImpl ace = new AccessControlEntryImpl(null, this, sid, permission, granting, false, false);
synchronized (aces) {
if (afterAceId != null) {
int offset = findAceOffset(afterAceId);
if (offset == -1) {
throw new NotFoundException("Requested ACE ID not found");
}
aces.add(offset + 1, ace);
} else {
aces.add(ace);
}
}
this.addedAces = true;
}
public boolean isAclDirty() {
return aclDirty;
}
public boolean isEntriesInheriting() {
return entriesInheriting;
}
/**
* 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. The iteration of each <code>permission:sid</code> combination will then inspect the ACEs in the
* order they appear in the ACL. 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
* passed SIDs were not loaded by the ACL, the <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(Permission[] permission, 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");
}
AccessControlEntry firstRejection = null;
for (int i = 0; i < permission.length; i++) {
for (int x = 0; x < sids.length; x++) {
// Attempt to find exact match for this permission mask and SID
Iterator acesIterator = aces.iterator();
boolean scanNextSid = true;
while (acesIterator.hasNext()) {
AccessControlEntry ace = (AccessControlEntry) acesIterator.next();
if ((ace.getPermission().getMask() == permission[i].getMask()) && ace.getSid().equals(sids[x])) {
// Found a matching ACE, so its authorization decision will prevail
if (ace.isGranting()) {
// Success
if (!administrativeMode) {
auditLogger.logIfNeeded(true, ace);
}
return true;
} else {
// 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 "aceIterator" while loop
}
}
}
if (!scanNextSid) {
break; // exit SID for loop (now try next permission)
}
}
}
if (firstRejection != null) {
// We found an ACE to reject the request at this point, as no
// other ACEs were found that granted a different permission
if (!administrativeMode) {
auditLogger.logIfNeeded(false, firstRejection);
}
return false;
}
// No matches have been found so far
if (isEntriesInheriting() && (parentAcl != null)) {
// We have a parent, so let them try to find a matching ACE
return parentAcl.isGranted(permission, sids, false);
} else {
// We either have no parent, or we're the uppermost parent
throw new NotFoundException("Unable to locate a matching ACE for passed permissions and SIDs");
}
}
public boolean isSidLoaded(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.length == 0)) {
return true;
}
// This ACL applies to a SID subset. Iterate to check it applies
for (int i = 0; i < sids.length; i++) {
boolean found = false;
for (int y = 0; y < this.loadedSids.length; y++) {
if (sids[i].equals(this.loadedSids[y])) {
// this SID is OK
found = true;
break; // out of loadedSids for loop
}
}
if (!found) {
return false;
}
}
return true;
}
protected void securityCheck(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 = new PrincipalSid(authentication);
if (currentUser.equals(this.owner) && ((changeType == CHANGE_GENERAL) || (changeType == CHANGE_OWNERSHIP))) {
return;
}
// Not authorized by ACL ownership; try via adminstrative permissions
GrantedAuthority requiredAuthority = null;
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");
}
// Iterate this principal's authorities to determine right
GrantedAuthority[] auths = authentication.getAuthorities();
for (int i = 0; i < auths.length; i++) {
if (requiredAuthority.equals(auths[i])) {
return;
}
}
throw new AccessDeniedException(
"Principal does not have required ACL permissions to perform requested operation");
}
/**
* Change the special adminstrative permissions honoured by this object.<p>Normally a principal must be the
* owner of the ACL in order to make most changes. The authorities passed to this method provide a way for
* non-owners to modify the ACL (and indeed modify audit parameters, which are not available to ACL owners).</p>
*
* @param auths an array of <code>GrantedAuthority</code>s that have administrative 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)
*/
private void setAuthorities(GrantedAuthority[] auths) {
Assert.notEmpty(auths, "GrantedAuthority[] with three elements required");
Assert.isTrue(auths.length == 3, "GrantedAuthority[] with three elements required");
this.gaTakeOwnership = auths[0];
this.gaModifyAuditing = auths[1];
this.gaGeneralChanges = auths[2];
}
public void setEntriesInheriting(boolean entriesInheriting) {
securityCheck(CHANGE_GENERAL);
this.entriesInheriting = entriesInheriting;
this.aclDirty = true;
}
public void setOwner(Sid newOwner) {
securityCheck(CHANGE_OWNERSHIP);
Assert.notNull(newOwner, "Owner required");
this.owner = newOwner;
this.aclDirty = true;
}
public void setParent(MutableAcl newParent) {
securityCheck(CHANGE_GENERAL);
Assert.notNull(newParent, "New Parent required");
this.parentAcl = newParent;
this.aclDirty = true;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("AclImpl[");
sb.append("id: ").append(this.id).append("; ");
sb.append("objectIdentity: ").append(this.objectIdentity).append("; ");
sb.append("owner: ").append(this.owner).append("; ");
Iterator iterator = this.aces.iterator();
int count = 0;
while (iterator.hasNext()) {
count++;
if (count == 1) {
sb.append("\r\n");
}
sb.append(iterator.next().toString()).append("\r\n");
}
sb.append("inheriting: ").append(this.entriesInheriting).append("; ");
sb.append("parent: ").append((this.parentAcl == null) ? "Null" : this.parentAcl.getObjectIdentity());
sb.append("]");
return sb.toString();
}
public void updateAce(Long aceId, Permission permission)
throws NotFoundException {
securityCheck(CHANGE_GENERAL);
synchronized (aces) {
int offset = findAceOffset(aceId);
if (offset == 1) {
throw new NotFoundException("Requested ACE ID not found");
}
AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(offset);
ace.setPermission(permission);
}
this.updatedAces = true;
}
public void updateAuditing(Long aceId, boolean auditSuccess, boolean auditFailure) {
securityCheck(CHANGE_AUDITING);
synchronized (aces) {
int offset = findAceOffset(aceId);
if (offset == 1) {
throw new NotFoundException("Requested ACE ID not found");
}
AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(offset);
ace.setAuditSuccess(auditSuccess);
ace.setAuditFailure(auditFailure);
}
this.updatedAces = true;
}
}
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.domain;
import org.acegisecurity.acls.AccessControlEntry;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.AuditableAcl;
import org.acegisecurity.acls.MutableAcl;
import org.acegisecurity.acls.NotFoundException;
import org.acegisecurity.acls.OwnershipAcl;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.UnloadedSidException;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.sid.Sid;
import org.springframework.util.Assert;
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
/**
* Base implementation of <code>Acl</code>.
*
* @author Ben Alex
* @version $Id
*/
public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
//~ Instance fields ================================================================================================
private Acl parentAcl;
private AclAuthorizationStrategy aclAuthorizationStrategy;
private AuditLogger auditLogger;
private List aces = new Vector();
private ObjectIdentity objectIdentity;
private Serializable id;
private Sid owner; // OwnershipAcl
private Sid[] loadedSids = null; // includes all SIDs the WHERE clause covered, even if there was no ACE for a SID
private boolean entriesInheriting = true;
//~ Constructors ===================================================================================================
/**
* Minimal constructor, which should be used {@link
* org.acegisecurity.acls.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;
}
/**
* 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, 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 no-argument constructor for use by reflection-based persistence
* tools along with field-level access.
*/
private AclImpl() {}
//~ Methods ========================================================================================================
public void deleteAce(Serializable aceId) throws NotFoundException {
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
synchronized (aces) {
int offset = findAceOffset(aceId);
if (offset == -1) {
throw new NotFoundException("Requested ACE ID not found");
}
this.aces.remove(offset);
}
}
private int findAceOffset(Serializable aceId) {
Assert.notNull(aceId, "ACE ID is required");
synchronized (aces) {
for (int i = 0; i < aces.size(); i++) {
AccessControlEntry ace = (AccessControlEntry) aces.get(i);
if (ace.getId().equals(aceId)) {
return i;
}
}
}
return -1;
}
public AccessControlEntry[] getEntries() {
// Can safely return AccessControlEntry directly, as they're immutable outside the ACL package
return (AccessControlEntry[]) aces.toArray(new AccessControlEntry[] {});
}
public Serializable getId() {
return this.id;
}
public ObjectIdentity getObjectIdentity() {
return objectIdentity;
}
public Sid getOwner() {
return this.owner;
}
public Acl getParentAcl() {
return parentAcl;
}
public void insertAce(Serializable afterAceId, Permission permission, Sid sid, boolean granting)
throws NotFoundException {
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
Assert.notNull(permission, "Permission required");
Assert.notNull(sid, "Sid required");
AccessControlEntryImpl ace = new AccessControlEntryImpl(null, this, sid, permission, granting, false, false);
synchronized (aces) {
if (afterAceId != null) {
int offset = findAceOffset(afterAceId);
if (offset == -1) {
throw new NotFoundException("Requested ACE ID not found");
}
this.aces.add(offset + 1, ace);
} else {
this.aces.add(ace);
}
}
}
public boolean isEntriesInheriting() {
return entriesInheriting;
}
/**
* 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(Permission[] permission, 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");
}
AccessControlEntry firstRejection = null;
for (int i = 0; i < permission.length; i++) {
for (int x = 0; x < sids.length; x++) {
// Attempt to find exact match for this permission mask and SID
Iterator acesIterator = aces.iterator();
boolean scanNextSid = true;
while (acesIterator.hasNext()) {
AccessControlEntry ace = (AccessControlEntry) acesIterator.next();
if ((ace.getPermission().getMask() == permission[i].getMask()) && ace.getSid().equals(sids[x])) {
// Found a matching ACE, so its authorization decision will prevail
if (ace.isGranting()) {
// Success
if (!administrativeMode) {
auditLogger.logIfNeeded(true, ace);
}
return true;
} else {
// 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 "aceIterator" while loop
}
}
}
if (!scanNextSid) {
break; // exit SID for loop (now try next permission)
}
}
}
if (firstRejection != null) {
// We found an ACE to reject the request at this point, as no
// other ACEs were found that granted a different permission
if (!administrativeMode) {
auditLogger.logIfNeeded(false, firstRejection);
}
return false;
}
// No matches have been found so far
if (isEntriesInheriting() && (parentAcl != null)) {
// We have a parent, so let them try to find a matching ACE
return parentAcl.isGranted(permission, sids, false);
} else {
// We either have no parent, or we're the uppermost parent
throw new NotFoundException("Unable to locate a matching ACE for passed permissions and SIDs");
}
}
public boolean isSidLoaded(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.length == 0)) {
return true;
}
// This ACL applies to a SID subset only. Iterate to check it applies.
for (int i = 0; i < sids.length; i++) {
boolean found = false;
for (int y = 0; y < this.loadedSids.length; y++) {
if (sids[i].equals(this.loadedSids[y])) {
// 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 void setParent(MutableAcl newParent) {
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
Assert.notNull(newParent, "New Parent required");
Assert.isTrue(!newParent.equals(this), "Cannot be the parent of yourself");
this.parentAcl = newParent;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("AclImpl[");
sb.append("id: ").append(this.id).append("; ");
sb.append("objectIdentity: ").append(this.objectIdentity).append("; ");
sb.append("owner: ").append(this.owner).append("; ");
Iterator iterator = this.aces.iterator();
int count = 0;
while (iterator.hasNext()) {
count++;
if (count == 1) {
sb.append("\r\n");
}
sb.append(iterator.next().toString()).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("]");
return sb.toString();
}
public void updateAce(Serializable aceId, Permission permission)
throws NotFoundException {
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_GENERAL);
synchronized (aces) {
int offset = findAceOffset(aceId);
if (offset == 1) {
throw new NotFoundException("Requested ACE ID not found");
}
AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(offset);
ace.setPermission(permission);
}
}
public void updateAuditing(Serializable aceId, boolean auditSuccess, boolean auditFailure) {
aclAuthorizationStrategy.securityCheck(this, AclAuthorizationStrategy.CHANGE_AUDITING);
synchronized (aces) {
int offset = findAceOffset(aceId);
if (offset == 1) {
throw new NotFoundException("Requested ACE ID not found");
}
AccessControlEntryImpl ace = (AccessControlEntryImpl) aces.get(offset);
ace.setAuditSuccess(auditSuccess);
ace.setAuditFailure(auditFailure);
}
}
}
@@ -1,32 +1,31 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.domain;
import org.acegisecurity.acls.AccessControlEntry;
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.domain;
import org.acegisecurity.acls.AccessControlEntry;
/**
* Used by <code>AclImpl</code> to log audit events.
*
* @author Ben Alex
* @version $Id$
*
*/
public interface AuditLogger {
//~ Methods ========================================================================================================
public void logIfNeeded(boolean granted, AccessControlEntry ace);
}
*/
public interface AuditLogger {
//~ Methods ========================================================================================================
public void logIfNeeded(boolean granted, AccessControlEntry ace);
}
@@ -0,0 +1,164 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.domain;
import org.acegisecurity.acls.AclFormattingUtils;
import org.acegisecurity.acls.Permission;
import org.springframework.util.Assert;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
/**
* A set of standard permissions.
*
* @author Ben Alex
* @version $Id$
*/
public class BasePermission implements Permission {
//~ Static fields/initializers =====================================================================================
public static final Permission READ = new BasePermission(1 << 0, 'R'); // 1
public static final Permission WRITE = new BasePermission(1 << 1, 'W'); // 2
public static final Permission CREATE = new BasePermission(1 << 2, 'C'); // 4
public static final Permission DELETE = new BasePermission(1 << 3, 'D'); // 8
public static final Permission ADMINISTRATION = new BasePermission(1 << 4, 'A'); // 16
private static Map locallyDeclaredPermissionsByInteger = new HashMap();
private static Map locallyDeclaredPermissionsByName = new HashMap();
static {
Field[] fields = BasePermission.class.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
try {
Object fieldValue = fields[i].get(null);
if (BasePermission.class.isAssignableFrom(fieldValue.getClass())) {
// Found a BasePermission static field
BasePermission perm = (BasePermission) fieldValue;
locallyDeclaredPermissionsByInteger.put(new Integer(perm.getMask()), perm);
locallyDeclaredPermissionsByName.put(fields[i].getName(), perm);
}
} catch (Exception ignore) {}
}
}
//~ Instance fields ================================================================================================
private char code;
private int mask;
//~ Constructors ===================================================================================================
private BasePermission(int mask, char code) {
this.mask = mask;
this.code = code;
}
//~ Methods ========================================================================================================
/**
* Dynamically creates a <code>CumulativePermission</code> or <code>BasePermission</code> representing the
* active bits in the passed mask.
*
* @param mask to build
*
* @return a Permission representing the requested object
*/
public static Permission buildFromMask(int mask) {
if (locallyDeclaredPermissionsByInteger.containsKey(new Integer(mask))) {
// The requested mask has an exactly match against a statically-defined BasePermission, so return it
return (Permission) locallyDeclaredPermissionsByInteger.get(new Integer(mask));
}
// To get this far, we have to use a CumulativePermission
CumulativePermission permission = new CumulativePermission();
for (int i = 0; i < 32; i++) {
int permissionToCheck = 1 << i;
if ((mask & permissionToCheck) == permissionToCheck) {
Permission p = (Permission) locallyDeclaredPermissionsByInteger.get(new Integer(permissionToCheck));
Assert.state(p != null,
"Mask " + permissionToCheck + " does not have a corresponding static BasePermission");
permission.set(p);
}
}
return permission;
}
public static Permission[] buildFromMask(int[] masks) {
if ((masks == null) || (masks.length == 0)) {
return new Permission[] {};
}
List list = new Vector();
for (int i = 0; i < masks.length; i++) {
list.add(BasePermission.buildFromMask(masks[i]));
}
return (Permission[]) list.toArray(new Permission[] {});
}
public static Permission buildFromName(String name) {
Assert.isTrue(locallyDeclaredPermissionsByName.containsKey(name), "Unknown permission '" + name + "'");
return (Permission) locallyDeclaredPermissionsByName.get(name);
}
public static Permission[] buildFromName(String[] names) {
if ((names == null) || (names.length == 0)) {
return new Permission[] {};
}
List list = new Vector();
for (int i = 0; i < names.length; i++) {
list.add(BasePermission.buildFromName(names[i]));
}
return (Permission[]) list.toArray(new Permission[] {});
}
public boolean equals(Object arg0) {
if (!(arg0 instanceof BasePermission)) {
return false;
}
BasePermission rhs = (BasePermission) arg0;
return (this.mask == rhs.getMask());
}
public int getMask() {
return mask;
}
public String getPattern() {
return AclFormattingUtils.printBinary(mask, code);
}
public String toString() {
return "BasePermission[" + getPattern() + "=" + mask + "]";
}
}
@@ -1,46 +1,45 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.domain;
import org.acegisecurity.acls.AccessControlEntry;
import org.acegisecurity.acls.AuditableAccessControlEntry;
import org.springframework.util.Assert;
/**
* DOCUMENT ME!
*
* @author $author$
* @version $Revision$
*/
public class ConsoleAuditLogger implements AuditLogger {
//~ Methods ========================================================================================================
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);
}
}
}
}
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.domain;
import org.acegisecurity.acls.AccessControlEntry;
import org.acegisecurity.acls.AuditableAccessControlEntry;
import org.springframework.util.Assert;
/**
* A bsaic implementation of {@link AuditLogger}.
*
* @author Ben Alex
* @version $Id$
*/
public class ConsoleAuditLogger implements AuditLogger {
//~ Methods ========================================================================================================
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,79 +1,78 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.domain;
import org.acegisecurity.acls.AclFormattingUtils;
import org.acegisecurity.acls.Permission;
/**
* Represents a <code>Permission</code> that is constructed at runtime from other permissions.<p>Methods return
* <code>this</code>, in order to facilitate method chaining.</p>
*
* @author Ben Alex
* @version $Id$
*/
public class CumulativePermission implements Permission {
//~ Instance fields ================================================================================================
private String pattern = THIRTY_TWO_RESERVED_OFF;
private int mask = 0;
//~ Methods ========================================================================================================
public CumulativePermission clear(Permission permission) {
this.mask &= ~permission.getMask();
this.pattern = AclFormattingUtils.demergePatterns(this.pattern, permission.getPattern());
return this;
}
public CumulativePermission clear() {
this.mask = 0;
this.pattern = THIRTY_TWO_RESERVED_OFF;
return this;
}
public boolean equals(Object arg0) {
if (!(arg0 instanceof CumulativePermission)) {
return false;
}
CumulativePermission rhs = (CumulativePermission) arg0;
return (this.mask == rhs.getMask());
}
public int getMask() {
return this.mask;
}
public String getPattern() {
return this.pattern;
}
public CumulativePermission set(Permission permission) {
this.mask |= permission.getMask();
this.pattern = AclFormattingUtils.mergePatterns(this.pattern, permission.getPattern());
return this;
}
public String toString() {
return "CumulativePermission[" + pattern + "=" + this.mask + "]";
}
}
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.domain;
import org.acegisecurity.acls.AclFormattingUtils;
import org.acegisecurity.acls.Permission;
/**
* Represents a <code>Permission</code> that is constructed at runtime from other permissions.<p>Methods return
* <code>this</code>, in order to facilitate method chaining.</p>
*
* @author Ben Alex
* @version $Id$
*/
public class CumulativePermission implements Permission {
//~ Instance fields ================================================================================================
private String pattern = THIRTY_TWO_RESERVED_OFF;
private int mask = 0;
//~ Methods ========================================================================================================
public CumulativePermission clear(Permission permission) {
this.mask &= ~permission.getMask();
this.pattern = AclFormattingUtils.demergePatterns(this.pattern, permission.getPattern());
return this;
}
public CumulativePermission clear() {
this.mask = 0;
this.pattern = THIRTY_TWO_RESERVED_OFF;
return this;
}
public boolean equals(Object arg0) {
if (!(arg0 instanceof CumulativePermission)) {
return false;
}
CumulativePermission rhs = (CumulativePermission) arg0;
return (this.mask == rhs.getMask());
}
public int getMask() {
return this.mask;
}
public String getPattern() {
return this.pattern;
}
public CumulativePermission set(Permission permission) {
this.mask |= permission.getMask();
this.pattern = AclFormattingUtils.mergePatterns(this.pattern, permission.getPattern());
return this;
}
public String toString() {
return "CumulativePermission[" + pattern + "=" + this.mask + "]";
}
}
@@ -0,0 +1,5 @@
<html>
<body>
Basic implementation of access control lists (ACLs) interfaces.
</body>
</html>
@@ -1,39 +1,42 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.jdbc;
import org.acegisecurity.acls.domain.AclImpl;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.jdbc;
import org.acegisecurity.acls.MutableAcl;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import java.io.Serializable;
/**
* A caching layer for {@link JdbcAclService}.
*
* @author Ben Alex
* @version $Id$
*
*/
public interface AclCache {
//~ Methods ========================================================================================================
public void evictFromCache(Long pk);
public AclImpl getFromCache(ObjectIdentity objectIdentity);
public AclImpl getFromCache(Long pk);
public void putInCache(AclImpl acl); // should walk tree as well!
}
*/
public interface AclCache {
//~ Methods ========================================================================================================
public void evictFromCache(Serializable pk);
public void evictFromCache(ObjectIdentity objectIdentity);
public MutableAcl getFromCache(ObjectIdentity objectIdentity);
public MutableAcl getFromCache(Serializable pk);
public void putInCache(MutableAcl acl);
}
@@ -1,93 +1,115 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.jdbc;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.Element;
import org.acegisecurity.acls.domain.AclImpl;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.springframework.util.Assert;
/**
* DOCUMENT ME!
*
* @author $author$
* @version $Revision$
*/
public class EhCacheBasedAclCache implements AclCache {
//~ Instance fields ================================================================================================
private Cache cache;
//~ Constructors ===================================================================================================
public EhCacheBasedAclCache(Cache cache) {
Assert.notNull(cache, "Cache required");
this.cache = cache;
}
//~ Methods ========================================================================================================
public void evictFromCache(Long pk) {
AclImpl acl = getFromCache(pk);
if (acl != null) {
cache.remove(pk);
cache.remove(acl.getObjectIdentity());
}
}
public AclImpl getFromCache(ObjectIdentity objectIdentity) {
Element element = null;
try {
element = cache.get(objectIdentity);
} catch (CacheException ignored) {}
if (element == null) {
return null;
}
return (AclImpl) element.getValue();
}
public AclImpl getFromCache(Long pk) {
Element element = null;
try {
element = cache.get(pk);
} catch (CacheException ignored) {}
if (element == null) {
return null;
}
return (AclImpl) element.getValue();
}
public void putInCache(AclImpl acl) {
if ((acl.getParentAcl() != null) && acl.getParentAcl() instanceof AclImpl) {
putInCache((AclImpl) acl.getParentAcl());
}
cache.put(new Element(acl.getObjectIdentity(), acl));
cache.put(new Element(acl.getId(), acl));
}
}
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.jdbc;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.Element;
import org.acegisecurity.acls.MutableAcl;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.springframework.util.Assert;
import java.io.Serializable;
/**
* Simple implementation of {@link AclCache} that delegates to EH-CACHE.
*
* @author Ben Alex
* @version $Id$
*/
public class EhCacheBasedAclCache implements AclCache {
//~ Instance fields ================================================================================================
private Cache cache;
//~ Constructors ===================================================================================================
public EhCacheBasedAclCache(Cache cache) {
Assert.notNull(cache, "Cache required");
this.cache = cache;
}
//~ Methods ========================================================================================================
public void evictFromCache(Serializable pk) {
Assert.notNull(pk, "Primary key (identifier) required");
MutableAcl acl = getFromCache(pk);
if (acl != null) {
cache.remove(acl.getId());
cache.remove(acl.getObjectIdentity());
}
}
public void evictFromCache(ObjectIdentity objectIdentity) {
Assert.notNull(objectIdentity, "ObjectIdentity required");
MutableAcl acl = getFromCache(objectIdentity);
if (acl != null) {
cache.remove(acl.getId());
cache.remove(acl.getObjectIdentity());
}
}
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 (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 (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 ((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));
}
}
@@ -0,0 +1,114 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.jdbc;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.AclService;
import org.acegisecurity.acls.NotFoundException;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.objectidentity.ObjectIdentityImpl;
import org.acegisecurity.acls.sid.Sid;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.util.Assert;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
/**
* Simple JDBC-based implementation of <code>AclService</code>.<p>Requires the "dirty" flags in {@link
* org.acegisecurity.acls.domain.AclImpl} and {@link org.acegisecurity.acls.domain.AccessControlEntryImpl} to be set,
* so that the implementation can detect changed parameters easily.</p>
*
* @author Ben Alex
* @version $Id$
*/
public class JdbcAclService implements AclService {
//~ Static fields/initializers =====================================================================================
protected static final Log log = LogFactory.getLog(JdbcAclService.class);
private static final String selectAclObjectWithParent = "SELECT obj.object_id_identity obj_id, class.class class "
+ "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 = ?)";
//~ Instance fields ================================================================================================
protected JdbcTemplate jdbcTemplate;
private LookupStrategy lookupStrategy;
//~ Constructors ===================================================================================================
public JdbcAclService(DataSource dataSource, LookupStrategy lookupStrategy) {
Assert.notNull(dataSource, "DataSource required");
Assert.notNull(lookupStrategy, "LookupStrategy required");
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.lookupStrategy = lookupStrategy;
}
//~ Methods ========================================================================================================
public ObjectIdentity[] findChildren(ObjectIdentity parentIdentity) {
Object[] args = {parentIdentity.getIdentifier(), parentIdentity.getJavaType().getName()};
List objects = jdbcTemplate.query(selectAclObjectWithParent, args,
new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum)
throws SQLException {
String javaType = rs.getString("class");
String identifier = rs.getString("obj_id");
return new ObjectIdentityImpl(javaType, identifier);
}
});
return (ObjectIdentityImpl[]) objects.toArray(new ObjectIdentityImpl[] {});
}
public Acl readAclById(ObjectIdentity object, Sid[] sids)
throws NotFoundException {
Map map = readAclsById(new ObjectIdentity[] {object}, sids);
if (map.size() == 0) {
throw new NotFoundException("Could not find ACL");
} else {
return (Acl) map.get(object);
}
}
public Acl readAclById(ObjectIdentity object) throws NotFoundException {
return readAclById(object, null);
}
public Map readAclsById(ObjectIdentity[] objects) {
return readAclsById(objects, null);
}
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids)
throws NotFoundException {
return lookupStrategy.readAclsById(objects, sids);
}
}
@@ -0,0 +1,368 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.jdbc;
import org.acegisecurity.Authentication;
import org.acegisecurity.acls.AccessControlEntry;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.AlreadyExistsException;
import org.acegisecurity.acls.ChildrenExistException;
import org.acegisecurity.acls.MutableAcl;
import org.acegisecurity.acls.MutableAclService;
import org.acegisecurity.acls.NotFoundException;
import org.acegisecurity.acls.domain.AccessControlEntryImpl;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.objectidentity.ObjectIdentityImpl;
import org.acegisecurity.acls.sid.GrantedAuthoritySid;
import org.acegisecurity.acls.sid.PrincipalSid;
import org.acegisecurity.acls.sid.Sid;
import org.acegisecurity.context.SecurityContextHolder;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
import java.lang.reflect.Array;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import javax.sql.DataSource;
/**
* Provides a base implementation of {@link MutableAclService}.
*
* @author Ben Alex
* @author Johannes Zlattinger
* @version $Id$
*/
public class JdbcMutableAclService extends JdbcAclService implements MutableAclService {
//~ Instance fields ================================================================================================
private AclCache aclCache;
private String deleteClassByClassNameString = "DELETE FROM acl_class WHERE class=?";
private String deleteEntryByObjectIdentityForeignKey = "DELETE FROM acl_entry WHERE acl_object_identity=?";
private String deleteObjectIdentityByPrimaryKey = "DELETE FROM acl_object_identity WHERE id=?";
private String identityQuery = "call identity()";
private String insertClass = "INSERT INTO acl_class (id, class) VALUES (null, ?)";
private String insertEntry = "INSERT INTO acl_entry "
+ "(id, acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure)"
+ "VALUES (null, ?, ?, ?, ?, ?, ?, ?)";
private String insertObjectIdentity = "INSERT INTO acl_object_identity "
+ "(id, object_id_class, object_id_identity, owner_sid, entries_inheriting) " + "VALUES (null, ?, ?, ?, ?)";
private String insertSid = "INSERT INTO acl_sid (id, principal, sid) VALUES (null, ?, ?)";
private String selectClassPrimaryKey = "SELECT id FROM acl_class WHERE class=?";
private String selectCountObjectIdentityRowsForParticularClassNameString = "SELECT COUNT(acl_object_identity.id) "
+ "FROM acl_object_identity, acl_class WHERE acl_class.id = acl_object_identity.object_id_class and 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().length;
}
public void setValues(PreparedStatement stmt, int i)
throws SQLException {
AccessControlEntry entry_ = (AccessControlEntry) Array.get(acl.getEntries(), 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.getJavaType(), true);
jdbcTemplate.update(insertObjectIdentity,
new Object[] {classId, object.getIdentifier().toString(), sidId, new Boolean(true)});
}
/**
* Retrieves the primary key from acl_class, creating a new row if needed and the allowCreate property is
* true.
*
* @param clazz to find or create an entry for (this implementation uses the fully-qualified class name String)
* @param allowCreate true if creation is permitted if not found
*
* @return the primary key or null if not found
*/
protected Long createOrRetrieveClassPrimaryKey(Class clazz, boolean allowCreate) {
List classIds = jdbcTemplate.queryForList(selectClassPrimaryKey, new Object[] {clazz.getName()}, Long.class);
Long classId = null;
if (classIds.isEmpty()) {
if (allowCreate) {
classId = null;
jdbcTemplate.update(insertClass, new Object[] {clazz.getName()});
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
classId = new Long(jdbcTemplate.queryForLong(identityQuery));
}
} else {
classId = (Long) classIds.iterator().next();
}
return classId;
}
/**
* 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 DOCUMENT ME!
*/
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
Assert.notNull(sid, "Sid required");
String sidName = null;
boolean principal = true;
if (sid instanceof PrincipalSid) {
sidName = ((PrincipalSid) sid).getPrincipal();
} else if (sid instanceof GrantedAuthoritySid) {
sidName = ((GrantedAuthoritySid) sid).getGrantedAuthority();
principal = false;
} else {
throw new IllegalArgumentException("Unsupported implementation of Sid");
}
List sidIds = jdbcTemplate.queryForList(selectSidPrimaryKey, new Object[] {new Boolean(principal), sidName},
Long.class);
Long sidId = null;
if (sidIds.isEmpty()) {
if (allowCreate) {
sidId = null;
jdbcTemplate.update(insertSid, new Object[] {new Boolean(principal), sidName});
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(), "Transaction must be running");
sidId = new Long(jdbcTemplate.queryForLong(identityQuery));
}
} else {
sidId = (Long) sidIds.iterator().next();
}
return sidId;
}
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");
// Recursively call this method for children, or handle children if they don't want automatic recursion
ObjectIdentity[] children = findChildren(objectIdentity);
if (deleteChildren) {
for (int i = 0; i < children.length; i++) {
deleteAcl(children[i], true);
}
} else if (children.length > 0) {
throw new ChildrenExistException("Cannot delete '" + objectIdentity + "' (has " + children.length
+ " children)");
}
// Delete this ACL's ACEs in the acl_entry table
deleteEntries(objectIdentity);
// Delete this ACL's acl_object_identity row
deleteObjectIdentityAndOptionallyClass(objectIdentity);
// Clear the cache
aclCache.evictFromCache(objectIdentity);
}
/**
* Deletes all ACEs defined in the acl_entry table belonging to the presented ObjectIdentity
*
* @param oid the rows in acl_entry to delete
*/
protected void deleteEntries(ObjectIdentity oid) {
jdbcTemplate.update(deleteEntryByObjectIdentityForeignKey, new Object[] {retrieveObjectIdentityPrimaryKey(oid)});
}
/**
* Deletes a single row from acl_object_identity that is associated with the presented ObjectIdentity. In
* addition, deletes the corresponding row from acl_class if there are no more entries in acl_object_identity that
* use that particular acl_class. This keeps the acl_class table reasonably small.
*
* @param oid to delete the acl_object_identity (and clean up acl_class for that class name if appropriate)
*/
protected void deleteObjectIdentityAndOptionallyClass(ObjectIdentity oid) {
// Delete the acl_object_identity row
jdbcTemplate.update(deleteObjectIdentityByPrimaryKey, new Object[] {retrieveObjectIdentityPrimaryKey(oid)});
// Delete the acl_class row, assuming there are no other references to it in acl_object_identity
Object[] className = {oid.getJavaType().getName()};
long numObjectIdentities = jdbcTemplate.queryForLong(selectCountObjectIdentityRowsForParticularClassNameString,
className);
if (numObjectIdentities == 0) {
// No more rows
jdbcTemplate.update(deleteClassByClassNameString, className);
}
}
/**
* 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.getJavaType().getName(), 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}.
*
* @param acl DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws NotFoundException DOCUMENT ME!
*/
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(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
aclCache.evictFromCache(acl.getObjectIdentity());
// Retrieve the ACL via superclass (ensures cache registration, proper retrieval etc)
return (MutableAcl) super.readAclById(acl.getObjectIdentity());
}
/**
* 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 DOCUMENT ME!
*/
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");
}
}
}
@@ -1,44 +1,43 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.jdbc;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.sid.Sid;
import java.util.Map;
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.jdbc;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.sid.Sid;
import java.util.Map;
/**
* Performs optimised lookups for {@link JdbcAclService}.
*
* @author Ben Alex
* @version $Id$
*/
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 <code>null</code> - implementations may elect not
* to provide SID optimisations)
*
* @return the <code>Map</code> pursuant to the interface contract for {@link
* org.acegisecurity.acls.AclService#readAclsById(ObjectIdentity[], Sid[])}
*/
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids);
}
*/
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 <code>null</code> - implementations may elect not
* to provide SID optimisations)
*
* @return the <code>Map</code> pursuant to the interface contract for {@link
* org.acegisecurity.acls.AclService#readAclsById(ObjectIdentity[], Sid[])}
*/
public Map readAclsById(ObjectIdentity[] objects, Sid[] sids);
}
@@ -0,0 +1,5 @@
<html>
<body>
JDBC-based persistence of ACL information.
</body>
</html>
@@ -1,23 +1,22 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.objectidentity;
import java.io.Serializable;
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.objectidentity;
import java.io.Serializable;
/**
* Interface representing the identity of an individual domain object instance.
*
@@ -32,40 +31,40 @@ import java.io.Serializable;
*
* @author Ben Alex
* @version $Id$
*/
public interface ObjectIdentity 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
*/
public boolean equals(Object obj);
/**
* Obtains the actual identifier. This identifier must not be reused to represent other domain objects with
* the same <code>javaType</code>.<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.</p>
*
* @return the identifier (unique within this <code>javaType</code>
*/
public Serializable getIdentifier();
/**
* Obtains the Java type represented by the domain object.
*
* @return the Java type of the domain object
*/
public Class getJavaType();
/**
* Refer to the <code>java.lang.Object</code> documentation for the interface contract.
*
* @return a hash code representation of this object
*/
public int hashCode();
}
*/
public interface ObjectIdentity 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
*/
public boolean equals(Object obj);
/**
* Obtains the actual identifier. This identifier must not be reused to represent other domain objects with
* the same <code>javaType</code>.<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.</p>
*
* @return the identifier (unique within this <code>javaType</code>
*/
public Serializable getIdentifier();
/**
* Obtains the Java type represented by the domain object.
*
* @return the Java type of the domain object
*/
public Class getJavaType();
/**
* Refer to the <code>java.lang.Object</code> documentation for the interface contract.
*
* @return a hash code representation of this object
*/
public int hashCode();
}
@@ -1,146 +1,147 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.objectidentity;
import org.acegisecurity.acl.basic.AclObjectIdentity;
import org.acegisecurity.acls.IdentityUnavailableException;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import java.io.Serializable;
import java.lang.reflect.Method;
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.objectidentity;
import org.acegisecurity.acl.basic.AclObjectIdentity;
import org.acegisecurity.acls.IdentityUnavailableException;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import java.io.Serializable;
import java.lang.reflect.Method;
/**
* Simple implementation of {@link AclObjectIdentity}.<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.</p>
*/
public class ObjectIdentityImpl implements ObjectIdentity {
//~ Instance fields ================================================================================================
private Class javaType;
private Serializable identifier;
//~ Constructors ===================================================================================================
public ObjectIdentityImpl(String javaType, Serializable identifier) {
Assert.hasText(javaType, "Java Type required");
Assert.notNull(identifier, "identifier required");
try {
this.javaType = Class.forName(javaType);
} catch (Exception ex) {
ReflectionUtils.handleReflectionException(ex);
}
this.identifier = identifier;
}
public ObjectIdentityImpl(Class javaType, Serializable identifier) {
Assert.notNull(javaType, "Java Type required");
Assert.notNull(identifier, "identifier required");
this.javaType = javaType;
this.identifier = identifier;
}
/**
* Simple implementation of {@link AclObjectIdentity}.<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.</p>
*/
public class ObjectIdentityImpl implements ObjectIdentity {
//~ Instance fields ================================================================================================
private Class javaType;
private Serializable identifier;
//~ Constructors ===================================================================================================
public ObjectIdentityImpl(String javaType, Serializable identifier) {
Assert.hasText(javaType, "Java Type required");
Assert.notNull(identifier, "identifier required");
try {
this.javaType = Class.forName(javaType);
} catch (Exception ex) {
ReflectionUtils.handleReflectionException(ex);
}
this.identifier = identifier;
}
public ObjectIdentityImpl(Class javaType, Serializable identifier) {
Assert.notNull(javaType, "Java Type required");
Assert.notNull(identifier, "identifier required");
this.javaType = javaType;
this.identifier = identifier;
}
/**
* Creates the <code>NamedEntityObjectIdentity</code> based on the passed
* 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.
* method, otherwise an exception will be thrown. The object passed will
* be considered the {@link #javaType}, so if more control is required,
* an alternate constructor should be used instead.
*
* @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");
this.javaType = object.getClass();
Object result;
try {
Method method = this.javaType.getMethod("getId", new Class[] {});
result = method.invoke(object, new Object[] {});
} catch (Exception e) {
throw new IdentityUnavailableException("Could not extract identity from object " + object, e);
}
Assert.isInstanceOf(Serializable.class, result, "Getter must provide a return value of type Serializable");
this.identifier = (Serializable) result;
}
//~ 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>
*
* @param arg0 object to compare
*
* @return <code>true</code> if the presented object matches this object
*/
public boolean equals(Object arg0) {
if (arg0 == null) {
return false;
}
if (!(arg0 instanceof ObjectIdentityImpl)) {
return false;
}
ObjectIdentityImpl other = (ObjectIdentityImpl) arg0;
if (this.getIdentifier().equals(other.getIdentifier()) && this.getJavaType().equals(other.getJavaType())) {
return true;
}
return false;
}
public Serializable getIdentifier() {
return identifier;
}
public Class getJavaType() {
return javaType;
}
/**
* Important so caching operates properly.
*
* @return the hash
*/
public int hashCode() {
int code = 31;
code ^= this.javaType.hashCode();
code ^= this.identifier.hashCode();
return code;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(this.getClass().getName()).append("[");
sb.append("Java Type: ").append(this.javaType);
sb.append("; Identifier: ").append(this.identifier).append("]");
return sb.toString();
}
}
*/
public ObjectIdentityImpl(Object object) throws IdentityUnavailableException {
Assert.notNull(object, "object cannot be null");
this.javaType = object.getClass();
Object result;
try {
Method method = this.javaType.getMethod("getId", new Class[] {});
result = method.invoke(object, new Object[] {});
} catch (Exception e) {
throw new IdentityUnavailableException("Could not extract identity from object " + object, e);
}
Assert.isInstanceOf(Serializable.class, result, "Getter must provide a return value of type Serializable");
this.identifier = (Serializable) result;
}
//~ 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>
*
* @param arg0 object to compare
*
* @return <code>true</code> if the presented object matches this object
*/
public boolean equals(Object arg0) {
if (arg0 == null) {
return false;
}
if (!(arg0 instanceof ObjectIdentityImpl)) {
return false;
}
ObjectIdentityImpl other = (ObjectIdentityImpl) arg0;
if (this.getIdentifier().equals(other.getIdentifier()) && this.getJavaType().equals(other.getJavaType())) {
return true;
}
return false;
}
public Serializable getIdentifier() {
return identifier;
}
public Class getJavaType() {
return javaType;
}
/**
* Important so caching operates properly.
*
* @return the hash
*/
public int hashCode() {
int code = 31;
code ^= this.javaType.hashCode();
code ^= this.identifier.hashCode();
return code;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(this.getClass().getName()).append("[");
sb.append("Java Type: ").append(this.javaType);
sb.append("; Identifier: ").append(this.identifier).append("]");
return sb.toString();
}
}
@@ -13,25 +13,18 @@
* limitations under the License.
*/
package org.acegisecurity.providers.smb;
import org.acegisecurity.AuthenticationException;
package org.acegisecurity.acls.objectidentity;
/**
* Thrown if
*
* @author Davide Baroncelli
* Strategy interface that provides the ability to determine which {@link ObjectIdentity}
* will be returned for a particular domain object
*
* @author Ben Alex
* @version $Id$
*
*/
public class ChallengeExpiredException extends AuthenticationException {
//~ Constructors ===================================================================================================
public interface ObjectIdentityRetrievalStrategy {
//~ Methods ========================================================================================================
public ChallengeExpiredException(String msg) {
super(msg);
}
public ChallengeExpiredException(String msg, Throwable t) {
super(msg, t);
}
public ObjectIdentity getObjectIdentity(Object domainObject);
}
@@ -0,0 +1,31 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.objectidentity;
/**
* Basic implementation of {@link ObjectIdentityRetrievalStrategy} that uses the constructor of {@link
* ObjectIdentityImpl} to create the {@link ObjectIdentity}.
*
* @author Ben Alex
* @version $Id$
*/
public class ObjectIdentityRetrievalStrategyImpl implements ObjectIdentityRetrievalStrategy {
//~ Methods ========================================================================================================
public ObjectIdentity getObjectIdentity(Object domainObject) {
return new ObjectIdentityImpl(domainObject);
}
}
@@ -0,0 +1,5 @@
<html>
<body>
Provides indirection between ACL packages and domain objects.
</body>
</html>
@@ -0,0 +1,5 @@
<html>
<body>
Interfaces and shared classes to manage access control lists (ACLs) for domain object instances.
</body>
</html>
@@ -1,68 +1,67 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.sid;
import org.acegisecurity.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>
*
* @author Ben Alex
* @version $Id$
*/
public class GrantedAuthoritySid implements Sid {
//~ Instance fields ================================================================================================
private String grantedAuthority;
//~ Constructors ===================================================================================================
public GrantedAuthoritySid(String grantedAuthority) {
Assert.hasText(grantedAuthority, "GrantedAuthority required");
this.grantedAuthority = grantedAuthority;
}
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();
}
//~ Methods ========================================================================================================
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 String getGrantedAuthority() {
return grantedAuthority;
}
public String toString() {
return "GrantedAuthoritySid[" + this.grantedAuthority + "]";
}
}
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.sid;
import org.acegisecurity.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>
*
* @author Ben Alex
* @version $Id$
*/
public class GrantedAuthoritySid implements Sid {
//~ Instance fields ================================================================================================
private String grantedAuthority;
//~ Constructors ===================================================================================================
public GrantedAuthoritySid(String grantedAuthority) {
Assert.hasText(grantedAuthority, "GrantedAuthority required");
this.grantedAuthority = grantedAuthority;
}
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();
}
//~ Methods ========================================================================================================
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 String getGrantedAuthority() {
return grantedAuthority;
}
public String toString() {
return "GrantedAuthoritySid[" + this.grantedAuthority + "]";
}
}
@@ -1,73 +1,72 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.sid;
import org.acegisecurity.Authentication;
import org.acegisecurity.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>
*
* @author Ben Alex
* @version $Id$
*/
public class PrincipalSid implements Sid {
//~ Instance fields ================================================================================================
private String principal;
//~ Constructors ===================================================================================================
public PrincipalSid(String principal) {
Assert.hasText(principal, "Principal required");
this.principal = principal;
}
public PrincipalSid(Authentication authentication) {
Assert.notNull(authentication, "Authentication required");
Assert.notNull(authentication.getPrincipal(), "Principal required");
this.principal = authentication.getPrincipal().toString();
if (authentication.getPrincipal() instanceof UserDetails) {
this.principal = ((UserDetails) authentication.getPrincipal()).getUsername();
}
}
//~ Methods ========================================================================================================
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 String getPrincipal() {
return principal;
}
public String toString() {
return "PrincipalSid[" + this.principal + "]";
}
}
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.sid;
import org.acegisecurity.Authentication;
import org.acegisecurity.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>
*
* @author Ben Alex
* @version $Id$
*/
public class PrincipalSid implements Sid {
//~ Instance fields ================================================================================================
private String principal;
//~ Constructors ===================================================================================================
public PrincipalSid(String principal) {
Assert.hasText(principal, "Principal required");
this.principal = principal;
}
public PrincipalSid(Authentication authentication) {
Assert.notNull(authentication, "Authentication required");
Assert.notNull(authentication.getPrincipal(), "Principal required");
this.principal = authentication.getPrincipal().toString();
if (authentication.getPrincipal() instanceof UserDetails) {
this.principal = ((UserDetails) authentication.getPrincipal()).getUsername();
}
}
//~ Methods ========================================================================================================
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 String getPrincipal() {
return principal;
}
public String toString() {
return "PrincipalSid[" + this.principal + "]";
}
}
@@ -1,20 +1,19 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.sid;
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.sid;
/**
* A security identity recognised by the ACL system.
*
@@ -29,23 +28,23 @@ package org.acegisecurity.acls.sid;
*
* @author Ben Alex
* @version $Id$
*/
public interface Sid {
//~ 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
*/
public 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
*/
public int hashCode();
}
*/
public interface Sid {
//~ 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
*/
public 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
*/
public int hashCode();
}
@@ -0,0 +1,32 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.sid;
import org.acegisecurity.Authentication;
/**
* Strategy interface that provides an ability to determine the {@link Sid} instances applicable
* for an {@link Authentication}.
*
* @author Ben Alex
* @version $Id$
*/
public interface SidRetrievalStrategy {
//~ Methods ========================================================================================================
public Sid[] getSids(Authentication authentication);
}
@@ -0,0 +1,48 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.acls.sid;
import org.acegisecurity.Authentication;
import org.acegisecurity.GrantedAuthority;
import java.util.List;
import java.util.Vector;
/**
* Basic implementation of {@link SidRetrievalStrategy} that creates a {@link Sid} for the principal, as well as
* every granted authority the principal holds.<p>The returned array will always contain the {@link PrincipalSid}
* before any {@link GrantedAuthoritySid} elements.</p>
*
* @author Ben Alex
* @version $Id$
*/
public class SidRetrievalStrategyImpl implements SidRetrievalStrategy {
//~ Methods ========================================================================================================
public Sid[] getSids(Authentication authentication) {
List list = new Vector();
list.add(new PrincipalSid(authentication));
GrantedAuthority[] authorities = authentication.getAuthorities();
for (int i = 0; i < authorities.length; i++) {
list.add(new GrantedAuthoritySid(authorities[i]));
}
return (Sid[]) list.toArray(new Sid[] {});
}
}
@@ -0,0 +1,5 @@
<html>
<body>
Provides indirection between ACL packages and security identities, such as principals and GrantedAuthority[]s.
</body>
</html>
@@ -29,6 +29,7 @@ import java.security.Principal;
public class PrincipalAcegiUserToken extends AbstractAdapterAuthenticationToken implements Principal {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private Object principal;
private String password;
private String username;
@@ -0,0 +1,130 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.afterinvocation;
import org.acegisecurity.Authentication;
import org.acegisecurity.ConfigAttribute;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.AclService;
import org.acegisecurity.acls.NotFoundException;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.domain.BasePermission;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.objectidentity.ObjectIdentityRetrievalStrategy;
import org.acegisecurity.acls.objectidentity.ObjectIdentityRetrievalStrategyImpl;
import org.acegisecurity.acls.sid.Sid;
import org.acegisecurity.acls.sid.SidRetrievalStrategy;
import org.acegisecurity.acls.sid.SidRetrievalStrategyImpl;
import org.springframework.util.Assert;
/**
* DOCUMENT ME!
*
* @author $author$
* @version $Revision$
*/
public abstract class AbstractAclProvider implements AfterInvocationProvider {
//~ Instance fields ================================================================================================
private AclService aclService;
private Class processDomainObjectClass = Object.class;
private ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy = new ObjectIdentityRetrievalStrategyImpl();
private SidRetrievalStrategy sidRetrievalStrategy = new SidRetrievalStrategyImpl();
private String processConfigAttribute;
private Permission[] requirePermission = {BasePermission.READ};
//~ Constructors ===================================================================================================
public AbstractAclProvider(AclService aclService, String processConfigAttribute, Permission[] requirePermission) {
Assert.hasText(processConfigAttribute, "A processConfigAttribute is mandatory");
Assert.notNull(aclService, "An AclService is mandatory");
if ((requirePermission == null) || (requirePermission.length == 0)) {
throw new IllegalArgumentException("One or more requirePermission entries is mandatory");
}
this.aclService = aclService;
this.processConfigAttribute = processConfigAttribute;
this.requirePermission = requirePermission;
}
//~ Methods ========================================================================================================
protected Class getProcessDomainObjectClass() {
return processDomainObjectClass;
}
protected boolean hasPermission(Authentication authentication, Object domainObject) {
// Obtain the OID applicable to the domain object
ObjectIdentity objectIdentity = objectIdentityRetrievalStrategy.getObjectIdentity(domainObject);
// Obtain the SIDs applicable to the principal
Sid[] sids = sidRetrievalStrategy.getSids(authentication);
Acl acl = null;
try {
// Lookup only ACLs for SIDs we're interested in
acl = aclService.readAclById(objectIdentity, sids);
return acl.isGranted(requirePermission, sids, false);
} catch (NotFoundException ignore) {
return false;
}
}
public void setObjectIdentityRetrievalStrategy(ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy) {
Assert.notNull(objectIdentityRetrievalStrategy, "ObjectIdentityRetrievalStrategy required");
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
}
protected void setProcessConfigAttribute(String processConfigAttribute) {
Assert.hasText(processConfigAttribute, "A processConfigAttribute is mandatory");
this.processConfigAttribute = processConfigAttribute;
}
public void setProcessDomainObjectClass(Class processDomainObjectClass) {
Assert.notNull(processDomainObjectClass, "processDomainObjectClass cannot be set to null");
this.processDomainObjectClass = processDomainObjectClass;
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
this.sidRetrievalStrategy = sidRetrievalStrategy;
}
public boolean supports(ConfigAttribute attribute) {
if ((attribute.getAttribute() != null) && attribute.getAttribute().equals(this.processConfigAttribute)) {
return true;
} else {
return false;
}
}
/**
* 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;
}
}
@@ -0,0 +1,133 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.afterinvocation;
import org.acegisecurity.AccessDeniedException;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthorizationServiceException;
import org.acegisecurity.ConfigAttribute;
import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.AclService;
import org.acegisecurity.acls.Permission;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.Collection;
import java.util.Iterator;
/**
* <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}.</p>
* <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.</p>
* <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 Acl#isGranted(org.acegisecurity.acls.Permission[], org.acegisecurity.acls.sid.Sid[], boolean)}
* when presenting the {@link #requirePermission} array to that method.</p>
* <p>If the principal does not have permission, that element will not be included in the returned
* <code>Collection</code>.</p>
* <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.</p>
* <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.</p>
* <p>All comparisons and prefixes are case sensitive.</p>
*
* @author Ben Alex
* @author Paulo Neves
* @version $Id$
*/
public class AclEntryAfterInvocationCollectionFilteringProvider extends AbstractAclProvider {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationCollectionFilteringProvider.class);
//~ Constructors ===================================================================================================
public AclEntryAfterInvocationCollectionFilteringProvider(AclService aclService, Permission[] requirePermission) {
super(aclService, "AFTER_ACL_COLLECTION_READ", requirePermission);
}
//~ Methods ========================================================================================================
public Object decide(Authentication authentication, Object object, ConfigAttributeDefinition config,
Object returnedObject) throws AccessDeniedException {
Iterator iter = config.getConfigAttributes();
while (iter.hasNext()) {
ConfigAttribute attr = (ConfigAttribute) iter.next();
if (this.supports(attr)) {
// Need to process the Collection for this invocation
if (returnedObject == null) {
if (logger.isDebugEnabled()) {
logger.debug("Return object is null, skipping");
}
return null;
}
Filterer filterer = null;
if (returnedObject instanceof Collection) {
Collection collection = (Collection) returnedObject;
filterer = new CollectionFilterer(collection);
} else if (returnedObject.getClass().isArray()) {
Object[] array = (Object[]) returnedObject;
filterer = new ArrayFilterer(array);
} 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
Iterator collectionIter = filterer.iterator();
while (collectionIter.hasNext()) {
Object domainObject = collectionIter.next();
boolean hasPermission = false;
if (domainObject == null) {
hasPermission = true;
} else if (!getProcessDomainObjectClass().isAssignableFrom(domainObject.getClass())) {
hasPermission = true;
} else {
hasPermission = hasPermission(authentication, domainObject);
if (!hasPermission) {
filterer.remove(domainObject);
if (logger.isDebugEnabled()) {
logger.debug("Principal is NOT authorised for element: " + domainObject);
}
}
}
}
return filterer.getFilteredObject();
}
}
return returnedObject;
}
}
@@ -0,0 +1,119 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.afterinvocation;
import org.acegisecurity.AccessDeniedException;
import org.acegisecurity.AcegiMessageSource;
import org.acegisecurity.Authentication;
import org.acegisecurity.ConfigAttribute;
import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.AclService;
import org.acegisecurity.acls.Permission;
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;
import java.util.Iterator;
/**
* <p>Given a domain object instance returned from a secure object invocation, ensures the principal has
* appropriate permission as defined by the {@link AclService}.</p>
* <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.</p>
* <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 Acl#isGranted(org.acegisecurity.acls.Permission[], org.acegisecurity.acls.sid.Sid[], boolean)}
* when presenting the {@link #requirePermission} array to that method.</p>
* <p>Often users will setup 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>
* <p>If the principal does not have sufficient permissions, an <code>AccessDeniedException</code> will be thrown.</p>
* <p>If the provided <code>returnObject</code> is <code>null</code>, permission will always be granted and
* <code>null</code> will be returned.</p>
* <p>All comparisons and prefixes are case sensitive.</p>
*/
public class AclEntryAfterInvocationProvider extends AbstractAclProvider implements MessageSourceAware {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(AclEntryAfterInvocationProvider.class);
//~ Instance fields ================================================================================================
protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
//~ Constructors ===================================================================================================
public AclEntryAfterInvocationProvider(AclService aclService, Permission[] requirePermission) {
super(aclService, "AFTER_ACL_READ", requirePermission);
}
//~ Methods ========================================================================================================
public Object decide(Authentication authentication, Object object, ConfigAttributeDefinition config,
Object returnedObject) throws AccessDeniedException {
Iterator iter = config.getConfigAttributes();
while (iter.hasNext()) {
ConfigAttribute attr = (ConfigAttribute) iter.next();
if (this.supports(attr)) {
// Need to make an access decision on this invocation
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");
}
return null;
}
if (!getProcessDomainObjectClass().isAssignableFrom(returnedObject.getClass())) {
if (logger.isDebugEnabled()) {
logger.debug("Return object is not applicable for this provider, skipping");
}
return null;
}
if (hasPermission(authentication, returnedObject)) {
return returnedObject;
} else {
if (logger.isDebugEnabled()) {
logger.debug("Denying access");
}
throw new AccessDeniedException(messages.getMessage(
"BasicAclEntryAfterInvocationProvider.noPermission",
new Object[] {authentication.getName(), returnedObject},
"Authentication {0} has NO permissions to the domain object {1}"));
}
}
}
return returnedObject;
}
public void setMessageSource(MessageSource messages) {
this.messages = new MessageSourceAccessor(messages);
}
}
@@ -0,0 +1,101 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.afterinvocation;
import org.apache.commons.collections.iterators.ArrayIterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.lang.reflect.Array;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* A filter used to filter arrays.
*
* @author Ben Alex
* @author Paulo Neves
* @version $Id$
*/
class ArrayFilterer implements Filterer {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(BasicAclEntryAfterInvocationCollectionFilteringProvider.class);
//~ Instance fields ================================================================================================
private Set removeList;
private Object[] list;
//~ Constructors ===================================================================================================
ArrayFilterer(Object[] 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.
removeList = new HashSet();
}
//~ Methods ========================================================================================================
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#getFilteredObject()
*/
public Object getFilteredObject() {
// Recreate an array of same type and filter the removed objects.
int originalSize = list.length;
int sizeOfResultingList = originalSize - removeList.size();
Object[] filtered = (Object[]) Array.newInstance(list.getClass().getComponentType(), sizeOfResultingList);
for (int i = 0, j = 0; i < list.length; i++) {
Object object = list[i];
if (!removeList.contains(object)) {
filtered[j] = object;
j++;
}
}
if (logger.isDebugEnabled()) {
logger.debug("Original array contained " + originalSize + " elements; now contains " + sizeOfResultingList
+ " elements");
}
return filtered;
}
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#iterator()
*/
public Iterator iterator() {
return new ArrayIterator(list);
}
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#remove(java.lang.Object)
*/
public void remove(Object object) {
removeList.add(object);
}
}
@@ -12,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.afterinvocation;
import org.acegisecurity.AccessDeniedException;
@@ -26,7 +25,6 @@ import org.acegisecurity.acl.AclManager;
import org.acegisecurity.acl.basic.BasicAclEntry;
import org.acegisecurity.acl.basic.SimpleAclEntry;
import org.apache.commons.collections.iterators.ArrayIterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -34,12 +32,8 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
@@ -135,42 +129,40 @@ public class BasicAclEntryAfterInvocationCollectionFilteringProvider implements
boolean hasPermission = false;
AclEntry[] acls = null;
if (domainObject == null) {
hasPermission = true;
} else if (!processDomainObjectClass.isAssignableFrom(domainObject.getClass())) {
hasPermission = true;
} else {
acls = aclManager.getAcls(domainObject, authentication);
}
AclEntry[] acls = aclManager.getAcls(domainObject, authentication);
if ((acls != null) && (acls.length != 0)) {
for (int i = 0; i < acls.length; i++) {
// Locate processable AclEntrys
if (acls[i] instanceof BasicAclEntry) {
BasicAclEntry processableAcl = (BasicAclEntry) acls[i];
if ((acls != null) && (acls.length != 0)) {
for (int i = 0; i < acls.length; i++) {
// Locate processable AclEntrys
if (acls[i] instanceof BasicAclEntry) {
BasicAclEntry processableAcl = (BasicAclEntry) acls[i];
// See if principal has any of the required permissions
for (int y = 0; y < requirePermission.length; y++) {
if (processableAcl.isPermitted(requirePermission[y])) {
hasPermission = true;
// See if principal has any of the required permissions
for (int y = 0; y < requirePermission.length; y++) {
if (processableAcl.isPermitted(requirePermission[y])) {
hasPermission = true;
if (logger.isDebugEnabled()) {
logger.debug("Principal is authorised for element: " + domainObject
+ " due to ACL: " + processableAcl.toString());
if (logger.isDebugEnabled()) {
logger.debug("Principal is authorised for element: " + domainObject
+ " due to ACL: " + processableAcl.toString());
}
}
}
}
}
}
}
if (!hasPermission) {
filterer.remove(domainObject);
if (!hasPermission) {
filterer.remove(domainObject);
if (logger.isDebugEnabled()) {
logger.debug("Principal is NOT authorised for element: " + domainObject);
if (logger.isDebugEnabled()) {
logger.debug("Principal is NOT authorised for element: " + domainObject);
}
}
}
}
@@ -211,6 +203,18 @@ public class BasicAclEntryAfterInvocationCollectionFilteringProvider implements
this.requirePermission = requirePermission;
}
/**
* Allow setting permissions with String literals instead of integers as {@link
* #setRequirePermission(int[])}
*
* @param requirePermission permission literals
*
* @see SimpleAclEntry#parsePermissions(String[]) for valid values
*/
public void setRequirePermissionFromString(String[] requirePermission) {
setRequirePermission(SimpleAclEntry.parsePermissions(requirePermission));
}
public boolean supports(ConfigAttribute attribute) {
if ((attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute())) {
return true;
@@ -230,179 +234,3 @@ public class BasicAclEntryAfterInvocationCollectionFilteringProvider implements
return true;
}
}
/**
* Filter strategy interface.
*/
interface Filterer {
//~ Methods ========================================================================================================
/**
* Gets the filtered collection or array.
*
* @return the filtered collection or array
*/
public Object getFilteredObject();
/**
* Returns an iterator over the filtered collection or array.
*
* @return an Iterator
*/
public Iterator iterator();
/**
* Removes the the given object from the resulting list.
*
* @param object the object to be removed
*/
public void remove(Object object);
}
/**
* A filter used to filter Collections.
*/
class CollectionFilterer implements Filterer {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(BasicAclEntryAfterInvocationCollectionFilteringProvider.class);
//~ Instance fields ================================================================================================
private Collection collection;
// collectionIter offers significant performance optimisations (as
// per acegisecurity-developer mailing list conversation 19/5/05)
private Iterator collectionIter;
private Set removeList;
//~ Constructors ===================================================================================================
CollectionFilterer(Collection 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)
removeList = new HashSet();
}
//~ Methods ========================================================================================================
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#getFilteredObject()
*/
public Object getFilteredObject() {
// Now the Iterator has ended, remove Objects from Collection
Iterator 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.acegisecurity.afterinvocation.Filterer#iterator()
*/
public Iterator iterator() {
collectionIter = collection.iterator();
return collectionIter;
}
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#remove(java.lang.Object)
*/
public void remove(Object object) {
collectionIter.remove();
}
}
/**
* A filter used to filter arrays.
*/
class ArrayFilterer implements Filterer {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(BasicAclEntryAfterInvocationCollectionFilteringProvider.class);
//~ Instance fields ================================================================================================
private Set removeList;
private Object[] list;
//~ Constructors ===================================================================================================
ArrayFilterer(Object[] 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.
removeList = new HashSet();
}
//~ Methods ========================================================================================================
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#getFilteredObject()
*/
public Object getFilteredObject() {
// Recreate an array of same type and filter the removed objects.
int originalSize = list.length;
int sizeOfResultingList = originalSize - removeList.size();
Object[] filtered = (Object[]) Array.newInstance(list.getClass().getComponentType(), sizeOfResultingList);
for (int i = 0, j = 0; i < list.length; i++) {
Object object = list[i];
if (!removeList.contains(object)) {
filtered[j] = object;
j++;
}
}
if (logger.isDebugEnabled()) {
logger.debug("Original array contained " + originalSize + " elements; now contains " + sizeOfResultingList
+ " elements");
}
return filtered;
}
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#iterator()
*/
public Iterator iterator() {
return new ArrayIterator(list);
}
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#remove(java.lang.Object)
*/
public void remove(Object object) {
removeList.add(object);
}
}
@@ -39,7 +39,6 @@ import org.springframework.util.Assert;
import java.util.Iterator;
/**
* <p>Given a domain object instance returned from a secure object invocation, ensures the principal has
* appropriate permission as defined by the {@link AclManager}.</p>
@@ -187,6 +186,16 @@ public class BasicAclEntryAfterInvocationProvider implements AfterInvocationProv
this.requirePermission = requirePermission;
}
/**
* Allow setting permissions with String literals instead of integers as {@link #setRequirePermission(int[])}
*
* @param requirePermission Permission literals
* @see SimpleAclEntry#parsePermissions(String[]) for valid values
*/
public void setRequirePermissionFromString(String[] requirePermission) {
setRequirePermission(SimpleAclEntry.parsePermissions(requirePermission));
}
public boolean supports(ConfigAttribute attribute) {
if ((attribute.getAttribute() != null) && attribute.getAttribute().equals(getProcessConfigAttribute())) {
return true;
@@ -0,0 +1,104 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.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;
/**
* A filter used to filter Collections.
*
* @author Ben Alex
* @author Paulo Neves
* @version $Id$
*/
class CollectionFilterer implements Filterer {
//~ Static fields/initializers =====================================================================================
protected static final Log logger = LogFactory.getLog(BasicAclEntryAfterInvocationCollectionFilteringProvider.class);
//~ Instance fields ================================================================================================
private Collection collection;
// collectionIter offers significant performance optimisations (as
// per acegisecurity-developer mailing list conversation 19/5/05)
private Iterator collectionIter;
private Set removeList;
//~ Constructors ===================================================================================================
CollectionFilterer(Collection 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)
removeList = new HashSet();
}
//~ Methods ========================================================================================================
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#getFilteredObject()
*/
public Object getFilteredObject() {
// Now the Iterator has ended, remove Objects from Collection
Iterator 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.acegisecurity.afterinvocation.Filterer#iterator()
*/
public Iterator iterator() {
collectionIter = collection.iterator();
return collectionIter;
}
/**
*
* @see org.acegisecurity.afterinvocation.Filterer#remove(java.lang.Object)
*/
public void remove(Object object) {
removeList.add(object);
}
}
@@ -13,39 +13,39 @@
* limitations under the License.
*/
package org.acegisecurity.domain.impl;
package org.acegisecurity.afterinvocation;
import java.io.Serializable;
import java.util.Iterator;
/**
* A persistable entity that uses a <code>Integer</code> based identity.
*
* Filter strategy interface.
*
* @author Ben Alex
* @author Paulo Neves
* @version $Id$
*/
public abstract class PersistableEntityInteger extends AbstractPersistableEntity {
//~ Instance fields ================================================================================================
private Integer id;
interface Filterer {
//~ Methods ========================================================================================================
/**
* Obtains the persistence identity of this instance.
* Gets the filtered collection or array.
*
* @return DOCUMENT ME!
* @return the filtered collection or array
*/
public Integer getId() {
return this.id;
}
public Object getFilteredObject();
/**
* Required solely because Hibernate
* Returns an iterator over the filtered collection or array.
*
* @return DOCUMENT ME!
* @return an Iterator
*/
public Serializable getInternalId() {
return this.id;
}
public Iterator iterator();
/**
* Removes the the given object from the resulting list.
*
* @param object the object to be removed
*/
public void remove(Object object);
}
@@ -15,12 +15,8 @@
package org.acegisecurity.context;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import java.io.IOException;
import java.lang.reflect.Method;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
@@ -31,6 +27,12 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
/**
* <p>Populates the {@link SecurityContextHolder} with information obtained from the <code>HttpSession</code>.</p>
@@ -71,16 +73,12 @@ import javax.servlet.http.HttpSession;
public class HttpSessionContextIntegrationFilter implements InitializingBean, Filter {
//~ Static fields/initializers =====================================================================================
// ~ Static fields/initializers
// =============================================
protected static final Log logger = LogFactory.getLog(HttpSessionContextIntegrationFilter.class);
private static final String FILTER_APPLIED = "__acegi_session_integration_filter_applied";
public static final String ACEGI_SECURITY_CONTEXT_KEY = "ACEGI_SECURITY_CONTEXT";
//~ Instance fields ================================================================================================
// ~ Instance fields
// ========================================================
private Class context = SecurityContextImpl.class;
private Object contextObject;
@@ -103,6 +101,30 @@ public class HttpSessionContextIntegrationFilter implements InitializingBean, Fi
* are conscious of the session creation overhead.
*/
private boolean forceEagerSessionCreation = false;
/**
* Indicates whether the <code>SecurityContext</code> will be cloned from the <code>HttpSession</code>. The
* default is to simply reference (ie the default is <code>false</code>). The default may cause issues if
* concurrent threads need to have a different security identity from other threads being concurrently processed
* that share the same <code>HttpSession</code>. In most normal environments this does not represent an issue,
* as changes to the security identity in one thread is allowed to affect the security identitiy in other
* threads associated with the same <code>HttpSession</code>. For unusual cases where this is not permitted,
* change this value to <code>true</code> and ensure the {@link #context} is set to a <code>SecurityContext</code>
* that implements {@link Cloneable} and overrides the <code>clone()</code> method.
*/
private boolean cloneFromHttpSession = false;
public boolean isCloneFromHttpSession() {
return cloneFromHttpSession;
}
public void setCloneFromHttpSession(boolean cloneFromHttpSession) {
this.cloneFromHttpSession = cloneFromHttpSession;
}
public HttpSessionContextIntegrationFilter() throws ServletException {
this.contextObject = generateNewContext();
}
//~ Methods ========================================================================================================
@@ -117,8 +139,6 @@ public class HttpSessionContextIntegrationFilter implements InitializingBean, Fi
throw new IllegalArgumentException(
"If using forceEagerSessionCreation, you must set allowSessionCreation to also be true");
}
this.contextObject = generateNewContext();
}
/**
@@ -147,7 +167,21 @@ public class HttpSessionContextIntegrationFilter implements InitializingBean, Fi
httpSessionExistedAtStartOfRequest = true;
Object contextFromSessionObject = httpSession.getAttribute(ACEGI_SECURITY_CONTEXT_KEY);
// Clone if required (see SEC-356)
if (cloneFromHttpSession) {
Assert.isInstanceOf(Cloneable.class, contextFromSessionObject, "Context must implement Clonable and provide a Object.clone() method");
try {
Method m = contextFromSessionObject.getClass().getMethod("clone", new Class[] {});
if (!m.isAccessible()) {
m.setAccessible(true);
}
contextFromSessionObject = m.invoke(contextFromSessionObject, new Object[] {});
} catch (Exception ex) {
ReflectionUtils.handleReflectionException(ex);
}
}
if (contextFromSessionObject != null) {
if (contextFromSessionObject instanceof SecurityContext) {
if (logger.isDebugEnabled()) {
@@ -287,8 +321,6 @@ public class HttpSessionContextIntegrationFilter implements InitializingBean, Fi
return allowSessionCreation;
}
// ~ Methods
// ================================================================
public boolean isForceEagerSessionCreation() {
return forceEagerSessionCreation;
}
@@ -30,11 +30,11 @@ import java.lang.reflect.Constructor;
* three valid <code>MODE_</code> settings defined as <code>static final</code> fields, or a fully qualified classname
* to a concrete implementation of {@link org.acegisecurity.context.SecurityContextHolderStrategy} that provides a
* public no-argument constructor.</p>
* <p>There are two ways to specify the desired mode <code>String</code>. The first is to specify it via the
* system property keyed on {@link #SYSTEM_PROPERTY}. The second is to call {@link #setStrategyName(String)} before
* using the class. If neither approach is used, the class will default to using {@link #MODE_THREADLOCAL}, which is
* backwards compatible, has fewer JVM incompatibilities and is appropriate on servers (whereas {@link #MODE_GLOBAL}
* is not).</p>
* <p>There are two ways to specify the desired strategy mode <code>String</code>. The first is to specify it via
* the system property keyed on {@link #SYSTEM_PROPERTY}. The second is to call {@link #setStrategyName(String)}
* before using the class. If neither approach is used, the class will default to using {@link #MODE_THREADLOCAL},
* which is backwards compatible, has fewer JVM incompatibilities and is appropriate on servers (whereas {@link
* #MODE_GLOBAL} is definitely inappropriate for server use).</p>
*
* @author Ben Alex
* @version $Id$
@@ -49,8 +49,12 @@ public class SecurityContextHolder {
public static final String MODE_GLOBAL = "MODE_GLOBAL";
public static final String SYSTEM_PROPERTY = "acegi.security.strategy";
private static String strategyName = System.getProperty(SYSTEM_PROPERTY);
private static Constructor customStrategy;
private static SecurityContextHolderStrategy strategy;
private static int initializeCount = 0;
static {
initialize();
}
//~ Methods ========================================================================================================
@@ -58,7 +62,6 @@ public class SecurityContextHolder {
* Explicitly clears the context value from the current thread.
*/
public static void clearContext() {
initialize();
strategy.clearContext();
}
@@ -68,11 +71,20 @@ public class SecurityContextHolder {
* @return the security context (never <code>null</code>)
*/
public static SecurityContext getContext() {
initialize();
return strategy.getContext();
}
/**
* Primarily for troubleshooting purposes, this method shows how many times the class has reinitialized its
* <code>SecurityContextHolderStrategy</code>.
*
* @return the count (should be one unless you've called {@link #setStrategyName(String)} to switch to an alternate
* strategy.
*/
public static int getInitializeCount() {
return initializeCount;
}
private static void initialize() {
if ((strategyName == null) || "".equals(strategyName)) {
// Set default
@@ -88,16 +100,15 @@ public class SecurityContextHolder {
} else {
// Try to load a custom strategy
try {
if (customStrategy == null) {
Class clazz = Class.forName(strategyName);
customStrategy = clazz.getConstructor(new Class[] {});
}
Class clazz = Class.forName(strategyName);
Constructor customStrategy = clazz.getConstructor(new Class[] {});
strategy = (SecurityContextHolderStrategy) customStrategy.newInstance(new Object[] {});
} catch (Exception ex) {
ReflectionUtils.handleReflectionException(ex);
}
}
initializeCount++;
}
/**
@@ -106,7 +117,6 @@ public class SecurityContextHolder {
* @param context the new <code>SecurityContext</code> (may not be <code>null</code>)
*/
public static void setContext(SecurityContext context) {
initialize();
strategy.setContext(context);
}
@@ -122,6 +132,6 @@ public class SecurityContextHolder {
}
public String toString() {
return "SecurityContextHolder[strategy='" + strategyName + "']";
return "SecurityContextHolder[strategy='" + strategyName + "'; initializeCount=" + initializeCount + "]";
}
}
@@ -72,7 +72,7 @@ public class SecurityContextImpl implements SecurityContext {
if (this.authentication == null) {
sb.append(": Null authentication");
} else {
sb.append(": Authentication: " + this.authentication);
sb.append(": Authentication: ").append(this.authentication);
}
return sb.toString();
@@ -15,13 +15,19 @@
package org.acegisecurity.event.authorization;
import org.acegisecurity.AccessDecisionManager;
import org.acegisecurity.AccessDeniedException;
import org.acegisecurity.AfterInvocationManager;
import org.acegisecurity.Authentication;
import org.acegisecurity.ConfigAttributeDefinition;
/**
* Indicates a secure object invocation failed because the principal could not be authorized for the request.
* Indicates a secure object invocation failed because the principal could not
* be authorized for the request.
*
* <p>This event might be thrown as a result of either an
* {@link AccessDecisionManager} or an {@link AfterInvocationManager}.
*
* @author Ben Alex
* @version $Id$
@@ -41,6 +41,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.MessageSource;
@@ -147,8 +148,17 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
}
if (afterInvocationManager != null) {
returnedObject = afterInvocationManager.decide(token.getAuthentication(), token.getSecureObject(),
token.getAttr(), returnedObject);
// Attempt after invocation handling
try {
returnedObject = afterInvocationManager.decide(token.getAuthentication(), token.getSecureObject(),
token.getAttr(), returnedObject);
} catch (AccessDeniedException accessDeniedException) {
AuthorizationFailureEvent event = new AuthorizationFailureEvent(token.getSecureObject(),
token.getAttr(), token.getAuthentication(), accessDeniedException);
publishEvent(event);
throw accessDeniedException;
}
}
return returnedObject;
@@ -276,7 +286,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
} catch (AccessDeniedException accessDeniedException) {
AuthorizationFailureEvent event = new AuthorizationFailureEvent(object, attr, authenticated,
accessDeniedException);
this.eventPublisher.publishEvent(event);
publishEvent(event);
throw accessDeniedException;
}
@@ -286,7 +296,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
}
AuthorizedEvent event = new AuthorizedEvent(object, attr, authenticated);
this.eventPublisher.publishEvent(event);
publishEvent(event);
// Attempt to run as a different user
Authentication runAs = this.runAsManager.buildRunAs(authenticated, object, attr);
@@ -311,7 +321,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
logger.debug("Public object - authentication not attempted");
}
this.eventPublisher.publishEvent(new PublicInvocationEvent(object));
publishEvent(new PublicInvocationEvent(object));
return null; // no further work post-invocation
}
@@ -330,7 +340,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
AuthenticationCredentialsNotFoundEvent event = new AuthenticationCredentialsNotFoundEvent(secureObject,
configAttribs, exception);
this.eventPublisher.publishEvent(event);
publishEvent(event);
throw exception;
}
@@ -431,4 +441,10 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
public void setValidateConfigAttributes(boolean validateConfigAttributes) {
this.validateConfigAttributes = validateConfigAttributes;
}
private void publishEvent(ApplicationEvent event) {
if (this.eventPublisher != null) {
this.eventPublisher.publishEvent(event);
}
}
}
@@ -17,6 +17,7 @@ package org.acegisecurity.intercept.method;
import org.acegisecurity.ConfigAttribute;
import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.SecurityConfig;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -232,4 +233,25 @@ public class MethodDefinitionMap extends AbstractMethodDefinitionSource {
definition.addConfigAttribute((ConfigAttribute) attribs.next());
}
}
/**
* Easier configuration of the instance, using {@link MethodDefinitionSourceMapping}.
*
* @param mappings {@link List} of {@link MethodDefinitionSourceMapping} objects.
*/
public void setMappings(List mappings) {
Iterator it = mappings.iterator();
while (it.hasNext()) {
MethodDefinitionSourceMapping mapping = (MethodDefinitionSourceMapping) it.next();
ConfigAttributeDefinition configDefinition = new ConfigAttributeDefinition();
Iterator configAttributesIt = mapping.getConfigAttributes().iterator();
while (configAttributesIt.hasNext()) {
String s = (String) configAttributesIt.next();
configDefinition.addConfigAttribute(new SecurityConfig(s));
}
addSecureMethod(mapping.getMethodName(), configDefinition);
}
}
}
@@ -15,17 +15,17 @@
package org.acegisecurity.intercept.method;
import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.ConfigAttributeEditor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.propertyeditors.PropertiesEditor;
import org.springframework.util.StringUtils;
import java.beans.PropertyEditorSupport;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
@@ -56,20 +56,24 @@ public class MethodDefinitionSourceEditor extends PropertyEditorSupport {
Properties props = (Properties) propertiesEditor.getValue();
// Now we have properties, process each one individually
ConfigAttributeEditor configAttribEd = new ConfigAttributeEditor();
List mappings = new ArrayList();
for (Iterator iter = props.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String value = props.getProperty(name);
// Convert value to series of security configuration attributes
configAttribEd.setAsText(value);
MethodDefinitionSourceMapping mapping = new MethodDefinitionSourceMapping();
mapping.setMethodName(name);
ConfigAttributeDefinition attr = (ConfigAttributeDefinition) configAttribEd.getValue();
String[] tokens = StringUtils.commaDelimitedListToStringArray(value);
// Register name and attribute
source.addSecureMethod(name, attr);
for (int i = 0; i < tokens.length; i++) {
mapping.addConfigAttribute(tokens[i].trim());
}
mappings.add(mapping);
}
source.setMappings(mappings);
}
setValue(source);
@@ -0,0 +1,82 @@
/* Copyright 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.intercept.method;
import java.util.ArrayList;
import java.util.List;
import org.acegisecurity.ConfigAttribute;
/**
* Configuration entry for {@link MethodDefinitionSource}, that holds
* the method to be protected and the {@link ConfigAttribute}s as {@link String}
* that apply to that url.
*
* @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
* @version $Id$
* @since 1.1
*/
public class MethodDefinitionSourceMapping {
private String methodName;
private List configAttributes = new ArrayList();
/**
* Name of the method to be secured, including package and class name.
* eg. <code>org.mydomain.MyClass.myMethod</code>
*
* @param methodName
*/
public void setMethodName(String methodName) {
this.methodName = methodName;
}
/**
* Name of the method to be secured.
*
* @return the name of the method
*/
public String getMethodName() {
return methodName;
}
/**
*
* @param roles {@link List}&lt;{@link String}>
*/
public void setConfigAttributes(List roles) {
this.configAttributes = roles;
}
/**
*
* @return {@link List}&lt;{@link String}>
*/
public List getConfigAttributes() {
return configAttributes;
}
/**
* Add a {@link ConfigAttribute} as {@link String}
*
* @param configAttribute
*/
public void addConfigAttribute(String configAttribute) {
configAttributes.add(configAttribute);
}
}
@@ -0,0 +1,27 @@
/* Copyright 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.intercept.web;
/**
* Interface to join {@link FilterInvocationDefinitionMap} and
* {@link FilterInvocationDefinitionSource}.
*
* @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
* @version $Id$
* @since 1.1
*/
public interface FilterInvocationDefinition extends FilterInvocationDefinitionMap, FilterInvocationDefinitionSource {
}
@@ -0,0 +1,153 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.intercept.web;
import java.util.Iterator;
import java.util.List;
import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.SecurityConfig;
/**
* <p>
* Decorator of {@link FilterInvocationDefinition} for easier configuration,
* using {@link FilterInvocationDefinitionSourceMapping}.
* </p>
*
* <p>
* Delegates all calls to decorated object set in constructor
* {@link #FilterInvocationDefinitionDecorator(FilterInvocationDefinition)} or
* by calling {@link #setDecorated(FilterInvocationDefinition)}
* </p>
*
* @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
* @version $Id$
* @since 1.1
*/
public class FilterInvocationDefinitionDecorator implements FilterInvocationDefinition {
private FilterInvocationDefinition decorated;
private List mappings;
public FilterInvocationDefinitionDecorator() {
}
public FilterInvocationDefinitionDecorator(FilterInvocationDefinition decorated) {
this.setDecorated(decorated);
}
/**
* Set the decorated object
*
* @param decorated
* the decorated {@link FilterInvocationDefinition}
*/
public void setDecorated(FilterInvocationDefinition decorated) {
this.decorated = decorated;
}
/**
* Get decorated object
*
* @return the decorated {@link FilterInvocationDefinition}
*/
public FilterInvocationDefinition getDecorated() {
return decorated;
}
/**
* Configures the decorated {@link FilterInvocationDefinitionMap} easier,
* using {@link FilterInvocationDefinitionSourceMapping}.
*
* @param mappings
* {@link List} of
* {@link FilterInvocationDefinitionSourceMapping} objects.
*/
public void setMappings(List mappings) {
if (decorated == null) {
throw new IllegalStateException("decorated object has not been set");
}
this.mappings = mappings;
Iterator it = mappings.iterator();
while (it.hasNext()) {
FilterInvocationDefinitionSourceMapping mapping = (FilterInvocationDefinitionSourceMapping) it.next();
ConfigAttributeDefinition configDefinition = new ConfigAttributeDefinition();
Iterator configAttributesIt = mapping.getConfigAttributes().iterator();
while (configAttributesIt.hasNext()) {
String s = (String) configAttributesIt.next();
configDefinition.addConfigAttribute(new SecurityConfig(s));
}
decorated.addSecureUrl(mapping.getUrl(), configDefinition);
}
}
/**
* Get the mappings used for configuration.
*
* @return {@link List} of {@link FilterInvocationDefinitionSourceMapping}
* objects.
*/
public List getMappings() {
return mappings;
}
/**
* Delegate to decorated object
*/
public void addSecureUrl(String expression, ConfigAttributeDefinition attr) {
getDecorated().addSecureUrl(expression, attr);
}
/**
* Delegate to decorated object
*/
public boolean isConvertUrlToLowercaseBeforeComparison() {
return getDecorated().isConvertUrlToLowercaseBeforeComparison();
}
/**
* Delegate to decorated object
*/
public void setConvertUrlToLowercaseBeforeComparison(boolean convertUrlToLowercaseBeforeComparison) {
getDecorated().setConvertUrlToLowercaseBeforeComparison(convertUrlToLowercaseBeforeComparison);
}
/**
* Delegate to decorated object
*/
public ConfigAttributeDefinition getAttributes(Object object) throws IllegalArgumentException {
return getDecorated().getAttributes(object);
}
/**
* Delegate to decorated object
*/
public Iterator getConfigAttributeDefinitions() {
return getDecorated().getConfigAttributeDefinitions();
}
/**
* Delegate to decorated object
*/
public boolean supports(Class clazz) {
return getDecorated().supports(clazz);
}
}
@@ -15,18 +15,17 @@
package org.acegisecurity.intercept.web;
import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.ConfigAttributeEditor;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.beans.PropertyEditorSupport;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import org.acegisecurity.util.StringSplitUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.StringUtils;
/**
@@ -50,19 +49,22 @@ public class FilterInvocationDefinitionSourceEditor extends PropertyEditorSuppor
//~ Methods ========================================================================================================
public void setAsText(String s) throws IllegalArgumentException {
FilterInvocationDefinitionMap source = new RegExpBasedFilterInvocationDefinitionMap();
FilterInvocationDefinitionDecorator source = new FilterInvocationDefinitionDecorator();
if ((s == null) || "".equals(s)) {
// Leave target object empty
source.setDecorated(new RegExpBasedFilterInvocationDefinitionMap());
} else {
// Check if we need to override the default definition map
if (s.lastIndexOf(DIRECTIVE_PATTERN_TYPE_APACHE_ANT) != -1) {
source = new PathBasedFilterInvocationDefinitionMap();
source.setDecorated(new PathBasedFilterInvocationDefinitionMap());
if (logger.isDebugEnabled()) {
logger.debug(("Detected " + DIRECTIVE_PATTERN_TYPE_APACHE_ANT
+ " directive; using Apache Ant style path expressions"));
}
} else {
source.setDecorated(new RegExpBasedFilterInvocationDefinitionMap());
}
if (s.lastIndexOf(DIRECTIVE_CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON) != -1) {
@@ -77,6 +79,8 @@ public class FilterInvocationDefinitionSourceEditor extends PropertyEditorSuppor
BufferedReader br = new BufferedReader(new StringReader(s));
int counter = 0;
String line;
List mappings = new ArrayList();
while (true) {
counter++;
@@ -129,16 +133,16 @@ public class FilterInvocationDefinitionSourceEditor extends PropertyEditorSuppor
// Tokenize the line into its name/value tokens
// As per SEC-219, use the LAST equals as the delimiter between LHS and RHS
String name = StringUtils.substringBeforeLast(line, "=");
String value = StringUtils.substringAfterLast(line, "=");
String name = StringSplitUtils.substringBeforeLast(line, "=");
String value = StringSplitUtils.substringAfterLast(line, "=");
if (StringUtils.isBlank(name) || StringUtils.isBlank(value)) {
if (!StringUtils.hasText(name) || !StringUtils.hasText(value)) {
throw new IllegalArgumentException("Failed to parse a valid name/value pair from " + line);
}
// Attempt to detect malformed lines (as per SEC-204)
if (source.isConvertUrlToLowercaseBeforeComparison()
&& source instanceof PathBasedFilterInvocationDefinitionMap) {
&& source.getDecorated() instanceof PathBasedFilterInvocationDefinitionMap) {
// Should all be lowercase; check each character
// We only do this for Ant (regexp have control chars)
for (int i = 0; i < name.length(); i++) {
@@ -153,17 +157,21 @@ public class FilterInvocationDefinitionSourceEditor extends PropertyEditorSuppor
}
}
// Convert value to series of security configuration attributes
ConfigAttributeEditor configAttribEd = new ConfigAttributeEditor();
configAttribEd.setAsText(value);
FilterInvocationDefinitionSourceMapping mapping = new FilterInvocationDefinitionSourceMapping();
mapping.setUrl(name);
ConfigAttributeDefinition attr = (ConfigAttributeDefinition) configAttribEd.getValue();
String[] tokens = org.springframework.util.StringUtils
.commaDelimitedListToStringArray(value);
// Register the regular expression and its attribute
source.addSecureUrl(name, attr);
for (int i = 0; i < tokens.length; i++) {
mapping.addConfigAttribute(tokens[i].trim());
}
mappings.add(mapping);
}
source.setMappings(mappings);
}
setValue(source);
setValue(source.getDecorated());
}
}
@@ -0,0 +1,82 @@
/* Copyright 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.intercept.web;
import java.util.ArrayList;
import java.util.List;
import org.acegisecurity.ConfigAttribute;
/**
* Configuration entry for {@link FilterInvocationDefinitionSource}, that holds
* the url to be protected and the {@link ConfigAttribute}s as {@link String}
* that apply to that url.
*
* @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
* @version $Id$
* @since 1.1
*/
public class FilterInvocationDefinitionSourceMapping {
private String url;
private List configAttributes = new ArrayList();
/**
* Url to be secured.
*
* @param url
*/
public void setUrl(String url) {
this.url = url;
}
/**
* Url to be secured.
*
* @return the url
*/
public String getUrl() {
return url;
}
/**
*
* @param roles
* {@link List}&lt;{@link String}>
*/
public void setConfigAttributes(List roles) {
this.configAttributes = roles;
}
/**
*
* @return {@link List}&lt;{@link String}>
*/
public List getConfigAttributes() {
return configAttributes;
}
/**
* Add a {@link ConfigAttribute} as {@link String}
*
* @param configAttribute
*/
public void addConfigAttribute(String configAttribute) {
configAttributes.add(configAttribute);
}
}
@@ -44,7 +44,7 @@ import java.util.Vector;
* @version $Id$
*/
public class PathBasedFilterInvocationDefinitionMap extends AbstractFilterInvocationDefinitionSource
implements FilterInvocationDefinitionMap {
implements FilterInvocationDefinition {
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(PathBasedFilterInvocationDefinitionMap.class);
@@ -86,14 +86,14 @@ public class PathBasedFilterInvocationDefinitionMap extends AbstractFilterInvoca
}
public ConfigAttributeDefinition lookupAttributes(String url) {
// Strip anything after a question mark symbol, as per SEC-161.
int firstQuestionMarkIndex = url.lastIndexOf("?");
// Strip anything after a question mark symbol, as per SEC-161. See also SEC-321
int firstQuestionMarkIndex = url.indexOf("?");
if (firstQuestionMarkIndex != -1) {
url = url.substring(0, firstQuestionMarkIndex);
}
if (convertUrlToLowercaseBeforeComparison) {
if (isConvertUrlToLowercaseBeforeComparison()) {
url = url.toLowerCase();
if (logger.isDebugEnabled()) {
@@ -45,7 +45,7 @@ import java.util.Vector;
* <p>If no registered regular expressions match the HTTP URL, <code>null</code> is returned.</p>
*/
public class RegExpBasedFilterInvocationDefinitionMap extends AbstractFilterInvocationDefinitionSource
implements FilterInvocationDefinitionMap {
implements FilterInvocationDefinition {
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(RegExpBasedFilterInvocationDefinitionMap.class);
@@ -100,7 +100,7 @@ public class RegExpBasedFilterInvocationDefinitionMap extends AbstractFilterInvo
Iterator iter = requestMap.iterator();
if (convertUrlToLowercaseBeforeComparison) {
if (isConvertUrlToLowercaseBeforeComparison()) {
url = url.toLowerCase();
if (logger.isDebugEnabled()) {
@@ -34,6 +34,8 @@ import java.util.StringTokenizer;
import javax.naming.CommunicationException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.OperationNotSupportedException;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
@@ -104,13 +106,32 @@ public class DefaultInitialDirContextFactory implements InitialDirContextFactory
*/
private boolean useConnectionPool = true;
/** Set to true for ldap v3 compatible servers */
private boolean useLdapContext = false;
//~ Constructors ===================================================================================================
/**
* Create and initialize an instance to the LDAP url provided
*
* @param providerUrl a String of the form <code>ldap://localhost:389/base_dn<code>
*/
public DefaultInitialDirContextFactory(String providerUrl) {
this.providerUrl = providerUrl;
this.setProviderUrl(providerUrl);
}
//~ Methods ========================================================================================================
/**
* Set the LDAP url
*
* @param providerUrl a String of the form <code>ldap://localhost:389/base_dn<code>
*/
private void setProviderUrl(String providerUrl) {
Assert.hasLength(providerUrl, "An LDAP connection URL must be supplied.");
this.providerUrl = providerUrl;
StringTokenizer st = new StringTokenizer(providerUrl);
// Work out rootDn from the first URL and check that the other URLs (if any) match
@@ -131,7 +152,14 @@ public class DefaultInitialDirContextFactory implements InitialDirContextFactory
//Assert.isTrue(uri.getScheme().equals("ldap"), "Ldap URL must start with 'ldap://'");
}
//~ Methods ========================================================================================================
/**
* Get the LDAP url
*
* @return the url
*/
private String getProviderUrl() {
return providerUrl;
}
private InitialDirContext connect(Hashtable env) {
if (logger.isDebugEnabled()) {
@@ -145,17 +173,22 @@ public class DefaultInitialDirContextFactory implements InitialDirContextFactory
}
try {
return new InitialDirContext(env);
} catch (CommunicationException ce) {
throw new LdapDataAccessException(messages.getMessage(
"DefaultIntitalDirContextFactory.communicationFailure", "Unable to connect to LDAP server"), ce);
} catch (javax.naming.AuthenticationException ae) {
throw new BadCredentialsException(messages.getMessage("DefaultIntitalDirContextFactory.badCredentials",
"Bad credentials"), ae);
} catch (NamingException nx) {
return useLdapContext ? new InitialLdapContext(env, null) : new InitialDirContext(env);
} catch (NamingException ne) {
if ((ne instanceof javax.naming.AuthenticationException) ||
(ne instanceof OperationNotSupportedException)) {
throw new BadCredentialsException(messages.getMessage("DefaultIntitalDirContextFactory.badCredentials",
"Bad credentials"), ne);
}
if (ne instanceof CommunicationException) {
throw new LdapDataAccessException(messages.getMessage(
"DefaultIntitalDirContextFactory.communicationFailure", "Unable to connect to LDAP server"), ne);
}
throw new LdapDataAccessException(messages.getMessage(
"DefaultIntitalDirContextFactory.unexpectedException",
"Failed to obtain InitialDirContext due to unexpected exception"), nx);
"Failed to obtain InitialDirContext due to unexpected exception"), ne);
}
}
@@ -169,7 +202,7 @@ public class DefaultInitialDirContextFactory implements InitialDirContextFactory
env.put(Context.SECURITY_AUTHENTICATION, authenticationType);
env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
env.put(Context.PROVIDER_URL, providerUrl);
env.put(Context.PROVIDER_URL, getProviderUrl());
if (useConnectionPool) {
env.put(CONNECTION_POOL_KEY, "true");
@@ -280,4 +313,8 @@ public class DefaultInitialDirContextFactory implements InitialDirContextFactory
public void setUseConnectionPool(boolean useConnectionPool) {
this.useConnectionPool = useConnectionPool;
}
public void setUseLdapContext(boolean useLdapContext) {
this.useLdapContext = useLdapContext;
}
}
@@ -16,7 +16,6 @@
package org.acegisecurity.ldap;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.util.Assert;
@@ -28,6 +27,7 @@ import java.util.Set;
import javax.naming.NameNotFoundException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.Context;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
@@ -133,17 +133,21 @@ public class LdapTemplate {
public boolean nameExists(final String dn) {
Boolean exists = (Boolean) execute(new LdapCallback() {
public Object doInDirContext(DirContext ctx)
throws NamingException {
try {
ctx.lookup(LdapUtils.getRelativeName(dn, ctx));
} catch (NameNotFoundException nnfe) {
return Boolean.FALSE;
public Object doInDirContext(DirContext ctx)
throws NamingException {
try {
Object obj = ctx.lookup(LdapUtils.getRelativeName(dn, ctx));
if (obj instanceof Context) {
LdapUtils.closeContext((Context) obj);
}
return Boolean.TRUE;
} catch (NameNotFoundException nnfe) {
return Boolean.FALSE;
}
});
return Boolean.TRUE;
}
});
return exists.booleanValue();
}
@@ -234,8 +238,7 @@ public class LdapTemplate {
*
* @return the object created by the mapper from the matching entry
*
* @throws EmptyResultDataAccessException if no results are found.
* @throws IncorrectResultSizeDataAccessException if the search returns more than one result.
* @throws IncorrectResultSizeDataAccessException if no results are found or the search returns more than one result.
*/
public Object searchForSingleEntry(final String base, final String filter, final Object[] params,
final LdapEntryMapper mapper) {
@@ -245,13 +248,14 @@ public class LdapTemplate {
NamingEnumeration results = ctx.search(base, filter, params, searchControls);
if (!results.hasMore()) {
throw new EmptyResultDataAccessException(1);
throw new IncorrectResultSizeDataAccessException(1, 0);
}
SearchResult searchResult = (SearchResult) results.next();
if (results.hasMore()) {
throw new IncorrectResultSizeDataAccessException(1);
// We don't know how many results but set to 2 which is good enough
throw new IncorrectResultSizeDataAccessException(1, 2);
}
// Work out the DN of the matched entry
@@ -27,7 +27,7 @@ import org.acegisecurity.userdetails.ldap.LdapUserDetailsMapper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.util.Assert;
@@ -123,8 +123,12 @@ public class FilterBasedLdapUserSearch implements LdapUserSearch {
user.setUsername(username);
return user.createUserDetails();
} catch (EmptyResultDataAccessException notFound) {
throw new UsernameNotFoundException("User " + username + " not found in directory.");
} catch (IncorrectResultSizeDataAccessException notFound) {
if(notFound.getActualSize() == 0) {
throw new UsernameNotFoundException("User " + username + " not found in directory.");
}
// Search should never return multiple results if properly configured, so just rethrow
throw notFound;
}
}
@@ -51,6 +51,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.MessageSource;
@@ -95,6 +96,7 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(ProviderManager.class);
private static final Properties DEFAULT_EXCEPTION_MAPPINGS = new Properties();
//~ Instance fields ================================================================================================
@@ -102,36 +104,39 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
private ConcurrentSessionController sessionController = new NullConcurrentSessionController();
private List providers;
protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
private Properties exceptionMappings;
private Properties exceptionMappings = new Properties();
static {
DEFAULT_EXCEPTION_MAPPINGS.put(AccountExpiredException.class.getName(),
AuthenticationFailureExpiredEvent.class.getName());
DEFAULT_EXCEPTION_MAPPINGS.put(AuthenticationServiceException.class.getName(),
AuthenticationFailureServiceExceptionEvent.class.getName());
DEFAULT_EXCEPTION_MAPPINGS.put(LockedException.class.getName(), AuthenticationFailureLockedEvent.class.getName());
DEFAULT_EXCEPTION_MAPPINGS.put(CredentialsExpiredException.class.getName(),
AuthenticationFailureCredentialsExpiredEvent.class.getName());
DEFAULT_EXCEPTION_MAPPINGS.put(DisabledException.class.getName(), AuthenticationFailureDisabledEvent.class.getName());
DEFAULT_EXCEPTION_MAPPINGS.put(BadCredentialsException.class.getName(),
AuthenticationFailureBadCredentialsEvent.class.getName());
DEFAULT_EXCEPTION_MAPPINGS.put(UsernameNotFoundException.class.getName(),
AuthenticationFailureBadCredentialsEvent.class.getName());
DEFAULT_EXCEPTION_MAPPINGS.put(ConcurrentLoginException.class.getName(),
AuthenticationFailureConcurrentLoginEvent.class.getName());
DEFAULT_EXCEPTION_MAPPINGS.put(ProviderNotFoundException.class.getName(),
AuthenticationFailureProviderNotFoundEvent.class.getName());
DEFAULT_EXCEPTION_MAPPINGS.put(ProxyUntrustedException.class.getName(),
AuthenticationFailureProxyUntrustedEvent.class.getName());
}
public ProviderManager() {
exceptionMappings.putAll(DEFAULT_EXCEPTION_MAPPINGS);
}
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
checkIfValidList(this.providers);
Assert.notNull(this.messages, "A message source must be set");
if (exceptionMappings == null) {
exceptionMappings = new Properties();
exceptionMappings.put(AccountExpiredException.class.getName(),
AuthenticationFailureExpiredEvent.class.getName());
exceptionMappings.put(AuthenticationServiceException.class.getName(),
AuthenticationFailureServiceExceptionEvent.class.getName());
exceptionMappings.put(LockedException.class.getName(), AuthenticationFailureLockedEvent.class.getName());
exceptionMappings.put(CredentialsExpiredException.class.getName(),
AuthenticationFailureCredentialsExpiredEvent.class.getName());
exceptionMappings.put(DisabledException.class.getName(), AuthenticationFailureDisabledEvent.class.getName());
exceptionMappings.put(BadCredentialsException.class.getName(),
AuthenticationFailureBadCredentialsEvent.class.getName());
exceptionMappings.put(UsernameNotFoundException.class.getName(),
AuthenticationFailureBadCredentialsEvent.class.getName());
exceptionMappings.put(ConcurrentLoginException.class.getName(),
AuthenticationFailureConcurrentLoginEvent.class.getName());
exceptionMappings.put(ProviderNotFoundException.class.getName(),
AuthenticationFailureProviderNotFoundEvent.class.getName());
exceptionMappings.put(ProxyUntrustedException.class.getName(),
AuthenticationFailureProxyUntrustedEvent.class.getName());
doAddExtraDefaultExceptionMappings(exceptionMappings);
}
doAddExtraDefaultExceptionMappings(DEFAULT_EXCEPTION_MAPPINGS);
}
private void checkIfValidList(List listToCheck) {
@@ -189,7 +194,7 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
if (result != null) {
sessionController.registerSuccessfulAuthentication(result);
applicationEventPublisher.publishEvent(new AuthenticationSuccessEvent(result));
publishEvent(new AuthenticationSuccessEvent(result));
return result;
}
@@ -222,7 +227,7 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
}
if (event != null) {
applicationEventPublisher.publishEvent(event);
publishEvent(event);
} else {
if (logger.isDebugEnabled()) {
logger.debug("No event was found for the exception " + lastException.getClass().getName());
@@ -268,16 +273,8 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
Iterator iter = newList.iterator();
while (iter.hasNext()) {
Object currentObject = null;
try {
currentObject = iter.next();
AuthenticationProvider attemptToCast = (AuthenticationProvider) currentObject;
} catch (ClassCastException cce) {
throw new IllegalArgumentException("AuthenticationProvider " + currentObject.getClass().getName()
+ " must implement AuthenticationProvider");
}
Object currentObject = iter.next();
Assert.isInstanceOf(AuthenticationProvider.class, currentObject, "Can only provide AuthenticationProvider instances");
}
this.providers = newList;
@@ -292,4 +289,10 @@ public class ProviderManager extends AbstractAuthenticationManager implements In
public void setSessionController(ConcurrentSessionController sessionController) {
this.sessionController = sessionController;
}
private void publishEvent( ApplicationEvent event ) {
if ( applicationEventPublisher != null ) {
applicationEventPublisher.publishEvent( event );
}
}
}
@@ -28,6 +28,7 @@ import org.acegisecurity.GrantedAuthority;
public class TestingAuthenticationToken extends AbstractAuthenticationToken {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private Object credentials;
private Object principal;
@@ -30,6 +30,7 @@ import org.acegisecurity.GrantedAuthority;
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private Object credentials;
private Object principal;
@@ -31,6 +31,7 @@ import java.io.Serializable;
public class AnonymousAuthenticationToken extends AbstractAuthenticationToken implements Serializable {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private Object principal;
private int keyHash;
@@ -35,6 +35,7 @@ import java.util.List;
public class CasAuthenticationToken extends AbstractAuthenticationToken implements Serializable {
//~ Instance fields ================================================================================================
private static final long serialVersionUID = 1L;
private final List proxyList;
private final Object credentials;
private final Object principal;
@@ -55,7 +55,7 @@ public class DaoCasAuthoritiesPopulator implements CasAuthoritiesPopulator, Init
return userDetailsService;
}
public void setUserDetailsService(UserDetailsService authenticationDao) {
this.userDetailsService = authenticationDao;
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
}
@@ -36,7 +36,7 @@ import org.springframework.util.Assert;
public abstract class AbstractTicketValidator implements TicketValidator, InitializingBean {
//~ Static fields/initializers =====================================================================================
private static final Log logger = LogFactory.getLog(CasProxyTicketValidator.class);
private static final Log logger = LogFactory.getLog(AbstractTicketValidator.class);
//~ Instance fields ================================================================================================

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