1
0
mirror of synced 2026-07-13 14:45:10 +00:00

Compare commits

...

191 Commits

Author SHA1 Message Date
Spring Buildmaster 6a25b8bc83 Release version 4.0.0.RC1 2014-12-10 20:29:53 -08:00
Rob Winch a36c4bcb04 Consistent configureGlobal in samples 2014-12-10 21:10:27 -06:00
Rob Winch 8b1f5f7cd7 SEC-2789: Polish
Remove unnecessary "extends WebSecurityConfigurerAdapter"
2014-12-10 21:10:27 -06:00
Rob Winch 1677836d53 SEC-2790: Deprecate @EnableWebMvcConfig 2014-12-10 21:10:27 -06:00
Rob Winch 62e127e978 SEC-2789: Add Default WebSecurityConfigurerAdapter 2014-12-10 21:10:26 -06:00
Rob Winch 3171cc4364 SEC-2788: Add @Configuration as meta annotation to @Enable* annotations 2014-12-10 21:10:15 -06:00
Rob Winch 11116c2b80 SEC-2787: Update Versions 2014-12-10 16:37:19 -06:00
Rob Winch f5e8222115 SEC-2783: Add more PermGen to work around Tomcat Gradle Bug
https://github.com/bmuschko/gradle-tomcat-plugin/issues/113
2014-12-08 21:06:36 -06:00
Rob Winch c67ff42b8a SEC-2783: XML Configuration Defaults Should Match JavaConfig
* j_username -> username
* j_password -> password
* j_spring_security_check -> login
* j_spring_cas_security_check -> login/cas
* j_spring_cas_security_proxyreceptor -> login/cas/proxyreceptor
* j_spring_openid_security_login -> login/openid
* j_spring_security_switch_user -> login/impersonate
* j_spring_security_exit_user -> logout/impersonate
* login_error -> error
* use-expressions=true by default
2014-12-08 15:09:15 -06:00
Rob Winch b56e5edbbd SEC-2784: Fix build plugins 2014-12-08 14:24:34 -06:00
Rob Winch 5f5e7e7265 SEC-2785: Reference outputs PDF, Html Multi, & epub 2014-12-08 13:29:15 -06:00
Rob Winch 87a52ffbfd SEC-2784: Update to Gradle 2.2.1 2014-12-08 13:29:07 -06:00
Rob Winch 6e204fff72 SEC-2781: Remove deprecations 2014-12-04 15:28:40 -06:00
Rob Winch 5bb0ce9a8f SEC-2773: Add Test for static delegatingApplicationListener 2014-12-01 12:06:09 -06:00
Oliver Gierke 0f7c2e4128 SEC-2773: Prevent premature container initialization in WebSecurityConfiguration.
Changed the bean definition method for the DelegatingApplicationListener
to be static to avoid the need to instantiate the configuration class which
caused further premature initializations to satisfy the dependencies
expressed in setFilterChainProxySecurityConfigurer(…).
2014-12-01 11:38:19 -06:00
Rob Winch 2cb2657f5b SEC-2702: Clean WebSocket Namespace documentation 2014-11-25 12:27:29 -06:00
Rob Winch 8ad16b01f5 SEC-2702: Add WebSocket Security XML Namespace Support 2014-11-25 09:45:32 -06:00
Rob Winch 09f6210c73 SEC-2347: Polish 2014-11-21 22:31:03 -06:00
Rob Winch 3c487c0348 SEC-2348: Update doc headers enabled by default with XML 2014-11-21 21:55:03 -06:00
Rob Winch 4392205f63 SEC-2347: CSRF Enabled by default w/ XML Config 2014-11-21 21:32:56 -06:00
Rob Winch eedbf44235 SEC-2348: Security HTTP Response Headers enabled by default w/ XML 2014-11-21 16:06:29 -06:00
Rob Winch 2e1e9885ec SEC-2054: Polish
Fix the tests to use .getName() for assertions
2014-11-21 11:08:30 -06:00
Rob Winch e2f7b38b87 SEC-2054: BasicAuthenticationFilter not invoked on ERROR dispatch 2014-11-21 10:47:45 -06:00
Rob Winch dfa17bdb98 SEC-2747: Remove spring-core dependency from spring-security-crypto 2014-11-20 16:16:22 -06:00
Rob Winch 30c5788b8b SEC-1897: Remove raw types from AbstractAccessDecisionManager 2014-11-20 15:36:53 -06:00
Rob Winch 1cca72e6d8 SEC-2749: CsrfConfigurer.requireCsrfProtectionMatcher correct null check 2014-11-20 14:40:51 -06:00
Rob Winch 4d738d8576 SEC-2491: KeyBasedPersistenceTokenService defaults to 32 bytes 2014-11-20 14:40:07 -06:00
Rob Winch 0704f88e99 SEC-2344: Remove check for DefaultParamterNameDiscoverer
Spring Security not requires Spring 4, so there is no need to perform a
check if Spring 4 is present.
2014-11-20 12:09:38 -06:00
Rob Winch 3089f1603e SEC-2682: DelegatingSecurityContextRunnable/Callable delegate toString() 2014-11-20 11:51:05 -06:00
Rob Winch 05882b5f24 SEC-2574: Polish
Handle null DelegatingApplicationListener
2014-11-19 17:09:24 -06:00
Rob Winch 5810681b06 SEC-2574: JavaConfig default SessionRegistry processes SessionDestroyedEvents 2014-11-19 16:48:19 -06:00
Rob Winch 4dcc89fab0 SEC-2674: Documentation refers to httpStrictTransportSecurity() instead of hsts() 2014-11-19 13:31:09 -06:00
Rob Winch 002a78d87d SEC-2768: DefaultMessageSecurityExpressionHandler sets PermissionEvaluator 2014-11-19 11:58:58 -06:00
Rob Winch 95c70f29bd SEC-2769: DefaultMessageSecurityExpressionHandler sets RoleHierarchy 2014-11-19 11:58:54 -06:00
Rob Winch ff95a34b1f SEC-2705: DefaultMessageSecurityExpressionHandler populates AuthenticationTrustResolver 2014-11-19 11:25:07 -06:00
Rob Winch 3b8f7fdd67 SEC-2732: ehcache-core -> ehcache 2014-11-18 17:14:30 -06:00
Rob Winch 55d6d5a86a SEC-2615: accesscontrollist tag hasPermission performs OR not AND
In 3.1 the accesscontrollist tag began performing an and on the
permissions. This may have been accidental, but I think that it is more
intuitive & secure for it to behave this way. When compared to hasAnyRole
and hasRoles the hasPermission tag implies it is an and. If users end up
needing OR support, then the authorize tag can be used along with the
hasPermission expression. For example:

  <sec:authorize access="hasPermission(#domain, 'read') or hasPermission(#domain, 'write') ">

In general, the authorize tag should be preferred as it is the more
powerful way of performing authorization checks.
2014-11-18 16:59:46 -06:00
Mikhail Stryzhonok f20219d541 Added possibility create custom Sid 2014-11-18 13:27:36 -06:00
Rob Winch fa9e7999da SEC-2569: SavedRequestAwareWrapper no longer overrides getCookies()
Previously SavedRequestAwareWrapper overrode the getCookies() method. This
meant that the cookies from the original request were used instead of the
new request. In general, this does not make sense since cookies are
automatically submitted in every request by a client. Additionally, this
caused problems with using a locale cookie that was specified after the
secured page was requested.

Now SavedRequestAwareWrapper uses the new incoming request for determining
the cookies.
2014-11-18 13:17:27 -06:00
Rob Winch 97df23e3b5 Add IDE Setup to CONTRIBUTING 2014-10-28 22:09:53 -05:00
Rob Winch 24dec7ec3e SEC-2737: Remove WebSocket Outbound Authorization 2014-10-10 15:56:25 -05:00
Rob Winch 4e7398eec0 SEC-2150: Support class level annotations on Spring Data Repositories 2014-09-26 13:47:37 -05:00
Rob Winch d429c96253 SEC-2150: Add tests to verify JSR-250 Spec behavior 2014-09-26 13:46:10 -05:00
Andy Wilkinson a28650c715 Provide a ClassLoader to be used to load LDIF files
Prior to this change, ApacheDSContainer created a LdifFileLoader
without a ClassLoader. This limited its ability to load LDIF files
and causes a problem with an executable war in Spring Boot. See [1]
for details.

ApacheDSContainer now initialises LdifFileLoader with a ClassLoader.
This allows it to locate LDIF files packaged in WEB-INF/classes in
the case of an executable war file. The executable jar case was not
affected by this problem as, in that case, the LDIF file is pacakaged
in the root of the jar and is accessible via getSystemResourceAsStream

[1] https://github.com/spring-projects/spring-boot/issues/1550
2014-09-24 13:49:15 -05:00
Rob Winch 5ba8f000a7 SEC-2714: Add AuthenticationPrincipal resolver for messaging support 2014-09-23 16:28:48 -05:00
Rob Winch d2fa019fe5 SEC-2704: Separation of inbound and outbound security rules 2014-09-19 16:39:43 -05:00
Rob Winch 28446284a6 SEC-2713: Support authorization by SimpMessageType 2014-09-19 16:38:56 -05:00
Rob Winch b717333707 Polish messaging generics and imports 2014-09-16 14:31:06 -05:00
Rob Winch b6fcde880a SEC-2703: ChannelSecurityInterceptor use ThreadLocal for InterceptorStatusToken 2014-09-16 13:46:10 -05:00
Rob Winch e7edb77cae SEC-2716: Fix doc spelling of AbstractPreAuthenticatedProcessingFilter 2014-09-16 10:56:52 -05:00
Rob Winch d316f661e8 SEC-2719: Fix order sensitive authenticated().withRoles(..) 2014-09-16 10:54:50 -05:00
Rob Winch 02c3565e22 Fix compiling in Eclipse 2014-09-16 10:18:46 -05:00
Rob Winch 39d544b901 Merge pull request #121 from bonifaido/patch-1
Removed unnecessary params from anyRequest()'s javadoc
2014-09-01 22:30:25 -05:00
Rob Winch 96ea4ddc7b Merge pull request #120 from bura/fix-clickjacking-url
Fixed broken url to Clickjacking description.
2014-09-01 22:29:39 -05:00
Nándor István Krácser a932d6ecf3 Removed unnecessary params from anyRequest()'s javadoc 2014-08-20 11:24:15 +02:00
Bloshchetsov Andrey Evgenyevich bd322542ca Fixed broken url to Clickjacking description. 2014-08-20 10:11:21 +04:00
Rob Winch 57ea75a7ce Merge pull request #118 from benmccann/patch-1
Artifacts should be downloaded using https
2014-08-18 17:03:36 -05:00
Rob Winch b9df7ba01f SEC-2179: Allow customize PathMatcher for SimpDestinationMessageMatcher 2014-08-18 11:04:04 -05:00
Ben McCann 613820a218 Artifacts should be downloaded using https
See http://blog.ontoillogical.com/blog/2014/07/28/how-to-take-over-any-java-developer/
2014-08-16 14:52:34 -07:00
Rob Winch 533b71b9b8 SEC-2688: Remove ORDER constant 2014-08-15 21:14:12 -05:00
Rob Winch 6321665353 SEC-2676: Update to Spring Data Evans RC1 2014-08-15 20:46:59 -05:00
Rob Winch 3f30529039 SEC-2179: Add Spring Security Messaging Support 2014-08-15 20:46:58 -05:00
Rob Winch 934937d9c1 SEC-2688: CAS Proxy Ticket Authentication uses Service for host & port 2014-08-15 16:41:33 -05:00
Rob Winch f50e058d07 SEC-2697: Fix logging of Spring Version Check 2014-08-15 16:41:33 -05:00
Rob Winch 939df5f0f9 SEC-2547: Update to cas-client-core-3.3.3 2014-08-15 16:41:33 -05:00
Rob Winch 3187ee8bf3 SEC-2700: Register WithSecurityContextTestExecutionListener by default 2014-08-15 16:41:33 -05:00
Rob Winch 1eaa621619 SEC-2676: Fix data and sample data poms 2014-08-15 16:40:51 -05:00
Rob Winch 94a0816153 Exclude spring-data-commons from spring-ldap-core 2014-08-01 14:04:47 -05:00
Rob Winch 4f936c4c51 Remove @Version from created since it should not be updated
This also works around DATAJPA-582
2014-08-01 14:03:27 -05:00
Rob Winch 3e8c879cea SEC-2676: Fix data-jc sample's classpath 2014-08-01 10:33:33 -05:00
Rob Winch 1f861f512a SEC-2676: Add SpEL Spring Security Integration 2014-07-29 20:04:37 -05:00
Rob Winch 4a633a938a SEC-2690: Add guard around debug statement 2014-07-28 16:25:27 -05:00
Rob Winch 0f6235bbe0 SEC-2690: Polish LdapAuthority
- Make dn required (as javadoc inidicates)
- Simplify .equals since role cannot be null
- Formatting polish
2014-07-28 16:25:27 -05:00
Rob Winch aac4ede3a4 SEC-2690: Polish method modifiers
- Make methods final where possible
- Make methods private where possible
2014-07-28 16:25:27 -05:00
Rob Winch 1761b29e58 SEC-2690: String[]->List<String>
Use Collections rather than Arrays since Collections can be immutable.
2014-07-28 16:25:27 -05:00
Rob Winch 15c837d5de SEC-2690: Revert explicit TcpTransport since causes tests to fail 2014-07-28 16:25:26 -05:00
Rob Winch 6b43b261bc SEC-2690: Formatting cleanup 2014-07-28 12:41:56 -05:00
Filip Hanik 93b863d2e5 SEC-2690: Support static nested groups in LDAP
This refers to groups that have member: <another group DN> as an attribute
- Add in a utility method in the SpringSecurityLdapTemplate to retrieve multiple attributes and their values from an LDAP record
- Make the DefaultLdapAuthoritiesPopulator more extensible
- Add an LdapAuthority object that holds the DN in addition to other group attributes
- Add a NestedLdapAuthoritiesPopulator to search statically nested groups
2014-07-28 12:40:19 -05:00
Rob Winch 8a2a1b7a5b SEC-2595: Polish 2014-07-25 16:27:19 -05:00
Rob Winch b2d66e2a78 SEC-2595: @EnableGlobalMethodSecurity AspectJ fixes 2014-07-25 16:03:18 -05:00
Rob Winch 44f688c9d2 Update to Spring IO 1.1.0.BUILD-SNAPSHOT 2014-07-22 22:32:42 -05:00
Rob Winch 08d703545c SEC-2686: Fix SpringSecurityCoreVersion 2014-07-22 22:06:45 -05:00
Rob Winch b72c1ad314 SEC-2686: Create SecurityMockMvcConfigurer 2014-07-22 15:11:37 -05:00
Rob Winch e14e5b42fc SEC-2599: HttpSessionEventPublisher get required ApplicationContext
In order to get better error messages (avoid NullPointerException) the
HttpSessionEventPublisher now gets the required ApplicationContext which
throws an IllegalStateException with a good error message.
2014-07-22 09:19:50 -05:00
Rob Winch 9654817fd8 SEC-2601: Add DigestRequestPostProcessor 2014-07-21 22:46:18 -05:00
Rob Winch c8348d60e1 SEC-2602: Add test support for x509 certificate 2014-07-21 15:09:30 -05:00
Rob Winch ecb4296540 SEC-2588: Javadoc fix channelSecurity->requiresChannel 2014-07-21 14:23:40 -05:00
Rob Winch b97b84063a SEC-2665: Fix samples/ldap-jc link in reference 2014-07-21 14:20:14 -05:00
Rob Winch 3289c1c92a SEC-2683: Correct spelling of assignamble in AuthenticationPrincipalResolver Exception 2014-07-18 13:57:13 -05:00
Rob Winch 906a0cb0e2 SEC-2684: Correct spelling of WithSecurityContextTestExecutionListener 2014-07-18 13:53:41 -05:00
Mirko Zeibig 75df42cb7c SEC-2656: Fix <frame-options> with whitelist strategy 2014-06-18 09:10:28 -05:00
Rob Winch 66c926f2c7 SEC-2653: Remove explicit port for ldap-xml so can be dynamic for ci 2014-06-18 08:27:39 -05:00
Rob Winch c3d05bea62 SEC-2657: Test for multi dynamic ports for LDAP Java Config 2014-06-17 17:25:08 -05:00
Rob Winch a3fd706335 SEC-2660: Move config integration-test *.groovy to groovy source folder 2014-06-17 17:22:42 -05:00
Rob Winch 6dc0733d9e SEC-2659: ApacheDSContainer fails on import multiple ldif 2014-06-17 17:19:51 -05:00
Rob Winch b255478b14 SEC-2658: Java Config triggers usePasswordAttrCompare to be set 2014-06-17 17:10:16 -05:00
Rob Winch a2b53fabce SEC-2657: LdapAuthenticationProviderConfigurer find available port 2014-06-17 16:54:42 -05:00
Rob Winch 63d1b531a1 SEC-2618: LdapAuthenticationProviderConfigurer passwordAttribute null check
If LdapAuthenticationProviderConfigurer passwordAttribute is null, do not
set on the PasswordComparisonAuthenticator
2014-06-17 16:51:01 -05:00
Rob Winch 47e02c41b6 SEC-2647: IntelliJ testSourceDirs 2014-06-17 16:38:43 -05:00
Rob Winch e4fa42c399 SEC-2593: Add test for TestSecurityContext RPP in stateless mode 2014-06-13 15:28:06 -05:00
Rob Winch 7e3e821db1 SEC-2593: Support stateless mode in Spring Security Test 2014-06-13 15:22:06 -05:00
Rob Winch 626b521c0e SEC-2591: Added more user friendly Korean messages_ko_KR.properties 2014-06-13 13:56:40 -05:00
Rob Winch 6b121c7543 SEC-2637: Add Geb integration tests for ldap-xml 2014-06-13 13:53:33 -05:00
Rob Winch 19ce54e4ff SEC-2653: ldap-xml logout is post with CSRF token 2014-06-13 13:53:19 -05:00
Rob Winch f7d09c6b62 SEC-2633: Remove springSecurityFilterChain from insecuremvc tests 2014-06-13 13:09:59 -05:00
Rob Winch 025c0857f4 SEC-2635: Add Geb integration tests for jdbc-jc 2014-06-13 12:24:03 -05:00
Rob Winch 0e9999e429 Fix jdbc-jc to work with tomcat gradle plugin
It is necessary to ensure that src/main/webapp exists to ensure the
application starts with the Tomcat Gradle Plugin.

This commit adds a Manifest file to src/main/webapp/META-INF to ensure
that git contains the otherwise empty directory.
2014-06-13 12:23:26 -05:00
Rob Winch ec1c5b0e78 SEC-2622: Set classesDirectory if exists for integrationTomcatRun 2014-06-13 12:22:01 -05:00
Rob Winch 6964c2e3de SEC-2633: Add MockMvc tests for insecuremvc 2014-06-13 11:26:28 -05:00
Rob Winch 8f84921713 SEC-2632: Add Geb Integration Tests for insecure sample 2014-06-13 11:20:57 -05:00
Rob Winch 41c19e88b2 SEC-2646: Use Gradle Wrapper with source code 2014-06-13 11:20:22 -05:00
Rob Winch 11d83cdce1 SEC-2651: Fix hellojs-jc after Thymeleaf Spring 4 changes 2014-06-13 09:43:32 -05:00
Rob Winch 80c0f5fa17 SEC-2626: Add Geb integration tests for form-jc 2014-06-12 17:06:05 -05:00
Rob Winch 2aea199001 SEC-2636: Added Geb integration tests for ldap-jc 2014-06-12 16:49:12 -05:00
Rob Winch 10c4d8f1af SEC-2651: Update Thymeleaf to Spring 4 variants in samples 2014-06-12 16:48:04 -05:00
Rob Winch cb94fb2c99 SEC-2631: Add spring-security-test to inmemory-jc pom 2014-06-12 15:08:53 -05:00
Rob Winch ac712f9f17 SEC-2617: Add JSTL to sample poms 2014-06-12 15:07:25 -05:00
Rob Winch 5953a35c95 SEC-2624: Add Geb integration tests to contacts-xml 2014-06-12 15:05:54 -05:00
Rob Winch 91b2b7f875 SEC-2634: Add Geb integration tests for jaas-xml 2014-06-12 12:18:56 -05:00
Rob Winch 1bff58577c SEC-2631: Add inmemory-jc MockMvc integration tests 2014-06-12 12:18:04 -05:00
Rob Winch 15ab3316b3 SEC-2630: Add helloworld-jc Gebintegration tests 2014-06-12 12:18:04 -05:00
Rob Winch 82e89db1c8 SEC-2622: Add integration test support to samples 2014-06-12 12:14:37 -05:00
Rob Winch fb25273672 SEC-2617: Fix JSTL Samples 2014-06-12 12:01:04 -05:00
Rob Winch dd0253048e SEC-2650: Fix Jetty Warn NoInitialContextException on shutdown 2014-06-12 11:53:22 -05:00
Rob Winch b13603f480 SEC-2649: Update to Tomcat 7.0.54 2014-06-12 11:48:05 -05:00
Rob Winch 2e88c1dfc7 SEC-2648: Update to gradle-tomcat-plugin:1.2.3 for samples 2014-06-12 11:41:52 -05:00
Rob Winch 26ffbeadf0 SEC-2647: Add integration test classpath in IntelliJ 2014-06-12 11:37:42 -05:00
Rob Winch e86cbc8731 SEC-2646: Update to Gradle 1.12 2014-06-12 11:33:58 -05:00
Rob Winch e9d9a83df4 SEC-2607: CAS Server logouts out synchronously 2014-05-21 15:43:56 -05:00
Rob Winch 26db320d3c SEC-2579: Ignore springio props in release checks 2014-05-21 14:04:41 -05:00
Rob Winch 3ba1f66f9d SEC-2606: ApacheDSServerIntegrationTests scan for available port 2014-05-21 06:51:11 -05:00
Rob Winch e6e35932ed SEC-2603: Fix config groovy integration tests 2014-05-20 23:15:39 -05:00
Rob Winch cbd06a4994 SEC-2472: Support LDAP crypto PasswordEncoder 2014-05-20 23:15:36 -05:00
Rob Winch b8f0db41f4 SEC-2579: Update to spring-io-plugin-0.0.3.RELEASE 2014-05-19 15:59:51 -05:00
Andy Wilkinson d95640d3e5 SEC-2600: Remove unused import 2014-05-19 12:29:04 -05:00
Rob Winch 6d45957eec SEC-2572: Add spring-security-test method showcase
This will allow for using the showcase in the documentation.
2014-05-07 10:45:52 -05:00
Rob Winch dabe3a03e7 SEC-2586: Create DefaultSecurityTestExecutionListeners 2014-05-07 10:44:05 -05:00
Rob Winch 2082d3747a SEC-2578: HttpSessionSecurityContextRepository traverses HttpServletResponseWrapper 2014-05-02 15:06:50 -05:00
Rob Winch f73b579ad9 SEC-2543: Logout with CSRF enabled requires POST by default 2014-05-02 11:24:02 -05:00
Rob Winch 809f98843b SEC-2581: Update to propdeps-plugin:0.0.6 2014-05-01 11:29:20 -05:00
Rob Winch 76bf378077 SEC-2580: Include ApacheDS in samples/ldap-xml 2014-05-01 11:28:27 -05:00
Rob Winch 04226caf63 SEC-2579: Update to springio-platform-plugin 0.0.2.RELEASE 2014-04-30 08:53:44 -05:00
Alexander Grüneberg d9efd08bfd SEC-2577: Add missing whitespace in reference 2014-04-28 16:24:48 -05:00
Rob Winch 1d7402e0cd SEC-2532: Add disclaimer about jdbcAuthentication() with persistent data stores 2014-04-28 15:06:52 -05:00
Rob Winch 9a4c50035c SEC-2537: Add nekohtml to openid module 2014-04-25 13:51:38 -05:00
Rob Winch 475f25c787 SEC-2571: Failure in UserDetailsService->InternalAuthenticationServiceException 2014-04-24 16:36:36 -05:00
Rob Winch 37bb350883 SEC-2549: Remove LazyBean marker interface 2014-04-24 14:34:35 -05:00
Rob Winch 00e1094178 Add springio-platform plugin 2014-04-23 14:35:22 -05:00
Mattias Severson 2b3becf666 SEC-2573: RequestHeaderRequestMatcher constructor argument name has typo 2014-04-23 09:28:00 -05:00
Rob Winch 8baf82532c SEC-2015: Add spring-security-test 2014-04-22 16:47:48 -05:00
Rob Winch 1c75d33adb SEC-2560: Remove samples from .gitignore and add missing sample files 2014-04-16 21:17:02 -05:00
Rob Winch fa6218cf73 SEC-2558: Fix failing ApacheDSContainerTests when port is taken 2014-04-15 11:52:09 -05:00
Rob Winch 5b216bd0b2 Revert "SEC-2547: Consistent CAS client version"
This reverts commit f6cc9d87d5.
2014-04-15 10:36:37 -05:00
Hans-Joachim Kliemeck f6cc9d87d5 SEC-2547: Consistent CAS client version 2014-04-14 22:48:55 -05:00
Grzegorz Rożniecki 8e31b66f06 SEC-2556: Fix @Import example in manual 2014-04-14 22:39:37 -05:00
Rob Winch ccf96a4d69 SEC-2542: Polish dependency exclusions
This cleans up exclusions so the pom.xml are not as cluttered.
2014-04-02 09:47:29 -05:00
Rob Winch 3118e39de8 SEC-2542: Use exclusions to remove duplicate dependencies
A number of projects had duplicate dependencies on their classpaths
as a result of the same classes being available in more than one
artifact, each with different Maven coordinates. Typically this only
affected the tests, but meant that the actual classes that were
loaded was somewhat unpredictable and had the potential to vary
between an IDE and the command line depending on the order in which
the aritfacts appeared on the classpath. This commit adds a number of
exclusions to remove such duplicates.

In addition to the new exclusions, notable other changes are:

 - Spring Data JPA has been updated to 1.4.1. This brings its
   transitive dependency upon spring-data-commons into line with
   Spring LDAP's and prevents both spring-data-commons-core and
   spring-data-commons from being on the classpath
 - All Servlet API dependencies have been updated to use the official
   artifact with all transitive dependencies on unofficial servlet API
   artifacts being excluded.
 - In places, groovy has been replaced with groovy-all. This removes
   some duplicates caused by groovy's transitive dependencies.
 - JUnit has been updated to 4.11 which brings its transitive Hamcrest
   dependency into line with other components.

There appears to be a bug in Gradle which means that some exclusions
applied to an artifact do not work reliably. To work around this
problem it has been necessary to apply some exclusions at the
configuration level

Conflicts:
	samples/messages-jc/pom.xml
2014-04-02 09:47:26 -05:00
Luke Taylor 71ba977dad Fix package name in manual code 2014-03-27 13:08:23 +00:00
Rob Winch c411014c24 SEC-2533: Global AuthenticationManagerBuilder disables clearing child credentials 2014-03-25 13:05:44 -05:00
Rob Winch cb0549a609 SEC-2498: RequestCache allows POST when CSRF is disabled 2014-03-25 10:50:59 -05:00
Rob Winch d079044592 SEC-2531: AuthenticationConfiguration#lazyBean should use BeanClassLoader 2014-03-24 14:58:19 -05:00
Rob Winch c0590e614a SEC-2177: Polish 2014-03-18 15:48:54 -05:00
Maciej Zasada 7cf37856c0 SEC-2177: Striping off all leading schemes
Striping off all leading schemes in the DefaultRedirectStrategy, so it
will be less vulnerable to open redirect phishing attacks. More info can
be found at SEC-2177 JIRA issue.
2014-03-18 15:45:41 -05:00
Rob Winch 5be4bfd55e SEC-2173: Polish javadoc 2014-03-14 08:59:24 -05:00
Rob Winch 2628be60d1 SEC-2173: Added SystemWideSaltSource.toString() test 2014-03-14 08:59:24 -05:00
Gamal Shaban 1c50a86661 SEC-2173: Override toString method in SystemWideSaltSource
Now prints the saltSource string instead of the object memory signature.
2014-03-14 08:59:24 -05:00
Julien Dubois 7325b97c76 SEC-2519: RememberMeAuthenticationException supports root cause
Added a constructor which keeps the root cause of the exception, and
added some documentation
2014-03-11 16:11:52 -05:00
Rob Winch 91a074c744 Merge pull request #62 from dalbertom/typo
Correct typo in AbstractRememberMeServices assertion
2014-03-11 15:40:23 -05:00
Alexander Kjäll 50637d4451 SEC-2518: UserDetailsService javadoc repeats "insensitive"
Typo in javadoc, "case insensitive" was repeated twice.
2014-03-11 15:36:47 -05:00
Rob Winch a7005bd742 SEC-2500: Prevent anonymous bind for ActiveDirectoryLdapAuthenticator 2014-03-10 14:33:39 -05:00
Rob Winch ea902e5829 SEC-2507: WebExpressionVoter.supports support subclasses of FilterInvocation 2014-03-10 14:33:37 -05:00
Rob Winch e4a58375cc SEC-2515: Detect object cycle for AuthenticationManager configuration 2014-03-10 14:33:35 -05:00
Rob Winch 32d3e29c65 SEC-2325: Polish CSRF Tag support
- Rename csrfField to csrfInput
- Make AbstractCsrfTag package scope
- rename FormFieldTag to CsrfInputTag
- rename MetaTagsTag to CsrfMetaTagsTag
- removed whitespace from tag output so output is
  minimized & improving browser performance
- Update @since
- changed test names to be more meaningful
2014-03-07 15:28:52 -06:00
beamerblvd a3e0475998 SEC-2325 Added JSP tags for CSRF meta tags and form fields 2014-03-07 15:28:48 -06:00
beamerblvd 26cee61b98 SEC-2335 Added ACL schema files for MySQL, SQL Server, Oracle 2014-03-07 15:28:45 -06:00
John Tims 56bb331760 SEC-2514: Fix typo in hellomvc.asc
packags -> packages
2014-03-07 10:27:23 -06:00
John Tims 1e3cdaf8a9 SEC-2513: Add link to SpringSource CLA form 2014-03-07 10:27:18 -06:00
Manimaran Selvan 1d6536fa71 SEC-2512: Fix typo in reference`
udates -> updates
2014-03-06 22:22:34 -06:00
Rob Winch e15cee62f4 SEC-2511: Remove double ALLOW-FROM in X-Frame-Options header 2014-03-06 22:01:25 -06:00
getvictor 6de138c2f2 SEC-2511: Remove double ALLOW-FROM from X-Frame-Options header.
The interface documentation for getAllowFromValue states: Gets the value for ALLOW-FROM excluding the ALLOW-FROM.
2014-03-06 22:01:23 -06:00
Rob Winch 4cdeacc277 SEC-2499: Allow MethodSecurityExpressionHandler in parent context
Previously a NoSuchBeanDefintionException was thrown when the
MethodSecurityExpressionHandler was defined in the parent context. This
happened due to trying to work around ordering issues related to SEC-2136

This commit resolves this by not marking the
MethodSecurityExpressionHandler bean as lazy unless it exists.
2014-03-06 21:14:35 -06:00
Rob Winch 9988fa141c Update Spring Security version in pom.xml 2014-03-06 08:13:52 -06:00
Rob Winch 8afa8d8588 Fix integration tests 2014-03-06 07:56:40 -06:00
Rob Winch 6dfdb10e31 Fix move to 4.0 2014-03-05 16:52:19 -06:00
Rob Winch 6be4e3a9fc SEC-2506: Remove Bundlor Support 2014-03-05 13:32:16 -06:00
Rob Winch 04a527d4ec SEC-2495: CSRF disables logout on GET 2014-02-20 09:40:00 -06:00
Rob Winch de4ed136ea Fix spring4 test 2014-02-19 16:13:30 -06:00
Rob Winch 4a1a2dfed4 Update min Spring version of 4.0.2.REELASE 2014-02-19 11:16:57 -06:00
Rob Winch 3fc9dd82f3 Start Spring Security 4.0.x 2014-02-19 11:05:27 -06:00
Spring Buildmaster 551f600073 Next development version 2014-02-19 08:10:01 -08:00
David Alberto f9998d582a Correct typo in AbstractRememberMeServices assertion 2013-11-26 18:06:55 -05:00
767 changed files with 32949 additions and 9778 deletions
+1 -2
View File
@@ -18,5 +18,4 @@ build/
*.ipr
*.iws
.gradle/
atlassian-ide-plugin.xml
/samples
atlassian-ide-plugin.xml
+13 -1
View File
@@ -6,6 +6,18 @@ _Please refer back to this document as a checklist before issuing any pull reque
Each Spring module is slightly different than another in terms of team size, number of issues, etc. Therefore each project is managed slightly different. You will notice that this document is very similar to the [Spring Framework Contributor guidelines](https://github.com/SpringSource/spring-framework/wiki/Contributor-guidelines). However, there are some subtle differences between the two documents, so please be sure to read this document thoroughly.
# Importing into IDE
The following provides information on setting up a development environment that can run the sample in [Spring Tool Suite 3.6.0+](http://www.springsource.org/sts). Other IDE's should work using Gradle's IDE support, but have not been tested.
* IDE Setup
* Install Spring Tool Suite 3.6.0+
* You will need the following plugins installed (can be found on the Extensions Page)
* Gradle Eclipse
* Groovy Eclipse
* Importing the project into Spring Tool Suite
* File->Import...->Gradle Project
# Understand the basics
Not sure what a pull request is, or how to submit one? Take a look at GitHub's excellent [help documentation first](https://help.github.com/articles/using-pull-requests).
@@ -16,7 +28,7 @@ Is there already an issue that addresses your concern? Do a bit of searching in
If you're considering anything more than correcting a typo or fixing a minor bug , please discuss it on the [Spring Security forums](http://forum.springsource.org/forumdisplay.php?33-Security) before submitting a pull request. We're happy to provide guidance but please spend an hour or two researching the subject on your own including searching the forums for prior discussions.
# Sign the Contributor License Agreement
If you have not previously done so, please fill out and submit the SpringSource CLA form. You'll receive a token when this process is complete. Keep track of this, you may be asked for it later!
If you have not previously done so, please fill out and submit the [SpringSource CLA form](https://support.springsource.com/spring_committer_signup). You'll receive a token when this process is complete. Keep track of this, you may be asked for it later!
* For **Project** select _Spring Security_
* For **Project Lead** enter _Rob Winch_
+1
View File
@@ -2,6 +2,7 @@
dependencies {
compile project(':spring-security-core'),
springCoreDependency,
'aopalliance:aopalliance:1.0',
"org.springframework:spring-aop:$springVersion",
"org.springframework:spring-context:$springVersion",
+30 -31
View File
@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-acl</artifactId>
<version>3.2.1.CI-SNAPSHOT</version>
<version>4.0.0.RC1</version>
<name>spring-security-acl</name>
<description>spring-security-acl</description>
<url>http://spring.io/spring-security</url>
@@ -31,21 +30,10 @@
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>https://repo.spring.io/snapshot</url>
<id>spring-milestone</id>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
<dependencies>
@@ -58,25 +46,25 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.2.1.CI-SNAPSHOT</version>
<version>4.0.0.RC1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -88,39 +76,39 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
<version>1.2</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>1.6.2</version>
<version>2.9.0</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.29</version>
<version>1.1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -132,7 +120,7 @@
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.3.1</version>
<version>2.3.2</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -144,26 +132,37 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.5</version>
<version>1.7.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -87,7 +87,7 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// Check if authorized by virtue of ACL ownership
Sid currentUser = new PrincipalSid(authentication);
Sid currentUser = createCurrentUser(authentication);
if (currentUser.equals(acl.getOwner())
&& ((changeType == CHANGE_GENERAL) || (changeType == CHANGE_OWNERSHIP))) {
@@ -123,6 +123,17 @@ public class AclAuthorizationStrategyImpl implements AclAuthorizationStrategy {
"Principal does not have required ACL permissions to perform requested operation");
}
/**
* Creates a principal-like sid from the authentication information.
*
* @param authentication the authentication information that can provide principal and thus the sid's id will be
* dependant on the value inside
* @return a sid with the ID taken from the authentication information
*/
protected Sid createCurrentUser(Authentication authentication) {
return new PrincipalSid(authentication);
}
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
this.sidRetrievalStrategy = sidRetrievalStrategy;
@@ -73,16 +73,6 @@ public class AclImpl implements Acl, MutableAcl, AuditableAcl, OwnershipAcl {
this.permissionGrantingStrategy = new DefaultPermissionGrantingStrategy(auditLogger);
}
/**
* @deprecated Use the version which takes a {@code PermissionGrantingStrategy} argument instead.
*/
@Deprecated
public AclImpl(ObjectIdentity objectIdentity, Serializable id, AclAuthorizationStrategy aclAuthorizationStrategy,
AuditLogger auditLogger, Acl parentAcl, List<Sid> loadedSids, boolean entriesInheriting, Sid owner) {
this(objectIdentity, id, aclAuthorizationStrategy, new DefaultPermissionGrantingStrategy(auditLogger),
parentAcl, loadedSids, entriesInheriting, owner);
}
/**
* Full constructor, which should be used by persistence tools that do not
* provide field-level access features.
@@ -46,15 +46,6 @@ public class EhCacheBasedAclCache implements AclCache {
//~ Constructors ===================================================================================================
/**
* @deprecated use the second constructor which injects the strategy objects. See SEC-1498.
*/
@Deprecated
public EhCacheBasedAclCache(Ehcache cache) {
Assert.notNull(cache, "Cache required");
this.cache = cache;
}
public EhCacheBasedAclCache(Ehcache cache, PermissionGrantingStrategy permissionGrantingStrategy,
AclAuthorizationStrategy aclAuthorizationStrategy) {
Assert.notNull(cache, "Cache required");
@@ -74,7 +74,7 @@ import org.springframework.util.Assert;
*
* @author Ben Alex
*/
public final class BasicLookupStrategy implements LookupStrategy {
public class BasicLookupStrategy implements LookupStrategy {
public final static String DEFAULT_SELECT_CLAUSE = "select acl_object_identity.object_id_identity, "
+ "acl_entry.ace_order, "
@@ -131,15 +131,20 @@ public final class BasicLookupStrategy implements LookupStrategy {
* @param dataSource to access the database
* @param aclCache the cache where fully-loaded elements can be stored
* @param aclAuthorizationStrategy authorization strategy (required)
*
* @deprecated Use the version which takes a {@code PermissionGrantingStrategy} argument instead.
*/
@Deprecated
public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
AclAuthorizationStrategy aclAuthorizationStrategy, AuditLogger auditLogger) {
this(dataSource, aclCache, aclAuthorizationStrategy, new DefaultPermissionGrantingStrategy(auditLogger));
}
/**
* Creates a new instance
*
* @param dataSource to access the database
* @param aclCache the cache where fully-loaded elements can be stored
* @param aclAuthorizationStrategy authorization strategy (required)
* @param grantingStrategy the PermissionGrantingStrategy
*/
public BasicLookupStrategy(DataSource dataSource, AclCache aclCache,
AclAuthorizationStrategy aclAuthorizationStrategy, PermissionGrantingStrategy grantingStrategy) {
Assert.notNull(dataSource, "DataSource required");
@@ -256,7 +261,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
* should not throw {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used
* to automatically create entries if required)
*/
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) {
public final Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) {
Assert.isTrue(batchSize >= 1, "BatchSize must be >= 1");
Assert.notEmpty(objects, "Objects to lookup required");
@@ -428,17 +433,33 @@ public final class BasicLookupStrategy implements LookupStrategy {
return result;
}
/**
* Creates a particular implementation of {@link Sid} depending on the arguments.
*
* @param sid the name of the sid representing its unique identifier. In typical ACL database schema it's
* located in table {@code acl_sid} table, {@code sid} column.
* @param isPrincipal whether it's a user or granted authority like role
* @return the instance of Sid with the {@code sidName} as an identifier
*/
protected Sid createSid(boolean isPrincipal, String sid) {
if (isPrincipal) {
return new PrincipalSid(sid);
} else {
return new GrantedAuthoritySid(sid);
}
}
/**
* Sets the {@code PermissionFactory} instance which will be used to convert loaded permission
* data values to {@code Permission}s. A {@code DefaultPermissionFactory} will be used by default.
*
* @param permissionFactory
*/
public void setPermissionFactory(PermissionFactory permissionFactory) {
public final void setPermissionFactory(PermissionFactory permissionFactory) {
this.permissionFactory = permissionFactory;
}
public void setBatchSize(int batchSize) {
public final void setBatchSize(int batchSize) {
this.batchSize = batchSize;
}
@@ -448,28 +469,28 @@ public final class BasicLookupStrategy implements LookupStrategy {
*
* @param selectClause the select clause, which defaults to {@link #DEFAULT_SELECT_CLAUSE}.
*/
public void setSelectClause(String selectClause) {
public final void setSelectClause(String selectClause) {
this.selectClause = selectClause;
}
/**
* The SQL for the where clause used in the <tt>lookupPrimaryKey</tt> method.
*/
public void setLookupPrimaryKeysWhereClause(String lookupPrimaryKeysWhereClause) {
public final void setLookupPrimaryKeysWhereClause(String lookupPrimaryKeysWhereClause) {
this.lookupPrimaryKeysWhereClause = lookupPrimaryKeysWhereClause;
}
/**
* The SQL for the where clause used in the <tt>lookupObjectIdentities</tt> method.
*/
public void setLookupObjectIdentitiesWhereClause(String lookupObjectIdentitiesWhereClause) {
public final void setLookupObjectIdentitiesWhereClause(String lookupObjectIdentitiesWhereClause) {
this.lookupObjectIdentitiesWhereClause = lookupObjectIdentitiesWhereClause;
}
/**
* The SQL for the "order by" clause used in both queries.
*/
public void setOrderByClause(String orderByClause) {
public final void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
@@ -556,13 +577,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
}
boolean entriesInheriting = rs.getBoolean("entries_inheriting");
Sid owner;
if (rs.getBoolean("acl_principal")) {
owner = new PrincipalSid(rs.getString("acl_sid"));
} else {
owner = new GrantedAuthoritySid(rs.getString("acl_sid"));
}
Sid owner = createSid(rs.getBoolean("acl_principal"), rs.getString("acl_sid"));
acl = new AclImpl(objectIdentity, id, aclAuthorizationStrategy, grantingStrategy, parentAcl, null,
entriesInheriting, owner);
@@ -574,13 +589,7 @@ public final class BasicLookupStrategy implements LookupStrategy {
// It is permissible to have no ACEs in an ACL (which is detected by a null ACE_SID)
if (rs.getString("ace_sid") != null) {
Long aceId = new Long(rs.getLong("ace_id"));
Sid recipient;
if (rs.getBoolean("ace_principal")) {
recipient = new PrincipalSid(rs.getString("ace_sid"));
} else {
recipient = new GrantedAuthoritySid(rs.getString("ace_sid"));
}
Sid recipient = createSid(rs.getBoolean("ace_principal"), rs.getString("ace_sid"));
int mask = rs.getInt("mask");
Permission permission = permissionFactory.buildFromMask(mask);
@@ -209,6 +209,19 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
throw new IllegalArgumentException("Unsupported implementation of Sid");
}
return createOrRetrieveSidPrimaryKey(sidName, sidIsPrincipal, allowCreate);
}
/**
* Retrieves the primary key from acl_sid, creating a new row if needed and the allowCreate property is
* true.
* @param sidName name of Sid to find or to create
* @param sidIsPrincipal whether it's a user or granted authority like role
* @param allowCreate true if creation is permitted if not found
* @return the primary key or null if not found
*/
protected Long createOrRetrieveSidPrimaryKey(String sidName, boolean sidIsPrincipal, boolean allowCreate) {
List<Long> sidIds = jdbcTemplate.queryForList(selectSidPrimaryKey,
new Object[] {Boolean.valueOf(sidIsPrincipal), sidName}, Long.class);
+2 -2
View File
@@ -5,12 +5,12 @@
-- drop table acl_class;
-- drop table acl_sid;
create table acl_sid(
id bigint generated by default as identity(start with 100) not null primary key,
principal boolean not null,
sid varchar_ignorecase(100) not null,
constraint unique_uk_1 unique(sid,principal));
constraint unique_uk_1 unique(sid,principal)
);
create table acl_class(
id bigint generated by default as identity(start with 100) not null primary key,
@@ -0,0 +1,46 @@
-- ACL Schema SQL for MySQL 5.5+ / MariaDB equivalent
-- drop table acl_entry;
-- drop table acl_object_identity;
-- drop table acl_class;
-- drop table acl_sid;
CREATE TABLE acl_sid (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
principal BOOLEAN NOT NULL,
sid VARCHAR(100) NOT NULL,
UNIQUE KEY unique_acl_sid (sid, principal)
) ENGINE=InnoDB;
CREATE TABLE acl_class (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
class VARCHAR(100) NOT NULL,
UNIQUE KEY uk_acl_class (class)
) ENGINE=InnoDB;
CREATE TABLE acl_object_identity (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
object_id_class BIGINT UNSIGNED NOT NULL,
object_id_identity BIGINT NOT NULL,
parent_object BIGINT UNSIGNED,
owner_sid BIGINT UNSIGNED,
entries_inheriting BOOLEAN NOT NULL,
UNIQUE KEY uk_acl_object_identity (object_id_class, object_id_identity),
CONSTRAINT fk_acl_object_identity_parent FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id),
CONSTRAINT fk_acl_object_identity_class FOREIGN KEY (object_id_class) REFERENCES acl_class (id),
CONSTRAINT fk_acl_object_identity_owner FOREIGN KEY (owner_sid) REFERENCES acl_sid (id)
) ENGINE=InnoDB;
CREATE TABLE acl_entry (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
acl_object_identity BIGINT UNSIGNED NOT NULL,
ace_order INTEGER NOT NULL,
sid BIGINT UNSIGNED NOT NULL,
mask INTEGER UNSIGNED NOT NULL,
granting BOOLEAN NOT NULL,
audit_success BOOLEAN NOT NULL,
audit_failure BOOLEAN NOT NULL,
UNIQUE KEY unique_acl_entry (acl_object_identity, ace_order),
CONSTRAINT fk_acl_entry_object FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity (id),
CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id)
) ENGINE=InnoDB;
@@ -0,0 +1,82 @@
-- ACL Schema SQL for Oracle Database 10g+
-- drop trigger acl_sid_id_trigger;
-- drop trigger acl_class_id_trigger;
-- drop trigger acl_object_identity_id_trigger;
-- drop trigger acl_entry_id_trigger;
-- drop sequence acl_sid_sequence;
-- drop sequence acl_class_sequence;
-- drop sequence acl_object_identity_sequence;
-- drop sequence acl_entry_sequence;
-- drop table acl_entry;
-- drop table acl_object_identity;
-- drop table acl_class;
-- drop table acl_sid;
CREATE TABLE acl_sid (
id NUMBER(38) NOT NULL PRIMARY KEY,
principal NUMBER(1) NOT NULL CHECK (principal in (0, 1)),
sid NVARCHAR2(100) NOT NULL,
CONSTRAINT unique_acl_sid UNIQUE (sid, principal)
);
CREATE SEQUENCE acl_sid_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE OR REPLACE TRIGGER acl_sid_id_trigger
BEFORE INSERT ON acl_sid
FOR EACH ROW
BEGIN
SELECT acl_sid_sequence.nextval INTO :new.id FROM dual;
END;
CREATE TABLE acl_class (
id NUMBER(38) NOT NULL PRIMARY KEY,
class NVARCHAR2(100) NOT NULL,
CONSTRAINT uk_acl_class UNIQUE (class)
);
CREATE SEQUENCE acl_class_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE OR REPLACE TRIGGER acl_class_id_trigger
BEFORE INSERT ON acl_class
FOR EACH ROW
BEGIN
SELECT acl_class_sequence.nextval INTO :new.id FROM dual;
END;
CREATE TABLE acl_object_identity (
id NUMBER(38) NOT NULL PRIMARY KEY,
object_id_class NUMBER(38) NOT NULL,
object_id_identity NUMBER(38) NOT NULL,
parent_object NUMBER(38),
owner_sid NUMBER(38),
entries_inheriting NUMBER(1) NOT NULL CHECK (entries_inheriting in (0, 1)),
CONSTRAINT uk_acl_object_identity UNIQUE (object_id_class, object_id_identity),
CONSTRAINT fk_acl_object_identity_parent FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id),
CONSTRAINT fk_acl_object_identity_class FOREIGN KEY (object_id_class) REFERENCES acl_class (id),
CONSTRAINT fk_acl_object_identity_owner FOREIGN KEY (owner_sid) REFERENCES acl_sid (id)
);
CREATE SEQUENCE acl_object_identity_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE OR REPLACE TRIGGER acl_object_identity_id_trigger
BEFORE INSERT ON acl_object_identity
FOR EACH ROW
BEGIN
SELECT acl_object_identity_sequence.nextval INTO :new.id FROM dual;
END;
CREATE TABLE acl_entry (
id NUMBER(38) NOT NULL PRIMARY KEY,
acl_object_identity NUMBER(38) NOT NULL,
ace_order INTEGER NOT NULL,
sid NUMBER(38) NOT NULL,
mask INTEGER NOT NULL,
granting NUMBER(1) NOT NULL CHECK (granting in (0, 1)),
audit_success NUMBER(1) NOT NULL CHECK (audit_success in (0, 1)),
audit_failure NUMBER(1) NOT NULL CHECK (audit_failure in (0, 1)),
CONSTRAINT unique_acl_entry UNIQUE (acl_object_identity, ace_order),
CONSTRAINT fk_acl_entry_object FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity (id),
CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id)
);
CREATE SEQUENCE acl_entry_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE OR REPLACE TRIGGER acl_entry_id_trigger
BEFORE INSERT ON acl_entry
FOR EACH ROW
BEGIN
SELECT acl_entry_sequence.nextval INTO :new.id FROM dual;
END;
@@ -0,0 +1,46 @@
-- ACL Schema SQL for Microsoft SQL Server 2008+
-- drop table acl_entry;
-- drop table acl_object_identity;
-- drop table acl_class;
-- drop table acl_sid;
CREATE TABLE acl_sid (
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
principal BIT NOT NULL,
sid VARCHAR(100) NOT NULL,
CONSTRAINT unique_acl_sid UNIQUE (sid, principal)
);
CREATE TABLE acl_class (
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
class VARCHAR(100) NOT NULL,
CONSTRAINT uk_acl_class UNIQUE (class)
);
CREATE TABLE acl_object_identity (
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
object_id_class BIGINT NOT NULL,
object_id_identity BIGINT NOT NULL,
parent_object BIGINT,
owner_sid BIGINT,
entries_inheriting BIT NOT NULL,
CONSTRAINT uk_acl_object_identity UNIQUE (object_id_class, object_id_identity),
CONSTRAINT fk_acl_object_identity_parent FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id),
CONSTRAINT fk_acl_object_identity_class FOREIGN KEY (object_id_class) REFERENCES acl_class (id),
CONSTRAINT fk_acl_object_identity_owner FOREIGN KEY (owner_sid) REFERENCES acl_sid (id)
);
CREATE TABLE acl_entry (
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
acl_object_identity BIGINT NOT NULL,
ace_order INTEGER NOT NULL,
sid BIGINT NOT NULL,
mask INTEGER NOT NULL,
granting BIT NOT NULL,
audit_success BIT NOT NULL,
audit_failure BIT NOT NULL,
CONSTRAINT unique_acl_entry UNIQUE (acl_object_identity, ace_order),
CONSTRAINT fk_acl_entry_object FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity (id),
CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id)
);
@@ -77,7 +77,7 @@ public class AclImplTests {
@Test(expected=IllegalArgumentException.class)
public void constructorsRejectNullAclAuthzStrategy() throws Exception {
try {
new AclImpl(objectIdentity, 1, null, mockAuditLogger, null, null, true, new PrincipalSid("joe"));
new AclImpl(objectIdentity, 1, null, new DefaultPermissionGrantingStrategy(mockAuditLogger), null, null, true, new PrincipalSid("joe"));
fail("It should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
@@ -223,7 +223,6 @@ public class AclImplementationSecurityCheckTests {
}
}
@SuppressWarnings("deprecation")
@Test
public void testSecurityCheckPrincipalOwner() throws Exception {
Authentication auth = new TestingAuthenticationToken("user", "password", "ROLE_ONE");
@@ -235,7 +234,7 @@ public class AclImplementationSecurityCheckTests {
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
Acl acl = new AclImpl(identity, 1, aclAuthorizationStrategy, new ConsoleAuditLogger(), null, null,
Acl acl = new AclImpl(identity, 1, aclAuthorizationStrategy, new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()), null, null,
false, new PrincipalSid(auth));
try {
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_GENERAL);
@@ -9,15 +9,7 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.domain.ConsoleAuditLogger;
import org.springframework.security.acls.domain.DefaultPermissionFactory;
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
import org.springframework.security.acls.domain.EhCacheBasedAclCache;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.domain.*;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.AuditableAccessControlEntry;
import org.springframework.security.acls.model.MutableAcl;
@@ -92,7 +84,7 @@ public class BasicLookupStrategyTests {
@Before
public void initializeBeans() {
EhCacheBasedAclCache cache = new EhCacheBasedAclCache(getCache());
EhCacheBasedAclCache cache = new EhCacheBasedAclCache(getCache(), new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()), new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_USER")));
AclAuthorizationStrategy authorizationStrategy = new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_ADMINISTRATOR"));
strategy = new BasicLookupStrategy(dataSource, cache, authorizationStrategy,
new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()));
@@ -301,4 +293,20 @@ public class BasicLookupStrategyTests {
strategy.readAclsById(Arrays.asList(oid), Arrays.asList(BEN_SID));
}
@Test
public void testCreatePrincipalSid() {
Sid result = strategy.createSid(true, "sid");
Assert.assertEquals(PrincipalSid.class, result.getClass());
Assert.assertEquals("sid", ((PrincipalSid)result).getPrincipal());
}
@Test
public void testCreateGrantedAuthority() {
Sid result = strategy.createSid(false, "sid");
Assert.assertEquals(GrantedAuthoritySid.class, result.getClass());
Assert.assertEquals("sid", ((GrantedAuthoritySid)result).getGrantedAuthority());
}
}
@@ -1,24 +1,9 @@
package org.springframework.security.acls.jdbc;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import org.junit.*;
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
import org.springframework.security.acls.domain.AclImpl;
import org.springframework.security.acls.domain.ConsoleAuditLogger;
import org.springframework.security.acls.domain.EhCacheBasedAclCache;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.util.FieldUtils;
import static org.fest.assertions.Assertions.*;
import java.io.File;
import java.io.FileInputStream;
@@ -26,53 +11,78 @@ import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.*;
import java.util.List;
import java.util.Map;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.security.acls.domain.*;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.util.FieldUtils;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.ReflectionUtils;
/**
* Tests {@link EhCacheBasedAclCache}
*
* @author Andrei Stefan
*/
@RunWith(MockitoJUnitRunner.class)
public class EhCacheBasedAclCacheTests {
private static final String TARGET_CLASS = "org.springframework.security.acls.TargetObject";
private static CacheManager cacheManager;
@Mock
private Ehcache cache;
@Captor
private ArgumentCaptor<Element> element;
@BeforeClass
public static void initCacheManaer() {
cacheManager = CacheManager.create();
// Use disk caching immediately (to test for serialization issue reported in SEC-527)
cacheManager.addCache(new Cache("ehcachebasedacltests", 0, true, false, 600, 300));
}
private EhCacheBasedAclCache myCache;
@AfterClass
public static void shutdownCacheManager() {
cacheManager.removalAll();
cacheManager.shutdown();
private MutableAcl acl;
@Before
public void setup() {
myCache = new EhCacheBasedAclCache(cache, new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()), new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_USER")));
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(100));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
acl = new AclImpl(identity, Long.valueOf(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
}
@After
public void clearContext() {
public void cleanup() {
SecurityContextHolder.clearContext();
}
private Ehcache getCache() {
Ehcache cache = cacheManager.getCache("ehcachebasedacltests");
cache.removeAll();
return cache;
}
@Test(expected=IllegalArgumentException.class)
public void constructorRejectsNullParameters() throws Exception {
new EhCacheBasedAclCache(null);
new EhCacheBasedAclCache(null, new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()), new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_USER")));
}
@Test
public void methodsRejectNullParameters() throws Exception {
Ehcache cache = new MockEhcache();
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
try {
Serializable id = null;
myCache.evictFromCache(id);
@@ -122,12 +132,6 @@ public class EhCacheBasedAclCacheTests {
// SEC-527
@Test
public void testDiskSerializationOfMutableAclObjectInstance() throws Exception {
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(100));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
MutableAcl acl = new AclImpl(identity, Long.valueOf(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
// Serialization test
File file = File.createTempFile("SEC_TEST", ".object");
FileOutputStream fos = new FileOutputStream(file);
@@ -150,111 +154,117 @@ public class EhCacheBasedAclCacheTests {
}
@Test
public void cacheOperationsAclWithoutParent() throws Exception {
Ehcache cache = getCache();
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
public void clearCache() throws Exception {
myCache.clearCache();
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(100));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
MutableAcl acl = new AclImpl(identity, Long.valueOf(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
assertEquals(0, cache.getDiskStoreSize());
myCache.putInCache(acl);
assertEquals(cache.getSize(), 2);
assertEquals(2, cache.getDiskStoreSize());
assertTrue(cache.isElementOnDisk(acl.getObjectIdentity()));
assertFalse(cache.isElementInMemory(acl.getObjectIdentity()));
// Check we can get from cache the same objects we put in
assertEquals(myCache.getFromCache(Long.valueOf(1)), acl);
assertEquals(myCache.getFromCache(identity), acl);
// Put another object in cache
ObjectIdentity identity2 = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(101));
MutableAcl acl2 = new AclImpl(identity2, Long.valueOf(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
myCache.putInCache(acl2);
assertEquals(cache.getSize(), 4);
assertEquals(4, cache.getDiskStoreSize());
// Try to evict an entry that doesn't exist
myCache.evictFromCache(Long.valueOf(3));
myCache.evictFromCache(new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(102)));
assertEquals(cache.getSize(), 4);
assertEquals(4, cache.getDiskStoreSize());
myCache.evictFromCache(Long.valueOf(1));
assertEquals(cache.getSize(), 2);
assertEquals(2, cache.getDiskStoreSize());
// Check the second object inserted
assertEquals(myCache.getFromCache(Long.valueOf(2)), acl2);
assertEquals(myCache.getFromCache(identity2), acl2);
myCache.evictFromCache(identity2);
assertEquals(cache.getSize(), 0);
verify(cache).removeAll();
}
@SuppressWarnings("unchecked")
@Test
public void cacheOperationsAclWithParent() throws Exception {
Ehcache cache = getCache();
EhCacheBasedAclCache myCache = new EhCacheBasedAclCache(cache);
public void putInCache() throws Exception {
myCache.putInCache(acl);
verify(cache, times(2)).put(element.capture());
assertThat(element.getValue().getKey()).isEqualTo(acl.getId());
assertThat(element.getValue().getObjectValue()).isEqualTo(acl);
assertThat(element.getAllValues().get(0).getKey()).isEqualTo(acl.getObjectIdentity());
assertThat(element.getAllValues().get(0).getObjectValue()).isEqualTo(acl);
}
@Test
public void putInCacheAclWithParent() throws Exception {
Authentication auth = new TestingAuthenticationToken("user", "password", "ROLE_GENERAL");
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
ObjectIdentity identity = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(1));
ObjectIdentity identityParent = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(2));
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
new SimpleGrantedAuthority("ROLE_OWNERSHIP"), new SimpleGrantedAuthority("ROLE_AUDITING"),
new SimpleGrantedAuthority("ROLE_GENERAL"));
MutableAcl acl = new AclImpl(identity, Long.valueOf(1), aclAuthorizationStrategy, new ConsoleAuditLogger());
MutableAcl parentAcl = new AclImpl(identityParent, Long.valueOf(2), aclAuthorizationStrategy, new ConsoleAuditLogger());
acl.setParent(parentAcl);
assertEquals(0, cache.getDiskStoreSize());
myCache.putInCache(acl);
assertEquals(cache.getSize(), 4);
assertEquals(4, cache.getDiskStoreSize());
assertTrue(cache.isElementOnDisk(acl.getObjectIdentity()));
assertTrue(cache.isElementOnDisk(Long.valueOf(1)));
assertFalse(cache.isElementInMemory(acl.getObjectIdentity()));
assertFalse(cache.isElementInMemory(Long.valueOf(1)));
cache.flush();
// Wait for the spool to be written to disk (it's asynchronous)
Map spool = (Map) FieldUtils.getFieldValue(cache, "diskStore.spool");
while(spool.size() > 0) {
Thread.sleep(50);
}
verify(cache, times(4)).put(element.capture());
// Check we can get from cache the same objects we put in
AclImpl aclFromCache = (AclImpl) myCache.getFromCache(Long.valueOf(1));
// For the checks on transient fields, we need to be sure that the object is being loaded from the cache,
// not from the ehcache spool or elsewhere...
assertFalse(acl == aclFromCache);
assertEquals(acl, aclFromCache);
// SEC-951 check transient fields are set on parent
assertNotNull(FieldUtils.getFieldValue(aclFromCache.getParentAcl(), "aclAuthorizationStrategy"));
assertNotNull(FieldUtils.getFieldValue(aclFromCache.getParentAcl(), "permissionGrantingStrategy"));
assertEquals(acl, myCache.getFromCache(identity));
assertNotNull(FieldUtils.getFieldValue(aclFromCache, "aclAuthorizationStrategy"));
AclImpl parentAclFromCache = (AclImpl) myCache.getFromCache(Long.valueOf(2));
assertEquals(parentAcl, parentAclFromCache);
assertNotNull(FieldUtils.getFieldValue(parentAclFromCache, "aclAuthorizationStrategy"));
assertEquals(parentAcl, myCache.getFromCache(identityParent));
List<Element> allValues = element.getAllValues();
assertThat(allValues.get(0).getKey()).isEqualTo(parentAcl.getObjectIdentity());
assertThat(allValues.get(0).getObjectValue()).isEqualTo(parentAcl);
assertThat(allValues.get(1).getKey()).isEqualTo(parentAcl.getId());
assertThat(allValues.get(1).getObjectValue()).isEqualTo(parentAcl);
assertThat(allValues.get(2).getKey()).isEqualTo(acl.getObjectIdentity());
assertThat(allValues.get(2).getObjectValue()).isEqualTo(acl);
assertThat(allValues.get(3).getKey()).isEqualTo(acl.getId());
assertThat(allValues.get(3).getObjectValue()).isEqualTo(acl);
}
//~ Inner Classes ==================================================================================================
@Test
public void getFromCacheSerializable() throws Exception {
when(cache.get(acl.getId())).thenReturn(new Element(acl.getId(),acl));
private class MockEhcache extends Cache {
public MockEhcache() {
super("cache", 0, true, true, 0, 0);
}
assertThat(myCache.getFromCache(acl.getId())).isEqualTo(acl);
}
@Test
public void getFromCacheSerializablePopulatesTransient() throws Exception {
when(cache.get(acl.getId())).thenReturn(new Element(acl.getId(),acl));
myCache.putInCache(acl);
ReflectionTestUtils.setField(acl, "permissionGrantingStrategy", null);
ReflectionTestUtils.setField(acl, "aclAuthorizationStrategy", null);
MutableAcl fromCache = myCache.getFromCache(acl.getId());
assertThat(ReflectionTestUtils.getField(fromCache, "aclAuthorizationStrategy")).isNotNull();
assertThat(ReflectionTestUtils.getField(fromCache, "permissionGrantingStrategy")).isNotNull();
}
@Test
public void getFromCacheObjectIdentity() throws Exception {
when(cache.get(acl.getId())).thenReturn(new Element(acl.getId(),acl));
assertThat(myCache.getFromCache(acl.getId())).isEqualTo(acl);
}
@Test
public void getFromCacheObjectIdentityPopulatesTransient() throws Exception {
when(cache.get(acl.getObjectIdentity())).thenReturn(new Element(acl.getId(),acl));
myCache.putInCache(acl);
ReflectionTestUtils.setField(acl, "permissionGrantingStrategy", null);
ReflectionTestUtils.setField(acl, "aclAuthorizationStrategy", null);
MutableAcl fromCache = myCache.getFromCache(acl.getObjectIdentity());
assertThat(ReflectionTestUtils.getField(fromCache, "aclAuthorizationStrategy")).isNotNull();
assertThat(ReflectionTestUtils.getField(fromCache, "permissionGrantingStrategy")).isNotNull();
}
@Test
public void evictCacheSerializable() throws Exception {
when(cache.get(acl.getObjectIdentity())).thenReturn(new Element(acl.getId(),acl));
myCache.evictFromCache(acl.getObjectIdentity());
verify(cache).remove(acl.getId());
verify(cache).remove(acl.getObjectIdentity());
}
@Test
public void evictCacheObjectIdentity() throws Exception {
when(cache.get(acl.getId())).thenReturn(new Element(acl.getId(),acl));
myCache.evictFromCache(acl.getId());
verify(cache).remove(acl.getId());
verify(cache).remove(acl.getObjectIdentity());
}
}
@@ -15,6 +15,7 @@
package org.springframework.security.acls.jdbc;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.util.Arrays;
import java.util.List;
@@ -43,6 +44,7 @@ import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.Sid;
import org.springframework.security.acls.sid.CustomSid;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
@@ -489,6 +491,43 @@ public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4Sprin
assertTrue(topParent.isGranted(Arrays.asList(cm), Arrays.asList(benSid), true));
SecurityContextHolder.clearContext();
}
}
@Test
public void testProcessingCustomSid() {
CustomJdbcMutableAclService customJdbcMutableAclService = spy(new CustomJdbcMutableAclService(dataSource,
lookupStrategy, aclCache));
CustomSid customSid = new CustomSid("Custom sid");
when(customJdbcMutableAclService.createOrRetrieveSidPrimaryKey("Custom sid", false, false)).thenReturn(1L);
Long result = customJdbcMutableAclService.createOrRetrieveSidPrimaryKey(customSid, false);
assertEquals(result, new Long(1L));
}
/**
* This class needed to show how to extend {@link JdbcMutableAclService} for processing
* custom {@link Sid} implementations
*/
private class CustomJdbcMutableAclService extends JdbcMutableAclService {
private CustomJdbcMutableAclService(DataSource dataSource, LookupStrategy lookupStrategy, AclCache aclCache) {
super(dataSource, lookupStrategy, aclCache);
}
@Override
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
String sidName;
boolean isPrincipal = false;
if (sid instanceof CustomSid) {
sidName = ((CustomSid)sid).getSid();
} else if (sid instanceof GrantedAuthoritySid) {
sidName = ((GrantedAuthoritySid)sid).getGrantedAuthority();
} else {
sidName = ((PrincipalSid)sid).getPrincipal();
isPrincipal = true;
}
return createOrRetrieveSidPrimaryKey(sidName, isPrincipal, allowCreate);
}
}
}
@@ -0,0 +1,24 @@
package org.springframework.security.acls.sid;
import org.springframework.security.acls.model.Sid;
/**
* This class is example of custom {@link Sid} implementation
* @author Mikhail Stryzhonok
*/
public class CustomSid implements Sid {
private String sid;
public CustomSid(String sid) {
this.sid = sid;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
}
@@ -22,6 +22,25 @@
<property name="cacheName" value="aclCache"/>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy">
<constructor-arg>
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
</constructor-arg>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_USER"/>
</bean>
</list>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
-24
View File
@@ -1,24 +0,0 @@
Implementation-Title: org.springframework.security.acls
Implementation-Version: ${version}
Bundle-SymbolicName: org.springframework.security.acls
Bundle-Name: Spring Security Acls
Bundle-Vendor: SpringSource
Bundle-Version: ${version}
Bundle-ManifestVersion: 2
Ignored-Existing-Headers:
Import-Package,
Export-Package
Import-Template:
org.aopalliance.*;version="${aopAllianceRange}",
org.apache.commons.logging.*;version="${cloggingRange}",
org.springframework.cache.*;version="${springRange}";resolution:=optional,
org.springframework.security.core.*;version="${secRange}",
org.springframework.security.access.*;version="${secRange}",
org.springframework.security.util.*;version="${secRange}",
org.springframework.context.*;version="${springRange}";resolution:=optional,
org.springframework.dao.*;version="${springRange}";resolution:=optional,
org.springframework.jdbc.core.*;version="${springRange}";resolution:=optional,
org.springframework.transaction.support.*;version="${springRange}";resolution:=optional,
org.springframework.util.*;version="${springRange}";resolution:=optional,
net.sf.ehcache.*;version="${ehcacheRange}";resolution:=optional,
javax.sql.*;version="0";resolution:=optional
+1
View File
@@ -1,6 +1,7 @@
dependencies {
compile project(':spring-security-core'),
springCoreDependency,
"org.springframework:spring-beans:$springVersion",
"org.springframework:spring-context:$springVersion"
+26 -27
View File
@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-aspects</artifactId>
<version>3.2.1.CI-SNAPSHOT</version>
<version>4.0.0.RC1</version>
<name>spring-security-aspects</name>
<description>spring-security-aspects</description>
<url>http://spring.io/spring-security</url>
@@ -31,46 +30,35 @@
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>https://repo.spring.io/snapshot</url>
<id>spring-milestone</id>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.2.1.CI-SNAPSHOT</version>
<version>4.0.0.RC1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -82,14 +70,14 @@
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
<version>1.2</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.10</version>
<version>1.8.4</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
@@ -102,13 +90,13 @@
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.29</version>
<version>1.1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -126,20 +114,31 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.5</version>
<version>1.7.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -53,10 +53,9 @@ public class AnnotationSecurityAspectTests {
public final void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
interceptor = new AspectJMethodSecurityInterceptor();
adm = new AffirmativeBased();
AccessDecisionVoter[] voters = new AccessDecisionVoter[]
{new RoleVoter(), new PreInvocationAuthorizationAdviceVoter(new ExpressionBasedPreInvocationAdvice())};
adm.setDecisionVoters(Arrays.asList(voters));
adm = new AffirmativeBased(Arrays.<AccessDecisionVoter<? extends Object>>asList(voters));
interceptor.setAccessDecisionManager(adm);
interceptor.setAuthenticationManager(authman);
interceptor.setSecurityMetadataSource(new SecuredAnnotationSecurityMetadataSource());
-16
View File
@@ -1,16 +0,0 @@
Implementation-Title: org.springframework.security.aspects
Implementation-Version: ${version}
Bundle-SymbolicName: org.springframework.security.aspects
Bundle-Name: Spring Security Aspects
Bundle-Vendor: SpringSource
Bundle-ManifestVersion: 2
Bundle-Version: ${version}
Ignored-Existing-Headers:
Import-Package,
Export-Package
Import-Template:
org.aspectj.*;version="${aspectjRange}";resolution:=optional,
org.apache.commons.logging.*;version="${cloggingRange}",
org.springframework.security.core.*;version="${secRange}",
org.springframework.security.access.intercept.aspectj;version="${secRange}",
org.springframework.beans.factory;version="${springRange}"
+15 -43
View File
@@ -2,15 +2,15 @@ import groovy.text.SimpleTemplateEngine
buildscript {
repositories {
maven { url "http://repo.springsource.org/plugins-release" }
maven { url "https://repo.spring.io/plugins-release" }
}
dependencies {
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.5")
classpath("org.springframework.build.gradle:bundlor-plugin:0.1.2")
classpath("org.gradle.api.plugins:gradle-tomcat-plugin:0.9.8")
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.7")
classpath("org.springframework.build.gradle:spring-io-plugin:0.0.3.RELEASE")
classpath("org.gradle.api.plugins:gradle-tomcat-plugin:1.2.5")
classpath('me.champeau.gradle:gradle-javadoc-hotfix-plugin:0.1')
classpath('org.asciidoctor:asciidoctor-gradle-plugin:0.7.0')
classpath('org.asciidoctor:asciidoctor-java-integration:0.1.4.preview.1')
classpath('org.asciidoctor:asciidoctor-gradle-plugin:1.5.1')
classpath("io.spring.gradle:docbook-reference-plugin:0.3.0")
}
}
@@ -25,10 +25,8 @@ allprojects {
ext.releaseBuild = version.endsWith('RELEASE')
ext.snapshotBuild = version.endsWith('SNAPSHOT')
ext.springVersion = '3.2.8.RELEASE'
ext.spring4Version = '4.0.2.RELEASE'
ext.springLdapVersion = '1.3.2.RELEASE'
ext.springLdap2Version = '2.0.1.RELEASE'
ext.springVersion = '4.1.3.RELEASE'
ext.springLdapVersion = '2.0.2.RELEASE'
group = 'org.springframework.security'
@@ -39,7 +37,7 @@ allprojects {
maven { url "http://repo.terracotta.org/maven2/" }
}
eclipse.project.name = "${project.name}-3.2.x"
eclipse.project.name = "${project.name}-4.0.x"
}
sonarRunner {
@@ -61,7 +59,7 @@ ext.javaProjects = subprojects.findAll { project -> project.name != 'docs' && pr
ext.sampleProjects = subprojects.findAll { project -> project.name.startsWith('spring-security-samples') }
ext.itestProjects = subprojects.findAll { project -> project.name.startsWith('itest') }
ext.coreModuleProjects = javaProjects - sampleProjects - itestProjects
ext.aspectjProjects = [project(':spring-security-aspects'), project(':spring-security-samples-aspectj-xml')]
ext.aspectjProjects = [project(':spring-security-aspects'), project(':spring-security-samples-aspectj-xml'), project(':spring-security-samples-aspectj-jc')]
configure(allprojects - javaProjects) {
task afterEclipseImport {
@@ -98,35 +96,17 @@ configure(javaProjects) {
}
configure(coreModuleProjects) {
apply plugin: 'bundlor'
apply plugin: 'emma'
apply plugin: 'spring-io'
ext.springIoVersion = project.hasProperty('platformVersion') ? platformVersion : '1.1.0.BUILD-SNAPSHOT'
bundlor.doFirst {
def templateText = file("template.mf").text
bundlor.manifestTemplate = new SimpleTemplateEngine().createTemplate(templateText).make(bundlorProperties).toString()
}
configurations {
jacoco //Configuration Group used by Sonar to provide Code Coverage using JaCoCo
spring4TestRuntime.extendsFrom testRuntime
}
configurations.spring4TestRuntime {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
if (details.requested.group == 'org.springframework') {
details.useVersion spring4Version
}
if (details.requested.name == 'ehcache') {
details.useVersion '2.6.5'
}
if (details.requested.name == 'ehcache-terracotta') {
details.useVersion '2.1.1'
}
if (details.requested.group == 'org.springframework.ldap') {
details.useVersion springLdap2Version
}
}
}
dependencies {
springIoVersions "io.spring.platform:platform-versions:${springIoVersion}@properties"
jacoco "org.jacoco:org.jacoco.agent:0.6.2.201302030002:runtime"
}
test {
@@ -135,14 +115,6 @@ configure(coreModuleProjects) {
integrationTest {
jvmArgs "-javaagent:${configurations.jacoco.asPath}=destfile=${buildDir}/jacoco.exec,includes=${project.group}.*"
}
task spring4Test(type: Test) {
jvmArgs = ['-ea', '-Xmx500m', '-XX:MaxPermSize=128M']
exclude "**/EhCacheBasedAclCacheTests.class", "**/Issue55Tests.class"
classpath = sourceSets.test.output + sourceSets.main.output + configurations.spring4TestRuntime
testResultsDir = file("$buildDir/spring4-test-results/")
testReportDir = file("$buildDir/reports/spring4-tests/")
}
check.dependsOn spring4Test
}
configure (aspectjProjects) {
@@ -194,5 +166,5 @@ artifacts {
}
task wrapper(type: Wrapper) {
gradleVersion = '1.10-rc-2'
gradleVersion = '1.12'
}
@@ -30,7 +30,7 @@ class AspectJPlugin implements Plugin<Project> {
}
if (project.configurations.findByName('ajtools') == null) {
project.configurations.add('ajtools')
project.configurations.create('ajtools')
project.dependencies {
ajtools "org.aspectj:aspectjtools:${project.aspectjVersion}"
optional "org.aspectj:aspectjrt:${project.aspectjVersion}"
@@ -38,10 +38,10 @@ class AspectJPlugin implements Plugin<Project> {
}
if (project.configurations.findByName('aspectpath') == null) {
project.configurations.add('aspectpath')
project.configurations.create('aspectpath')
}
project.tasks.add(name: 'compileAspect', overwrite: true, description: 'Compiles AspectJ Source', type: Ajc) {
project.tasks.create(name: 'compileAspect', overwrite: true, description: 'Compiles AspectJ Source', type: Ajc) {
dependsOn project.configurations*.getTaskDependencyFromProjectDependency(true, "compileJava")
dependsOn project.processResources
@@ -54,7 +54,7 @@ class AspectJPlugin implements Plugin<Project> {
project.tasks.compileJava.dependsOn project.tasks.compileAspect
project.tasks.add(name: 'compileTestAspect', overwrite: true, description: 'Compiles AspectJ Test Source', type: Ajc) {
project.tasks.create(name: 'compileTestAspect', overwrite: true, description: 'Compiles AspectJ Test Source', type: Ajc) {
dependsOn project.processTestResources, project.compileJava, project.jar
sourceSet = project.sourceSets.test
inputs.files(sourceSet.allSource)
@@ -21,7 +21,7 @@ class EmmaPlugin implements Plugin<Project> {
def emmaCoverageFile = "${rootProject.buildDir}/emma/emma.ec"
if (project.configurations.findByName('emma_rt') == null) {
project.configurations.add('emma_rt')
project.configurations.create('emma_rt')
project.dependencies {
emma_rt 'emma:emma:2.0.5312'
}
@@ -64,7 +64,7 @@ class EmmaPlugin implements Plugin<Project> {
CoverageReport task;
if (reportTasks.isEmpty()) {
task = rootProject.tasks.add('coverageReport', CoverageReport.class);
task = rootProject.tasks.create('coverageReport', CoverageReport.class);
task.dataPath = [emmaMetaDataFile, emmaCoverageFile];
} else {
task = reportTasks[0];
@@ -17,7 +17,7 @@ import org.gradle.api.file.FileCollection
*/
class TrangPlugin implements Plugin<Project> {
public void apply(Project project) {
Task rncToXsd = project.tasks.add('rncToXsd', RncToXsd.class)
Task rncToXsd = project.tasks.create('rncToXsd', RncToXsd.class)
rncToXsd.description = 'Converts .rnc to .xsd'
rncToXsd.group = 'Build'
}
+3 -2
View File
@@ -2,12 +2,13 @@
dependencies {
compile project(':spring-security-core'),
project(':spring-security-web'),
springCoreDependency,
"org.springframework:spring-context:$springVersion",
"org.springframework:spring-beans:$springVersion",
"org.springframework:spring-web:$springVersion",
"org.jasig.cas.client:cas-client-core:3.2.1"
"org.jasig.cas.client:cas-client-core:$casClientVersion"
optional "net.sf.ehcache:ehcache:$ehcacheVersion"
provided "org.apache.tomcat:tomcat-servlet-api:$servletApiVersion"
provided "javax.servlet:javax.servlet-api:$servletApiVersion"
}
+31 -32
View File
@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
<version>3.2.1.CI-SNAPSHOT</version>
<version>4.0.0.RC1</version>
<name>spring-security-cas</name>
<description>spring-security-cas</description>
<url>http://spring.io/spring-security</url>
@@ -31,58 +30,47 @@
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>https://repo.spring.io/snapshot</url>
<id>spring-milestone</id>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.2.1</version>
<version>3.3.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.2.1.CI-SNAPSHOT</version>
<version>4.0.0.RC1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.2.1.CI-SNAPSHOT</version>
<version>4.0.0.RC1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -94,39 +82,39 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
<version>1.2</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>1.6.2</version>
<version>2.9.0</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
<version>7.0.33</version>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.29</version>
<version>1.1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -144,14 +132,25 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.5</version>
<version>1.7.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -49,9 +49,7 @@ public class ServiceProperties implements InitializingBean {
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
if(!authenticateAllArtifacts) {
Assert.hasLength(this.service, "service must be specified unless authenticateAllArtifacts is true.");
}
Assert.hasLength(this.service, "service cannot be empty.");
Assert.hasLength(this.artifactParameter, "artifactParameter cannot be empty.");
Assert.hasLength(this.serviceParameter, "serviceParameter cannot be empty.");
}
@@ -62,7 +60,7 @@ public class ServiceProperties implements InitializingBean {
* This service is the callback URL belonging to the local Spring Security System for Spring secured application.
* For example,
* <pre>
* https://www.mycompany.com/application/j_spring_cas_security_check
* https://www.mycompany.com/application/login/cas
* </pre>
*
* @return the URL of the service the user is authenticating to
@@ -185,15 +185,15 @@ public class CasAuthenticationProvider implements AuthenticationProvider, Initia
return this.authenticationUserDetailsService.loadUserDetails(token);
}
@Deprecated
@SuppressWarnings("unchecked")
/**
* @deprecated as of 3.0. Use the {@link org.springframework.security.cas.authentication.CasAuthenticationProvider#setAuthenticationUserDetailsService(org.springframework.security.core.userdetails.AuthenticationUserDetailsService)} instead.
* Sets the UserDetailsService to use. This is a convenience method to invoke
*/
public void setUserDetailsService(final UserDetailsService userDetailsService) {
this.authenticationUserDetailsService = new UserDetailsByNameServiceWrapper(userDetailsService);
}
public void setAuthenticationUserDetailsService(final AuthenticationUserDetailsService<CasAssertionAuthenticationToken> authenticationUserDetailsService) {
this.authenticationUserDetailsService = authenticationUserDetailsService;
}
@@ -55,9 +55,7 @@ public class CasAuthenticationEntryPoint implements AuthenticationEntryPoint, In
* disable the session encoding is provided for backwards compatibility.
*
* By default, encoding is enabled.
* @deprecated since 3.0.0 because CAS is currently on 3.3.5.
*/
@Deprecated
private boolean encodeServiceUrlWithSessionId = true;
//~ Methods ========================================================================================================
@@ -135,9 +133,7 @@ public class CasAuthenticationEntryPoint implements AuthenticationEntryPoint, In
* Sets whether to encode the service url with the session id or not.
*
* @param encodeServiceUrlWithSessionId whether to encode the service url with the session id or not.
* @deprecated since 3.0.0 because CAS is currently on 3.3.5.
*/
@Deprecated
public final void setEncodeServiceUrlWithSessionId(final boolean encodeServiceUrlWithSessionId) {
this.encodeServiceUrlWithSessionId = encodeServiceUrlWithSessionId;
}
@@ -146,9 +142,7 @@ public class CasAuthenticationEntryPoint implements AuthenticationEntryPoint, In
* Sets whether to encode the service url with the session id or not.
* @return whether to encode the service url with the session id or not.
*
* @deprecated since 3.0.0 because CAS is currently on 3.3.5.
*/
@Deprecated
protected boolean getEncodeServiceUrlWithSessionId() {
return this.encodeServiceUrlWithSessionId;
}
@@ -38,6 +38,8 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
/**
@@ -49,7 +51,7 @@ import org.springframework.util.Assert;
* presented in the <code>ticket</code> request parameter.
* <p>
* This filter monitors the <code>service</code> URL so it can
* receive the service ticket and process it. By default this filter processes the URL <tt>/j_spring_cas_security_check</tt>.
* receive the service ticket and process it. By default this filter processes the URL <tt>/login/cas</tt>.
* When processing this URL, the value of {@link ServiceProperties#getService()} is used as the <tt>service</tt> when validating
* the <code>ticket</code>. This means that it is important that {@link ServiceProperties#getService()} specifies the same value
* as the <tt>filterProcessesUrl</tt>.
@@ -90,7 +92,7 @@ import org.springframework.util.Assert;
* <pre>
* &lt;b:bean id=&quot;serviceProperties&quot;
* class=&quot;org.springframework.security.cas.ServiceProperties&quot;
* p:service=&quot;https://service.example.com/cas-sample/j_spring_cas_security_check&quot;
* p:service=&quot;https://service.example.com/cas-sample/login/cas&quot;
* p:authenticateAllArtifacts=&quot;true&quot;/&gt;
* &lt;b:bean id=&quot;casEntryPoint&quot;
* class=&quot;org.springframework.security.cas.web.CasAuthenticationEntryPoint&quot;
@@ -100,7 +102,7 @@ import org.springframework.util.Assert;
* p:authenticationManager-ref=&quot;authManager&quot;
* p:serviceProperties-ref=&quot;serviceProperties&quot;
* p:proxyGrantingTicketStorage-ref=&quot;pgtStorage&quot;
* p:proxyReceptorUrl=&quot;/j_spring_cas_security_proxyreceptor&quot;&gt;
* p:proxyReceptorUrl=&quot;/login/cas/proxyreceptor&quot;&gt;
* &lt;b:property name=&quot;authenticationDetailsSource&quot;&gt;
* &lt;b:bean class=&quot;org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource&quot;/&gt;
* &lt;/b:property&gt;
@@ -127,7 +129,7 @@ import org.springframework.util.Assert;
* &lt;b:bean
* class=&quot;org.jasig.cas.client.validation.Cas20ProxyTicketValidator&quot;
* p:acceptAnyProxy=&quot;true&quot;
* p:proxyCallbackUrl=&quot;https://service.example.com/cas-sample/j_spring_cas_security_proxyreceptor&quot;
* p:proxyCallbackUrl=&quot;https://service.example.com/cas-sample/login/cas/proxyreceptor&quot;
* p:proxyGrantingTicketStorage-ref=&quot;pgtStorage&quot;&gt;
* &lt;b:constructor-arg value=&quot;https://login.example.org/cas&quot; /&gt;
* &lt;/b:bean&gt;
@@ -170,7 +172,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
/**
* The last portion of the receptor url, i.e. /proxy/receptor
*/
private String proxyReceptorUrl;
private RequestMatcher proxyReceptorMatcher;
/**
* The backing storage to store ProxyGrantingTicket requests.
@@ -186,7 +188,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
//~ Constructors ===================================================================================================
public CasAuthenticationFilter() {
super("/j_spring_cas_security_check");
super("/login/cas");
setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler());
}
@@ -254,7 +256,6 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
/**
* Overridden to provide proxying capabilities.
*/
@Override
protected boolean requiresAuthentication(final HttpServletRequest request, final HttpServletResponse response) {
final boolean serviceTicketRequest = serviceTicketRequest(request, response);
final boolean result = serviceTicketRequest || proxyReceptorRequest(request) || (proxyTicketRequest(serviceTicketRequest, request));
@@ -286,7 +287,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
}
public final void setProxyReceptorUrl(final String proxyReceptorUrl) {
this.proxyReceptorUrl = proxyReceptorUrl;
this.proxyReceptorMatcher = new AntPathRequestMatcher("/**" + proxyReceptorUrl);
}
public final void setProxyGrantingTicketStorage(
@@ -343,8 +344,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
* @return
*/
private boolean proxyReceptorRequest(final HttpServletRequest request) {
final String requestUri = request.getRequestURI();
final boolean result = proxyReceptorConfigured() && requestUri.endsWith(this.proxyReceptorUrl);
final boolean result = proxyReceptorConfigured() && proxyReceptorMatcher.matches(request);
if(logger.isDebugEnabled()) {
logger.debug("proxyReceptorRequest = "+result);
}
@@ -357,7 +357,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
* @return
*/
private boolean proxyReceptorConfigured() {
final boolean result = this.proxyGrantingTicketStorage != null && !CommonUtils.isEmpty(this.proxyReceptorUrl);
final boolean result = this.proxyGrantingTicketStorage != null && proxyReceptorMatcher != null;
if(logger.isDebugEnabled()) {
logger.debug("proxyReceptorConfigured = "+result);
}
@@ -1,12 +1,12 @@
/*
* Copyright 2011 the original author or authors.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,6 +15,8 @@
*/
package org.springframework.security.cas.web.authentication;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
@@ -50,11 +52,13 @@ final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
* string from containing the artifact name and value. This can
* be created using {@link #createArtifactPattern(String)}.
*/
DefaultServiceAuthenticationDetails(HttpServletRequest request, Pattern artifactPattern) {
DefaultServiceAuthenticationDetails(String casService, HttpServletRequest request, Pattern artifactPattern) throws MalformedURLException {
super(request);
URL casServiceUrl = new URL(casService);
int port = getServicePort(casServiceUrl);
final String query = getQueryString(request,artifactPattern);
this.serviceUrl = UrlUtils.buildFullRequestUrl(request.getScheme(),
request.getServerName(), request.getServerPort(),
this.serviceUrl = UrlUtils.buildFullRequestUrl(casServiceUrl.getProtocol(),
casServiceUrl.getHost(), port,
request.getRequestURI(), query);
}
@@ -128,4 +132,17 @@ final class DefaultServiceAuthenticationDetails extends WebAuthenticationDetails
Assert.hasLength(artifactParameterName);
return Pattern.compile("&?"+Pattern.quote(artifactParameterName)+"=[^&]*");
}
/**
* Gets the port from the casServiceURL ensuring to return the proper value if the default port is being used.
* @param casServiceUrl the casServerUrl to be used (i.e. "https://example.com/context/login/cas")
* @return the port that is configured for the casServerUrl
*/
private static int getServicePort(URL casServiceUrl) {
int port = casServiceUrl.getPort();
if(port == -1) {
port = casServiceUrl.getDefaultPort();
}
return port;
}
}
@@ -1,12 +1,12 @@
/*
* Copyright 2011 the original author or authors.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,12 +15,14 @@
*/
package org.springframework.security.cas.web.authentication;
import java.net.MalformedURLException;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.util.Assert;
/**
* The {@code AuthenticationDetailsSource} that is set on the
@@ -38,24 +40,31 @@ public class ServiceAuthenticationDetailsSource implements AuthenticationDetails
private final Pattern artifactPattern;
private ServiceProperties serviceProperties;
//~ Constructors ===================================================================================================
/**
* Creates an implementation that uses the default CAS artifactParameterName.
* Creates an implementation that uses the specified ServiceProperites and the default CAS artifactParameterName.
*
* @param serviceProperties The ServiceProperties to use to construct the serviceUrl.
*/
public ServiceAuthenticationDetailsSource() {
this(ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER);
public ServiceAuthenticationDetailsSource(ServiceProperties serviceProperties) {
this(serviceProperties,ServiceProperties.DEFAULT_CAS_ARTIFACT_PARAMETER);
}
/**
* Creates an implementation that uses the specified artifactParameterName
*
* @param serviceProperties The ServiceProperties to use to construct the serviceUrl.
* @param artifactParameterName
* the artifactParameterName that is removed from the current
* URL. The result becomes the service url. Cannot be null and
* cannot be an empty String.
*/
public ServiceAuthenticationDetailsSource(final String artifactParameterName) {
public ServiceAuthenticationDetailsSource(ServiceProperties serviceProperties, String artifactParameterName) {
Assert.notNull(serviceProperties, "serviceProperties cannot be null");
this.serviceProperties = serviceProperties;
this.artifactPattern = DefaultServiceAuthenticationDetails.createArtifactPattern(artifactParameterName);
}
@@ -66,6 +75,10 @@ public class ServiceAuthenticationDetailsSource implements AuthenticationDetails
* @return the {@code ServiceAuthenticationDetails} containing information about the current request
*/
public ServiceAuthenticationDetails buildDetails(HttpServletRequest context) {
return new DefaultServiceAuthenticationDetails(context,artifactPattern);
try {
return new DefaultServiceAuthenticationDetails(serviceProperties.getService(),context,artifactPattern);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
}
@@ -19,7 +19,7 @@ public abstract class AbstractStatelessTicketCacheTests {
protected CasAuthenticationToken getToken() {
List<String> proxyList = new ArrayList<String>();
proxyList.add("https://localhost/newPortal/j_spring_cas_security_check");
proxyList.add("https://localhost/newPortal/login/cas");
User user = new User("rod", "password", true, true, true, true, AuthorityUtils.createAuthorityList("ROLE_ONE", "ROLE_TWO"));
final Assertion assertion = new AssertionImpl("rod");
@@ -69,7 +69,7 @@ public class CasAuthenticationEntryPointTests extends TestCase {
public void testNormalOperationWithRenewFalse() throws Exception {
ServiceProperties sp = new ServiceProperties();
sp.setSendRenew(false);
sp.setService("https://mycompany.com/bigWebApp/j_spring_cas_security_check");
sp.setService("https://mycompany.com/bigWebApp/login/cas");
CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint();
ep.setLoginUrl("https://cas/login");
@@ -84,14 +84,14 @@ public class CasAuthenticationEntryPointTests extends TestCase {
ep.commence(request, response, null);
assertEquals("https://cas/login?service="
+ URLEncoder.encode("https://mycompany.com/bigWebApp/j_spring_cas_security_check", "UTF-8"),
+ URLEncoder.encode("https://mycompany.com/bigWebApp/login/cas", "UTF-8"),
response.getRedirectedUrl());
}
public void testNormalOperationWithRenewTrue() throws Exception {
ServiceProperties sp = new ServiceProperties();
sp.setSendRenew(true);
sp.setService("https://mycompany.com/bigWebApp/j_spring_cas_security_check");
sp.setService("https://mycompany.com/bigWebApp/login/cas");
CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint();
ep.setLoginUrl("https://cas/login");
@@ -105,7 +105,7 @@ public class CasAuthenticationEntryPointTests extends TestCase {
ep.afterPropertiesSet();
ep.commence(request, response, null);
assertEquals("https://cas/login?service="
+ URLEncoder.encode("https://mycompany.com/bigWebApp/j_spring_cas_security_check", "UTF-8") + "&renew=true",
+ URLEncoder.encode("https://mycompany.com/bigWebApp/login/cas", "UTF-8") + "&renew=true",
response.getRedirectedUrl());
}
}
@@ -63,7 +63,6 @@ public class CasAuthenticationFilterTests {
@Test
public void testGettersSetters() {
CasAuthenticationFilter filter = new CasAuthenticationFilter();
assertEquals("/j_spring_cas_security_check", filter.getFilterProcessesUrl());
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
filter.setProxyReceptorUrl("/someurl");
filter.setServiceProperties(new ServiceProperties());
@@ -71,7 +70,8 @@ public class CasAuthenticationFilterTests {
@Test
public void testNormalOperation() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/j_spring_cas_security_check");
MockHttpServletRequest request = new MockHttpServletRequest();
request.setServletPath("/login/cas");
request.addParameter("ticket", "ST-0-ER94xMJmn6pha35CQRoZ");
CasAuthenticationFilter filter = new CasAuthenticationFilter();
@@ -101,11 +101,13 @@ public class CasAuthenticationFilterTests {
@Test
public void testRequiresAuthenticationFilterProcessUrl() {
String url = "/login/cas";
CasAuthenticationFilter filter = new CasAuthenticationFilter();
filter.setFilterProcessesUrl(url);
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
request.setRequestURI(filter.getFilterProcessesUrl());
request.setServletPath(url);
assertTrue(filter.requiresAuthentication(request, response));
}
@@ -115,13 +117,13 @@ public class CasAuthenticationFilterTests {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
request.setRequestURI("/pgtCallback");
request.setServletPath("/pgtCallback");
assertFalse(filter.requiresAuthentication(request, response));
filter.setProxyReceptorUrl(request.getRequestURI());
filter.setProxyReceptorUrl(request.getServletPath());
assertFalse(filter.requiresAuthentication(request, response));
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
assertTrue(filter.requiresAuthentication(request, response));
request.setRequestURI("/other");
request.setServletPath("/other");
assertFalse(filter.requiresAuthentication(request, response));
}
@@ -130,15 +132,17 @@ public class CasAuthenticationFilterTests {
ServiceProperties properties = new ServiceProperties();
properties.setAuthenticateAllArtifacts(true);
String url = "/login/cas";
CasAuthenticationFilter filter = new CasAuthenticationFilter();
filter.setFilterProcessesUrl(url);
filter.setServiceProperties(properties);
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
request.setRequestURI(filter.getFilterProcessesUrl());
request.setServletPath(url);
assertTrue(filter.requiresAuthentication(request, response));
request.setRequestURI("/other");
request.setServletPath("/other");
assertFalse(filter.requiresAuthentication(request, response));
request.setParameter(properties.getArtifactParameter(), "value");
assertTrue(filter.requiresAuthentication(request, response));
@@ -156,9 +160,9 @@ public class CasAuthenticationFilterTests {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
request.setRequestURI("/pgtCallback");
request.setServletPath("/pgtCallback");
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
filter.setProxyReceptorUrl(request.getRequestURI());
filter.setProxyReceptorUrl(request.getServletPath());
assertNull(filter.attemptAuthentication(request, response));
}
@@ -172,7 +176,7 @@ public class CasAuthenticationFilterTests {
serviceProperties.setAuthenticateAllArtifacts(true);
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("ticket", "ST-1-123");
request.setRequestURI("/authenticate");
request.setServletPath("/authenticate");
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain chain = mock(FilterChain.class);
@@ -189,7 +193,7 @@ public class CasAuthenticationFilterTests {
verifyZeroInteractions(successHandler);
// validate for when the filterProcessUrl matches
filter.setFilterProcessesUrl(request.getRequestURI());
filter.setFilterProcessesUrl(request.getServletPath());
SecurityContextHolder.clearContext();
filter.doFilter(request,response,chain);
verifyNoMoreInteractions(chain);
@@ -204,9 +208,9 @@ public class CasAuthenticationFilterTests {
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain chain = mock(FilterChain.class);
request.setRequestURI("/pgtCallback");
request.setServletPath("/pgtCallback");
filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class));
filter.setProxyReceptorUrl(request.getRequestURI());
filter.setProxyReceptorUrl(request.getServletPath());
filter.doFilter(request,response,chain);
verifyZeroInteractions(chain);
@@ -36,10 +36,13 @@ public class ServicePropertiesTests {
}
@Test
public void allowNullServiceWhenAuthenticateAllTokens() throws Exception {
public void nullServiceWhenAuthenticateAllTokens() throws Exception {
ServiceProperties sp = new ServiceProperties();
sp.setAuthenticateAllArtifacts(true);
sp.afterPropertiesSet();
try {
sp.afterPropertiesSet();
fail("Expected Exception");
}catch(IllegalArgumentException success) {}
sp.setAuthenticateAllArtifacts(false);
try {
sp.afterPropertiesSet();
@@ -18,11 +18,21 @@ import static org.junit.Assert.assertEquals;
import java.util.regex.Pattern;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
*
@@ -32,9 +42,13 @@ public class DefaultServiceAuthenticationDetailsTests {
private DefaultServiceAuthenticationDetails details;
private MockHttpServletRequest request;
private Pattern artifactPattern;
private String casServiceUrl;
private ConfigurableApplicationContext context;
@Before
public void setUp() {
casServiceUrl = "https://localhost:8443/j_spring_security_cas";
request = new MockHttpServletRequest();
request.setScheme("https");
request.setServerName("localhost");
@@ -44,45 +58,74 @@ public class DefaultServiceAuthenticationDetailsTests {
}
@Test
public void getServiceUrlNullQuery() throws Exception {
details = new DefaultServiceAuthenticationDetails(request,artifactPattern);
assertEquals(UrlUtils.buildFullRequestUrl(request),details.getServiceUrl());
@After
public void cleanup() {
if(context != null) {
context.close();
}
}
@Test
public void getServiceUrlTicketOnlyParam() {
public void getServiceUrlNullQuery() throws Exception {
details = new DefaultServiceAuthenticationDetails(casServiceUrl, request,artifactPattern);
assertEquals(UrlUtils.buildFullRequestUrl(request), details.getServiceUrl());
}
@Test
public void getServiceUrlTicketOnlyParam() throws Exception {
request.setQueryString("ticket=123");
details = new DefaultServiceAuthenticationDetails(request,artifactPattern);
details = new DefaultServiceAuthenticationDetails(casServiceUrl,request,artifactPattern);
String serviceUrl = details.getServiceUrl();
request.setQueryString(null);
assertEquals(UrlUtils.buildFullRequestUrl(request),serviceUrl);
}
@Test
public void getServiceUrlTicketFirstMultiParam() {
public void getServiceUrlTicketFirstMultiParam() throws Exception {
request.setQueryString("ticket=123&other=value");
details = new DefaultServiceAuthenticationDetails(request,artifactPattern);
details = new DefaultServiceAuthenticationDetails(casServiceUrl, request,artifactPattern);
String serviceUrl = details.getServiceUrl();
request.setQueryString("other=value");
assertEquals(UrlUtils.buildFullRequestUrl(request),serviceUrl);
}
@Test
public void getServiceUrlTicketLastMultiParam() {
public void getServiceUrlTicketLastMultiParam() throws Exception {
request.setQueryString("other=value&ticket=123");
details = new DefaultServiceAuthenticationDetails(request,artifactPattern);
details = new DefaultServiceAuthenticationDetails(casServiceUrl,request,artifactPattern);
String serviceUrl = details.getServiceUrl();
request.setQueryString("other=value");
assertEquals(UrlUtils.buildFullRequestUrl(request),serviceUrl);
}
@Test
public void getServiceUrlTicketMiddleMultiParam() {
public void getServiceUrlTicketMiddleMultiParam() throws Exception {
request.setQueryString("other=value&ticket=123&last=this");
details = new DefaultServiceAuthenticationDetails(request,artifactPattern);
details = new DefaultServiceAuthenticationDetails(casServiceUrl,request,artifactPattern);
String serviceUrl = details.getServiceUrl();
request.setQueryString("other=value&last=this");
assertEquals(UrlUtils.buildFullRequestUrl(request),serviceUrl);
}
@Test
public void getServiceUrlDoesNotUseHostHeader() throws Exception {
casServiceUrl = "https://example.com/j_spring_security_cas";
request.setServerName("evil.com");
details = new DefaultServiceAuthenticationDetails(casServiceUrl, request,artifactPattern);
assertEquals("https://example.com/cas-sample/secure/",details.getServiceUrl());
}
@Test
public void getServiceUrlDoesNotUseHostHeaderExplicit() {
casServiceUrl = "https://example.com/j_spring_security_cas";
request.setServerName("evil.com");
ServiceAuthenticationDetails details = loadServiceAuthenticationDetails("defaultserviceauthenticationdetails-explicit.xml");
assertEquals("https://example.com/cas-sample/secure/", details.getServiceUrl());
}
private ServiceAuthenticationDetails loadServiceAuthenticationDetails(String resourceName) {
context = new GenericXmlApplicationContext(getClass(), resourceName);
ServiceAuthenticationDetailsSource source = context.getBean(ServiceAuthenticationDetailsSource.class);
return source.buildDetails(request);
}
}
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://example.com/j_spring_security_cas"/>
<property name="sendRenew" value="false"/>
</bean>
<bean id="serviceProperties2"
class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://example2.com/j_spring_security_cas"/>
<property name="sendRenew" value="false"/>
</bean>
<bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource">
<constructor-arg ref="serviceProperties"/>
</bean>
</beans>
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://example.com/j_spring_security_cas"/>
<property name="sendRenew" value="false"/>
</bean>
<bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource"/>
</beans>
-23
View File
@@ -1,23 +0,0 @@
Implementation-Title: org.springframework.security.cas
Implementation-Version: ${version}
Bundle-SymbolicName: org.springframework.security.cas
Bundle-Name: Spring Security CAS
Bundle-Vendor: SpringSource
Bundle-Version: ${version}
Bundle-ManifestVersion: 2
Ignored-Existing-Headers:
Import-Package,
Export-Package
Import-Template:
org.apache.commons.logging.*;version="${cloggingRange}",
org.jasig.cas.client.*;version="${casRange}",
org.springframework.security.core.*;version="${secRange}",
org.springframework.security.authentication.*;version="${secRange}",
org.springframework.security.web.*;version="${secRange}",
org.springframework.beans.factory;version="${springRange}",
org.springframework.cache.*;version="${springRange}";resolution:=optional,
org.springframework.context.*;version="${springRange}",
org.springframework.dao;version="${springRange}",
org.springframework.util;version="${springRange}",
net.sf.ehcache.*;version="${ehcacheRange}";resolution:=optional,
javax.servlet.*;version="0"
+15 -10
View File
@@ -10,6 +10,7 @@ compileTestJava.dependsOn(':spring-security-core:compileTestJava')
dependencies {
// NB: Don't add other compile time dependencies to the config module as this breaks tooling
compile project(':spring-security-core'),
springCoreDependency,
'aopalliance:aopalliance:1.0',
"org.springframework:spring-aop:$springVersion",
"org.springframework:spring-context:$springVersion",
@@ -18,26 +19,27 @@ dependencies {
optional project(':spring-security-web'),
project(':spring-security-ldap'),
project(':spring-security-openid'),
"org.springframework:spring-web:$springVersion",
project(':spring-security-messaging'),
"org.springframework:spring-web:$springVersion",
"org.springframework:spring-websocket:$springVersion",
"org.springframework:spring-webmvc:$springVersion",
"org.aspectj:aspectjweaver:$aspectjVersion",
"org.springframework:spring-jdbc:$springVersion",
"org.springframework:spring-tx:$springVersion"
provided "org.apache.tomcat:tomcat-servlet-api:$servletApiVersion"
provided "javax.servlet:javax.servlet-api:$servletApiVersion"
testCompile project(':spring-security-cas'),
project(':spring-security-core').sourceSets.test.output,
project(':spring-security-aspects'),
'javax.annotation:jsr250-api:1.0',
"org.springframework.ldap:spring-ldap-core:$springLdapVersion",
"org.springframework:spring-expression:$springVersion",
"org.springframework:spring-jdbc:$springVersion",
"org.springframework:spring-orm:$springVersion",
"org.springframework:spring-tx:$springVersion",
"org.spockframework:spock-core:$spockVersion",
"org.spockframework:spock-spring:$spockVersion",
"org.slf4j:jcl-over-slf4j:$slf4jVersion",
"org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final",
"org.eclipse.persistence:javax.persistence:2.0.5",
"org.hibernate:hibernate-entitymanager:4.1.0.Final",
"org.codehaus.groovy:groovy-all:$groovyVersion",
"org.apache.directory.server:apacheds-core:$apacheDsVersion",
@@ -48,16 +50,19 @@ dependencies {
'org.apache.directory.shared:shared-ldap:0.9.15',
'ldapsdk:ldapsdk:4.1',
powerMockDependencies,
"org.springframework.data:spring-data-jpa:1.2.0.RELEASE",
"org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.0.Final",
"org.hibernate:hibernate-entitymanager:3.6.10.Final",
"org.hsqldb:hsqldb:2.2.8"
"org.hsqldb:hsqldb:$hsqlVersion",
spockDependencies
testCompile('org.openid4java:openid4java-nodeps:0.9.6') {
exclude group: 'com.google.code.guice', module: 'guice'
exclude group: 'com.google.code.guice', module: 'guice'
}
testCompile("org.springframework.data:spring-data-jpa:$springDataJpaVersion") {
exclude group: 'org.aspectj', module: 'aspectjrt'
}
testRuntime "org.hsqldb:hsqldb:$hsqlVersion",
"cglib:cglib-nodep:2.2"
"cglib:cglib-nodep:$cglibVersion"
}
test {
+97 -66
View File
@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>3.2.1.CI-SNAPSHOT</version>
<version>4.0.0.RC1</version>
<name>spring-security-config</name>
<description>spring-security-config</description>
<url>http://spring.io/spring-security</url>
@@ -31,21 +30,10 @@
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>https://repo.spring.io/snapshot</url>
<id>spring-milestone</id>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
<dependencies>
@@ -58,31 +46,31 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.2.1.CI-SNAPSHOT</version>
<version>4.0.0.RC1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -94,82 +82,96 @@
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
<version>1.2</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.10</version>
<version>1.8.4</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
<version>3.2.1.CI-SNAPSHOT</version>
<version>4.0.0.RC1</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-messaging</artifactId>
<version>4.0.0.RC1</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-openid</artifactId>
<version>3.2.1.CI-SNAPSHOT</version>
<version>4.0.0.RC1</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.2.1.CI-SNAPSHOT</version>
<version>4.0.0.RC1</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
<version>7.0.33</version>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>4.1.3.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
<version>3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.29</version>
<version>1.1.2</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -181,7 +183,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -229,7 +231,7 @@
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.0.5</version>
<version>2.3.8</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -239,15 +241,9 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.0.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.1.Final</version>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>2.0.5</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -265,13 +261,7 @@
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.2.8</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.3.1</version>
<version>2.3.2</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -295,43 +285,49 @@
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.5.1</version>
<version>1.6.0</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>mockito-all</artifactId>
<groupId>org.mockito</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-support</artifactId>
<version>1.5.1</version>
<version>1.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>1.5.1</version>
<version>1.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.5.1</version>
<version>1.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4-common</artifactId>
<version>1.5.1</version>
<version>1.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-reflect</artifactId>
<version>1.5.1</version>
<version>1.6.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.5</version>
<version>1.7.7</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -339,48 +335,83 @@
<artifactId>spock-core</artifactId>
<version>0.7-groovy-2.0</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>junit-dep</artifactId>
<groupId>junit</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>0.7-groovy-2.0</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>junit-dep</artifactId>
<groupId>junit</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.2.0.RELEASE</version>
<version>1.7.1.RELEASE</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>aspectjrt</artifactId>
<groupId>org.aspectj</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap-core</artifactId>
<version>1.3.2.RELEASE</version>
<version>2.0.2.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-aspects</artifactId>
<version>4.0.0.RC1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
<version>3.2.1.CI-SNAPSHOT</version>
<version>4.0.0.RC1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.8.RELEASE</version>
<version>4.1.3.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -15,10 +15,12 @@
*/
package org.springframework.security.config.annotation.authentication.ldap
import org.springframework.beans.factory.config.AutowireCapableBeanFactory
import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Import
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.security.authentication.AuthenticationManager
@@ -27,7 +29,13 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.SecurityBuilder;
import org.springframework.security.config.annotation.authentication.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication
import org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessor
import org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessorTests
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
import org.springframework.security.ldap.server.ApacheDSContainer;
@@ -57,6 +65,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
}
}
@@ -74,6 +83,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
.groupRoleAttribute("group")
}
}
@@ -92,6 +102,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
.groupSearchFilter("ou=groupName");
}
}
@@ -110,6 +121,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
.rolePrefix("role_")
}
}
@@ -120,7 +132,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
AuthenticationManager auth = context.getBean(AuthenticationManager)
then:
auth
auth.authenticate(new UsernamePasswordAuthenticationToken("admin","password")).authorities.collect { it.authority }.sort() == ["ROLE_ADMIN","ROLE_USER"]
auth.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword")).authorities.collect { it.authority }.sort() == ["ROLE_DEVELOPERS"]
}
@Configuration
@@ -130,6 +142,29 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
.ldapAuthentication()
.contextSource(contextSource())
.groupSearchBase("ou=groups")
.groupSearchFilter("(member={0})")
.userDnPatterns("uid={0},ou=people");
}
}
def "SEC-2472: Can use crypto PasswordEncoder"() {
setup:
loadConfig(PasswordEncoderConfig)
when:
AuthenticationManager auth = context.getBean(AuthenticationManager)
then:
auth.authenticate(new UsernamePasswordAuthenticationToken("bcrypt","password")).authorities.collect { it.authority }.sort() == ["ROLE_DEVELOPERS"]
}
@Configuration
static class PasswordEncoderConfig extends BaseLdapServerConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.passwordEncoder(new BCryptPasswordEncoder())
.groupSearchBase("ou=groups")
.groupSearchFilter("(member={0})")
.userDnPatterns("uid={0},ou=people");
}
}
@@ -142,23 +177,44 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
static abstract class BaseLdapServerConfig extends BaseLdapProviderConfig {
@Bean
public ApacheDSContainer ldapServer() throws Exception {
ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/users.ldif");
apacheDSContainer.setPort(33389);
ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
apacheDSContainer.setPort(getPort());
return apacheDSContainer;
}
}
@Configuration
@EnableGlobalAuthentication
@Import(ObjectPostProcessorConfiguration)
static abstract class BaseLdapProviderConfig {
@Bean
public BaseLdapPathContextSource contextSource() throws Exception {
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(
"ldap://127.0.0.1:33389/dc=springframework,dc=org")
"ldap://127.0.0.1:"+ getPort() + "/dc=springframework,dc=org")
contextSource.userDn = "uid=admin,ou=system"
contextSource.password = "secret"
contextSource.afterPropertiesSet();
contextSource.afterPropertiesSet()
return contextSource;
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth) {
configure(auth)
auth.build()
}
abstract protected void configure(AuthenticationManagerBuilder auth) throws Exception
}
static Integer port;
static int getPort() {
if(port == null) {
ServerSocket socket = new ServerSocket(0)
port = socket.localPort
socket.close()
}
port
}
}
@@ -0,0 +1,60 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication.ldap
import org.springframework.context.annotation.Configuration
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.authentication.ldap.NamespaceLdapAuthenticationProviderTestsConfigs.LdapAuthenticationProviderConfig
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider
import org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator
import org.springframework.security.ldap.userdetails.PersonContextMapper
import org.springframework.test.util.ReflectionTestUtils
import static org.springframework.security.config.annotation.authentication.ldap.NamespaceLdapAuthenticationProviderTestsConfigs.*
/**
*
* @author Rob Winch
*
*/
class LdapAuthenticationProviderConfigurerTests extends BaseSpringSpec {
def "authentication-manager support multiple default ldap contexts (ports dynamically allocated)"() {
when:
loadConfig(MultiLdapAuthenticationProvidersConfig)
then:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
}
@EnableWebSecurity
static class MultiLdapAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.groupSearchBase("ou=groups")
.userDnPatterns("uid={0},ou=people")
.and()
.ldapAuthentication()
.groupSearchBase("ou=groups")
.userDnPatterns("uid={0},ou=people")
}
}
}
@@ -40,7 +40,7 @@ class NamespaceLdapAuthenticationProviderTests extends BaseSpringSpec {
when:
loadConfig(LdapAuthenticationProviderConfig)
then:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password")).authorities*.authority.sort() == ['ROLE_USER']
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
}
def "ldap-authentication-provider custom"() {
@@ -75,6 +75,6 @@ class NamespaceLdapAuthenticationProviderTests extends BaseSpringSpec {
LdapAuthenticationProvider provider = findAuthenticationProvider(LdapAuthenticationProvider)
then:
provider.authenticator instanceof PasswordComparisonAuthenticator
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password")).authorities*.authority.sort() == ['ROLE_USER']
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
}
}
@@ -1,7 +1,13 @@
package org.springframework.security.config.ldap
import static org.mockito.Mockito.*
import java.text.MessageFormat
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.security.config.AbstractXmlConfigTests
import org.springframework.security.config.BeanIds
import org.springframework.security.util.FieldUtils
@@ -36,7 +42,7 @@ class LdapProviderBeanDefinitionParserTests extends AbstractXmlConfigTests {
def simpleProviderAuthenticatesCorrectly() {
xml.'ldap-server'()
xml.'ldap-server'(ldif:'test-server.ldif')
xml.'authentication-manager'{
'ldap-authentication-provider'('group-search-filter':'member={0}')
}
@@ -66,7 +72,7 @@ class LdapProviderBeanDefinitionParserTests extends AbstractXmlConfigTests {
}
def supportsPasswordComparisonAuthentication() {
xml.'ldap-server'()
xml.'ldap-server'(ldif:'test-server.ldif')
xml.'authentication-manager'{
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people')
'password-compare'
@@ -83,7 +89,7 @@ class LdapProviderBeanDefinitionParserTests extends AbstractXmlConfigTests {
}
def supportsPasswordComparisonAuthenticationWithHashAttribute() {
xml.'ldap-server'()
xml.'ldap-server'(ldif:'test-server.ldif')
xml.'authentication-manager'{
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
'password-compare'('password-attribute': 'uid', hash: 'plaintext')
@@ -102,7 +108,7 @@ class LdapProviderBeanDefinitionParserTests extends AbstractXmlConfigTests {
}
def supportsPasswordComparisonAuthenticationWithPasswordEncoder() {
xml.'ldap-server'()
xml.'ldap-server'(ldif:'test-server.ldif')
xml.'authentication-manager'{
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
'password-compare'('password-attribute': 'uid') {
@@ -122,6 +128,28 @@ class LdapProviderBeanDefinitionParserTests extends AbstractXmlConfigTests {
notThrown(AuthenticationException)
}
def 'SEC-2472: Supports Crypto PasswordEncoder'() {
setup:
xml.'ldap-server'(ldif:'test-server.ldif')
xml.'authentication-manager'{
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
'password-compare'() {
'password-encoder'(ref: 'pe')
}
}
}
xml.'b:bean'(id:'pe','class':BCryptPasswordEncoder.class.name)
createAppContext('')
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
when:
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("bcrypt", 'password'))
then:
auth != null
}
def inetOrgContextMapperIsSupported() {
xml.'ldap-server'(url: 'ldap://127.0.0.1:343/dc=springframework,dc=org')
xml.'authentication-manager'{
@@ -28,8 +28,6 @@ import org.springframework.security.ldap.userdetails.PersonContextMapper;
*
*/
public class NamespaceLdapAuthenticationProviderTestsConfigs {
@Configuration
@EnableWebSecurity
static class LdapAuthenticationProviderConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
@@ -40,7 +38,6 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
}
}
@Configuration
@EnableWebSecurity
static class CustomLdapAuthenticationProviderConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
@@ -56,7 +53,7 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
.userSearchFilter("(uid={0})") // ldap-authentication-provider@user-search-filter
// .contextSource(contextSource) // ldap-authentication-provider@server-ref
.contextSource()
.ldif("classpath:user.ldif") // ldap-server@ldif
.ldif("classpath:users.xldif") // ldap-server@ldif
.managerDn("uid=admin,ou=system") // ldap-server@manager-dn
.managerPassword("secret") // ldap-server@manager-password
.port(33399) // ldap-server@port
@@ -66,7 +63,6 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
}
}
@Configuration
@EnableWebSecurity
static class CustomAuthoritiesPopulatorConfig extends WebSecurityConfigurerAdapter {
static LdapAuthoritiesPopulator LAP;
@@ -78,7 +74,6 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
}
}
@Configuration
@EnableWebSecurity
static class PasswordCompareLdapConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
@@ -28,6 +28,16 @@ sn: Alex
uid: ben
userPassword: {SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=
dn: uid=bcrypt,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: BCrypt user
sn: BCrypt
uid: bcrypt
userPassword: $2a$10$FBAKClV1zBIOOC9XMXf3AO8RoGXYVYsfvUdoLxGkd/BnXEn4tqT3u
dn: uid=bob,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
@@ -58,11 +68,22 @@ sn: Mouse
uid: jerry
userPassword: jerryspassword
dn: uid=bcrypt,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: BCrypt user
sn: BCrypt
uid: bcrypt
userPassword: $2a$10$lDa0YFNHAt63MjIzK/wUqeM0qjIhzPhp3RNI/MLUQEAUbzhB/SnnS
dn: cn=developers,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfNames
cn: developers
ou: developer
member: uid=bcrypt,ou=people,dc=springframework,dc=org
member: uid=ben,ou=people,dc=springframework,dc=org
member: uid=bob,ou=people,dc=springframework,dc=org
@@ -1,42 +0,0 @@
dn: ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: groups
dn: ou=people,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: people
dn: uid=admin,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Rod Johnson
sn: Johnson
uid: admin
userPassword: password
dn: uid=user,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Dianne Emu
sn: Emu
uid: user
userPassword: password
dn: cn=user,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfNames
cn: user
uniqueMember: uid=admin,ou=people,dc=springframework,dc=org
uniqueMember: uid=user,ou=people,dc=springframework,dc=org
dn: cn=admin,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfNames
cn: admin
uniqueMember: uid=admin,ou=people,dc=springframework,dc=org
@@ -0,0 +1,92 @@
dn: ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: groups
dn: ou=subgroups,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: subgroups
dn: ou=people,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: people
dn: ou=otherpeople,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: otherpeople
dn: uid=ben,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Ben Alex
sn: Alex
uid: ben
userPassword: {SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=
dn: uid=bcrypt,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: BCrypt user
sn: BCrypt
uid: bcrypt
userPassword: $2a$10$lDa0YFNHAt63MjIzK/wUqeM0qjIhzPhp3RNI/MLUQEAUbzhB/SnnS
dn: uid=bob,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Bob Hamilton
sn: Hamilton
uid: bob
userPassword: bobspassword
dn: uid=joe,ou=otherpeople,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Joe Smeth
sn: Smeth
uid: joe
userPassword: joespassword
dn: cn=mouse\, jerry,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Mouse, Jerry
sn: Mouse
uid: jerry
userPassword: jerryspassword
dn: cn=developers,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfNames
cn: developers
ou: developer
member: uid=ben,ou=people,dc=springframework,dc=org
member: uid=bob,ou=people,dc=springframework,dc=org
dn: cn=managers,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfNames
cn: managers
ou: manager
member: uid=ben,ou=people,dc=springframework,dc=org
member: cn=mouse\, jerry,ou=people,dc=springframework,dc=org
dn: cn=submanagers,ou=subgroups,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfNames
cn: submanagers
ou: submanager
member: uid=ben,ou=people,dc=springframework,dc=org
@@ -49,11 +49,12 @@ public abstract class Elements {
public static final String JEE = "jee";
public static final String FILTER_SECURITY_METADATA_SOURCE = "filter-security-metadata-source";
public static final String METHOD_SECURITY_METADATA_SOURCE = "method-security-metadata-source";
@Deprecated
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
public static final String DEBUG = "debug";
public static final String HTTP_FIREWALL = "http-firewall";
public static final String HEADERS = "headers";
public static final String CSRF = "csrf";
public static final String MESSAGES = "messages";
public static final String INTERCEPT_MESSAGE = "message-interceptor";
}
@@ -38,6 +38,7 @@ import org.springframework.security.config.http.HttpSecurityBeanDefinitionParser
import org.springframework.security.config.ldap.LdapProviderBeanDefinitionParser;
import org.springframework.security.config.ldap.LdapServerBeanDefinitionParser;
import org.springframework.security.config.ldap.LdapUserServiceBeanDefinitionParser;
import org.springframework.security.config.message.MessageSecurityBeanDefinitionParser;
import org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParser;
import org.springframework.security.config.method.InterceptMethodsBeanDefinitionDecorator;
import org.springframework.security.config.method.MethodSecurityMetadataSourceBeanDefinitionParser;
@@ -56,6 +57,7 @@ import org.w3c.dom.Node;
*/
public final class SecurityNamespaceHandler implements NamespaceHandler {
private static final String FILTER_CHAIN_PROXY_CLASSNAME = "org.springframework.security.web.FilterChainProxy";
private static final String MESSAGE_CLASSNAME = "org.springframework.messaging.Message";
private final Log logger = LogFactory.getLog(getClass());
private final Map<String, BeanDefinitionParser> parsers = new HashMap<String, BeanDefinitionParser>();
private final BeanDefinitionDecorator interceptMethodsBDD = new InterceptMethodsBeanDefinitionDecorator();
@@ -171,11 +173,14 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
parsers.put(Elements.DEBUG, new DebugBeanDefinitionParser());
parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
parsers.put(Elements.HTTP_FIREWALL, new HttpFirewallBeanDefinitionParser());
parsers.put(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
parsers.put(Elements.FILTER_CHAIN, new FilterChainBeanDefinitionParser());
filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
}
if(ClassUtils.isPresent(MESSAGE_CLASSNAME, getClass().getClassLoader())) {
parsers.put(Elements.MESSAGES, new MessageSecurityBeanDefinitionParser());
}
}
/**
@@ -196,7 +201,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
private boolean matchesVersionInternal(Element element) {
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
return schemaLocation.matches("(?m).*spring-security-3\\.2.*.xsd.*")
return schemaLocation.matches("(?m).*spring-security-4\\.0.*.xsd.*")
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|| !schemaLocation.matches("(?m).*spring-security.*");
}
@@ -29,8 +29,6 @@ import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.util.Assert;
import org.springframework.web.filter.DelegatingFilterProxy;
import com.google.inject.internal.ImmutableList.Builder;
/**
* <p>A base {@link SecurityBuilder} that allows {@link SecurityConfigurer} to be
* applied to it. This makes modifying the {@link SecurityBuilder} a strategy
@@ -78,6 +78,9 @@ public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuil
*/
public AuthenticationManagerBuilder parentAuthenticationManager(
AuthenticationManager authenticationManager) {
if(authenticationManager instanceof ProviderManager) {
eraseCredentials(((ProviderManager) authenticationManager).isEraseCredentialsAfterAuthentication());
}
this.parentAuthenticationManager = authenticationManager;
return this;
}
@@ -135,19 +138,31 @@ public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuil
/**
* Add JDBC authentication to the {@link AuthenticationManagerBuilder} and
* return a {@link JdbcUserDetailsManagerConfigurer} to allow customization of the
* JDBC authentication.
* return a {@link JdbcUserDetailsManagerConfigurer} to allow customization
* of the JDBC authentication.
*
* <p>
* When using with a persistent data store, it is best to add users external
* of configuration using something like <a
* href="http://flywaydb.org/">Flyway</a> or <a
* href="http://www.liquibase.org/">Liquibase</a> to create the schema and
* adding users to ensure these steps are only done once and that the
* optimal SQL is used.
* </p>
*
* <p>
* This method also ensure that a {@link UserDetailsService} is available
* for the {@link #getDefaultUserDetailsService()} method. Note that
* additional {@link UserDetailsService}'s may override this
* {@link UserDetailsService} as the default.
* {@link UserDetailsService} as the default. See the <a href=
* "http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#user-schema"
* >User Schema</a> section of the reference for the default schema.
* </p>
*
* @return a {@link JdbcUserDetailsManagerConfigurer} to allow customization of the
* JDBC authentication
* @throws Exception if an error occurs when adding the JDBC authentication
* @return a {@link JdbcUserDetailsManagerConfigurer} to allow customization
* of the JDBC authentication
* @throws Exception
* if an error occurs when adding the JDBC authentication
*/
public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication()
throws Exception {
@@ -113,8 +113,8 @@ public class AuthenticationConfiguration {
lazyTargetSource.setTargetBeanName(beanNamesForType[0]);
lazyTargetSource.setBeanFactory(applicationContext);
ProxyFactoryBean proxyFactory = new ProxyFactoryBean();
proxyFactory = objectPostProcessor.postProcess(proxyFactory);
proxyFactory.setTargetSource(lazyTargetSource);
proxyFactory.setInterfaces(new Class[] { interfaceName });
return (T) proxyFactory.getObject();
}
@@ -122,7 +122,6 @@ public class AuthenticationConfiguration {
return lazyBean(AuthenticationManager.class);
}
private static class EnableGlobalAuthenticationAutowiredConfigurer extends GlobalAuthenticationConfigurerAdapter {
private final ApplicationContext context;
private static final Log logger = LogFactory.getLog(EnableGlobalAuthenticationAutowiredConfigurer.class);
@@ -19,6 +19,7 @@ import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
@@ -88,4 +89,5 @@ import org.springframework.security.config.annotation.web.servlet.configuration.
@Target(value={java.lang.annotation.ElementType.TYPE})
@Documented
@Import(AuthenticationConfiguration.class)
@Configuration
public @interface EnableGlobalAuthentication {}
@@ -40,6 +40,10 @@ import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper;
import org.springframework.security.ldap.userdetails.PersonContextMapper;
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper;
import org.springframework.util.Assert;
import java.io.IOException;
import java.net.ServerSocket;
/**
* Configures LDAP {@link AuthenticationProvider} in the {@link ProviderManagerBuilder}.
@@ -60,7 +64,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
private BaseLdapPathContextSource contextSource;
private ContextSourceBuilder contextSourceBuilder = new ContextSourceBuilder();
private UserDetailsContextMapper userDetailsContextMapper;
private PasswordEncoder passwordEncoder;
private Object passwordEncoder;
private String passwordAttribute;
private LdapAuthoritiesPopulator ldapAuthoritiesPopulator;
@@ -149,7 +153,9 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
*/
private PasswordComparisonAuthenticator createPasswordCompareAuthenticator(BaseLdapPathContextSource contextSource) {
PasswordComparisonAuthenticator ldapAuthenticator = new PasswordComparisonAuthenticator(contextSource);
ldapAuthenticator.setPasswordAttributeName(passwordAttribute);
if(passwordAttribute != null) {
ldapAuthenticator.setPasswordAttributeName(passwordAttribute);
}
ldapAuthenticator.setPasswordEncoder(passwordEncoder);
return ldapAuthenticator;
}
@@ -204,12 +210,26 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
*
* @param passwordEncoder the {@link PasswordEncoder} to use
* @return the {@link LdapAuthenticationProviderConfigurer} for further customization
* @deprecated Use {@link #passwordEncoder(org.springframework.security.crypto.password.PasswordEncoder)} instead
*/
public LdapAuthenticationProviderConfigurer<B> passwordEncoder(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
return this;
}
/**
* Specifies the {@link org.springframework.security.crypto.password.PasswordEncoder} to be used when authenticating with
* password comparison.
*
* @param passwordEncoder the {@link org.springframework.security.crypto.password.PasswordEncoder} to use
* @return the {@link LdapAuthenticationProviderConfigurer} for further customization
*/
public LdapAuthenticationProviderConfigurer<B> passwordEncoder(final org.springframework.security.crypto.password.PasswordEncoder passwordEncoder) {
Assert.notNull(passwordEncoder, "passwordEncoder must not be null.");
this.passwordEncoder = passwordEncoder;
return this;
}
/**
* If your users are at a fixed location in the directory (i.e. you can work
* out the DN directly from the username without doing a directory search),
@@ -373,7 +393,8 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
private String ldif = "classpath*:*.ldif";
private String managerPassword;
private String managerDn;
private int port = 33389;
private Integer port;
private static final int DEFAULT_PORT = 33389;
private String root = "dc=springframework,dc=org";
private String url;
@@ -418,7 +439,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
}
/**
* The port to connect to LDAP to (the default is 33389).
* The port to connect to LDAP to (the default is 33389 or random available port if unavailable).
* @param port the port to connect to
* @return the {@link ContextSourceBuilder} for further customization
*/
@@ -478,14 +499,43 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
return contextSource;
}
ApacheDSContainer apacheDsContainer = new ApacheDSContainer(root, ldif);
apacheDsContainer.setPort(port);
apacheDsContainer.setPort(getPort());
postProcess(apacheDsContainer);
return contextSource;
}
private int getPort() {
if(port == null) {
port = getDefaultPort();
}
return port;
}
private int getDefaultPort() {
ServerSocket serverSocket = null;
try {
try {
serverSocket = new ServerSocket(DEFAULT_PORT);
} catch (IOException e) {
try {
serverSocket = new ServerSocket(0);
} catch(IOException e2) {
return DEFAULT_PORT;
}
}
return serverSocket.getLocalPort();
} finally {
if(serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {}
}
}
}
private String getProviderUrl() {
if(url == null) {
return "ldap://127.0.0.1:" + port + "/" + root;
return "ldap://127.0.0.1:" + getPort() + "/" + root;
}
return url;
}
@@ -62,6 +62,7 @@ final class AutowireBeanFactoryObjectPostProcessor implements ObjectPostProcesso
Class<?> type = object.getClass();
throw new RuntimeException("Could not postProcess " + object + " of type " + type, e);
}
autowireBeanFactory.autowireBean(object);
if(result instanceof DisposableBean) {
disposableBeans.add((DisposableBean) result);
}
@@ -20,6 +20,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.Ordered;
import org.springframework.security.access.annotation.Secured;
@@ -46,6 +47,7 @@ import org.springframework.security.config.annotation.configuration.ObjectPostPr
@Documented
@Import({GlobalMethodSecuritySelector.class,ObjectPostProcessorConfiguration.class})
@EnableGlobalAuthentication
@Configuration
public @interface EnableGlobalMethodSecurity {
/**
@@ -18,6 +18,8 @@ package org.springframework.security.config.annotation.method.configuration;
import java.util.Map;
import org.springframework.aop.config.AopConfigUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
@@ -50,18 +52,15 @@ class GlobalMethodSecurityAspectJAutoProxyRegistrar implements
AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
AopConfigUtils
.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
BeanDefinition interceptor = registry.getBeanDefinition("methodSecurityInterceptor");
Map<String, Object> annotationAttributes = importingClassMetadata
.getAnnotationAttributes(EnableGlobalMethodSecurity.class
.getName());
AnnotationAttributes enableAJAutoProxy = AnnotationAttributes
.fromMap(annotationAttributes);
BeanDefinitionBuilder aspect =
BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect");
aspect.setFactoryMethod("aspectOf");
aspect.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
aspect.addPropertyValue("securityInterceptor", interceptor);
if (enableAJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
registry.registerBeanDefinition("annotationSecurityAspect$0", aspect.getBeanDefinition());
}
}
@@ -24,10 +24,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.context.annotation.Role;
import org.springframework.context.annotation.*;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.type.AnnotationMetadata;
@@ -48,6 +45,7 @@ import org.springframework.security.access.intercept.AfterInvocationProviderMana
import org.springframework.security.access.intercept.RunAsManager;
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource;
import org.springframework.security.access.method.MethodSecurityMetadataSource;
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
@@ -111,7 +109,7 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
*/
@Bean
public MethodInterceptor methodSecurityInterceptor() throws Exception {
MethodSecurityInterceptor methodSecurityInterceptor = new MethodSecurityInterceptor();
MethodSecurityInterceptor methodSecurityInterceptor = isAspectJ() ? new AspectJMethodSecurityInterceptor() : new MethodSecurityInterceptor();
methodSecurityInterceptor
.setAccessDecisionManager(accessDecisionManager());
methodSecurityInterceptor
@@ -175,7 +173,7 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
*/
@SuppressWarnings("rawtypes")
protected AccessDecisionManager accessDecisionManager() {
List<AccessDecisionVoter> decisionVoters = new ArrayList<AccessDecisionVoter>();
List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList<AccessDecisionVoter<? extends Object>>();
ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
expressionAdvice.setExpressionHandler(getExpressionHandler());
if(prePostEnabled()) {
@@ -379,6 +377,10 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
return (Integer) enableMethodSecurity().get("order");
}
private boolean isAspectJ() {
return enableMethodSecurity().getEnum("mode") == AdviceMode.ASPECTJ;
}
private AnnotationAttributes enableMethodSecurity() {
if (enableMethodSecurity == null) {
// if it is null look at this instance (i.e. a subclass was used)
@@ -41,10 +41,6 @@ public abstract class AbstractRequestMatcherRegistry<C> {
/**
* Maps any request.
*
* @param method the {@link HttpMethod} to use or {@code null} for any {@link HttpMethod}.
* @param antPatterns the ant patterns to create {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher}
* from
*
* @return the object that is chained after creating the {@link RequestMatcher}
*/
public C anyRequest() {
@@ -181,7 +177,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
/**
* Create a {@link List} of {@link RegexRequestMatcher} instances that do not specify an {@link HttpMethod}.
*
* @param regexPatterns the regular expressions to create {@link RegexRequestMatcher} from
* @param regexPatterns the regular expressions to create {@link RegexRequestMatcher} from
*
* @return a {@link List} of {@link RegexRequestMatcher} instances
*/
@@ -948,8 +948,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* .antMatchers(&quot;/**&quot;).hasRole(&quot;USER&quot;)
* .and()
* .formLogin()
* .usernameParameter("j_username") // default is username
* .passwordParameter("j_password") // default is password
* .usernameParameter("username") // default is username
* .passwordParameter("password") // default is password
* .loginPage("/authentication/login") // default is /login with an HTTP get
* .failureUrl("/authentication/login?failed") // default is /login?error
* .loginProcessingUrl("/authentication/login/process"); // default is /login with an HTTP post
@@ -1000,7 +1000,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* .and()
* .formLogin()
* .and()
* .channelSecurity()
* .requiresChannel()
* .anyRequest().requiresSecure();
* }
*
@@ -0,0 +1,13 @@
package org.springframework.security.config.annotation.web.configuration;
import org.springframework.context.annotation.Conditional;
/**
* @author Rob Winch
* @since 4.0
*/
@Conditional(OnMissingBeanCondition.class)
@interface ConditionalOnMissingBean {
Class<?> value();
}
@@ -19,6 +19,7 @@ import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
@@ -77,8 +78,9 @@ import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value={java.lang.annotation.ElementType.TYPE})
@Documented
@Import({WebSecurityConfiguration.class,ObjectPostProcessorConfiguration.class})
@Import({WebSecurityConfiguration.class,ObjectPostProcessorConfiguration.class, SpringWebMvcImportSelector.class})
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
/**
@@ -0,0 +1,42 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.springframework.security.config.annotation.web.configuration;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.ConfigurationCondition;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.ClassUtils;
import java.util.Map;
/**
* @author Rob Winch
*/
class OnMissingBeanCondition implements ConfigurationCondition {
@Override
public ConfigurationPhase getConfigurationPhase() {
return ConfigurationPhase.REGISTER_BEAN;
}
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String,Object> attrs = metadata.getAnnotationAttributes(ConditionalOnMissingBean.class.getName());
Class<?> type = (Class) attrs.get("value");
final Map<String, ?> beans = context.getBeanFactory().getBeansOfType(type);
return beans.isEmpty();
}
}
@@ -0,0 +1,39 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;
/**
* Used by {@link EnableWebSecurity} to conditionaly import
* {@link WebMvcSecurityConfiguration} when the DispatcherServlet is present on the
* classpath.
*
* @author Rob Winch
* @since 3.2
*/
class SpringWebMvcImportSelector implements ImportSelector {
/* (non-Javadoc)
* @see org.springframework.context.annotation.ImportSelector#selectImports(org.springframework.core.type.AnnotationMetadata)
*/
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
boolean webmvcPresent = ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", getClass().getClassLoader());
return webmvcPresent ? new String[] {"org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration"} : new String[] {};
}
}
@@ -0,0 +1,54 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver;
import org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.support.RequestDataValueProcessor;
import java.util.List;
/**
* Used to add a {@link RequestDataValueProcessor} for Spring MVC and Spring
* Security CSRF integration. This configuration is added whenever
* {@link EnableWebMvc} is added by {@link SpringWebMvcImportSelector} and the
* DispatcherServlet is present on the classpath. It also adds the
* {@link AuthenticationPrincipalArgumentResolver} as a
* {@link HandlerMethodArgumentResolver}.
*
* @author Rob Winch
* @since 3.2
*/
class WebMvcSecurityConfiguration extends WebMvcConfigurerAdapter {
@Override
@SuppressWarnings("deprecation")
public void addArgumentResolvers(
List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new AuthenticationPrincipalArgumentResolver());
argumentResolvers.add(new org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver());
}
@ConditionalOnMissingBean(RequestDataValueProcessor.class)
@Bean
public RequestDataValueProcessor requestDataValueProcessor() {
return new CsrfRequestDataValueProcessor();
}
}
@@ -38,8 +38,10 @@ import org.springframework.core.type.AnnotationMetadata;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.context.DelegatingApplicationListener;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
@@ -72,6 +74,14 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
private ClassLoader beanClassLoader;
@Autowired(required = false)
private ObjectPostProcessor<Object> objectObjectPostProcessor;
@Bean
public static DelegatingApplicationListener delegatingApplicationListener() {
return new DelegatingApplicationListener();
}
@Bean
@DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler() {
@@ -87,7 +97,8 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = webSecurityConfigurers != null && !webSecurityConfigurers.isEmpty();
if(!hasConfigurers) {
throw new IllegalStateException("At least one non-null instance of "+ WebSecurityConfigurer.class.getSimpleName()+" must be exposed as a @Bean when using @EnableWebSecurity. Hint try extending "+ WebSecurityConfigurerAdapter.class.getSimpleName());
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {});
webSecurity.apply(adapter);
}
return webSecurity.build();
}
@@ -16,11 +16,20 @@
package org.springframework.security.config.annotation.web.configuration;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.target.LazyInitTargetSource;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
@@ -44,6 +53,7 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.accept.ContentNegotiationStrategy;
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
@@ -71,8 +81,8 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
private AuthenticationConfiguration authenticationConfiguration;
private AuthenticationManagerBuilder authenticationBuilder;
private AuthenticationManagerBuilder parentAuthenticationBuilder;
private boolean disableAuthenticationRegistration;
private AuthenticationManagerBuilder localConfigureAuthenticationBldr;
private boolean disableLocalConfigureAuthenticationBldr;
private boolean authenticationManagerInitialized;
private AuthenticationManager authenticationManager;
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
@@ -148,7 +158,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
* @throws Exception
*/
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
this.disableAuthenticationRegistration = true;
this.disableLocalConfigureAuthenticationBldr = true;
}
/**
@@ -163,11 +173,11 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
}
DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
parentAuthenticationBuilder.authenticationEventPublisher(eventPublisher);
localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
AuthenticationManager authenticationManager = authenticationManager();
authenticationBuilder.parentAuthenticationManager(authenticationManager);
http = new HttpSecurity(objectPostProcessor,authenticationBuilder, parentAuthenticationBuilder.getSharedObjects());
http = new HttpSecurity(objectPostProcessor,authenticationBuilder, localConfigureAuthenticationBldr.getSharedObjects());
http.setSharedObject(UserDetailsService.class, userDetailsService());
http.setSharedObject(ApplicationContext.class, context);
http.setSharedObject(ContentNegotiationStrategy.class, contentNegotiationStrategy);
@@ -207,7 +217,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
* @throws Exception
*/
public AuthenticationManager authenticationManagerBean() throws Exception {
return new AuthenticationManagerDelegator(authenticationBuilder);
return new AuthenticationManagerDelegator(authenticationBuilder, context);
}
/**
@@ -221,11 +231,11 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
*/
protected AuthenticationManager authenticationManager() throws Exception {
if(!authenticationManagerInitialized) {
configure(parentAuthenticationBuilder);
if(disableAuthenticationRegistration) {
configure(localConfigureAuthenticationBldr);
if(disableLocalConfigureAuthenticationBldr) {
authenticationManager = authenticationConfiguration.getAuthenticationManager();
} else {
authenticationManager = parentAuthenticationBuilder.build();
authenticationManager = localConfigureAuthenticationBldr.build();
}
authenticationManagerInitialized = true;
}
@@ -253,7 +263,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
*/
public UserDetailsService userDetailsServiceBean() throws Exception {
AuthenticationManagerBuilder globalAuthBuilder = context.getBean(AuthenticationManagerBuilder.class);
return new UserDetailsServiceDelegator(Arrays.asList(parentAuthenticationBuilder, globalAuthBuilder));
return new UserDetailsServiceDelegator(Arrays.asList(localConfigureAuthenticationBldr, globalAuthBuilder));
}
/**
@@ -266,7 +276,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
*/
protected UserDetailsService userDetailsService() {
AuthenticationManagerBuilder globalAuthBuilder = context.getBean(AuthenticationManagerBuilder.class);
return new UserDetailsServiceDelegator(Arrays.asList(parentAuthenticationBuilder, globalAuthBuilder));
return new UserDetailsServiceDelegator(Arrays.asList(localConfigureAuthenticationBldr, globalAuthBuilder));
}
public void init(final WebSecurity web) throws Exception {
@@ -337,7 +347,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
this.objectPostProcessor = objectPostProcessor;
authenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor);
parentAuthenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor) {
localConfigureAuthenticationBldr = new AuthenticationManagerBuilder(objectPostProcessor) {
@Override
public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {
authenticationBuilder.eraseCredentials(eraseCredentials);
@@ -410,9 +420,14 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
private AuthenticationManagerBuilder delegateBuilder;
private AuthenticationManager delegate;
private final Object delegateMonitor = new Object();
private Set<String> beanNames;
AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder) {
AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder, ApplicationContext context) {
Assert.notNull(delegateBuilder,"delegateBuilder cannot be null");
Field parentAuthMgrField = ReflectionUtils.findField(AuthenticationManagerBuilder.class, "parentAuthenticationManager");
ReflectionUtils.makeAccessible(parentAuthMgrField);
beanNames = getAuthenticationManagerBeanNames(context);
validateBeanCycle(ReflectionUtils.getField(parentAuthMgrField, delegateBuilder), beanNames);
this.delegateBuilder = delegateBuilder;
}
@@ -430,5 +445,26 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
return delegate.authenticate(authentication);
}
private static Set<String> getAuthenticationManagerBeanNames(ApplicationContext applicationContext) {
String[] beanNamesForType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, AuthenticationManager.class);
return new HashSet<String>(Arrays.asList(beanNamesForType));
}
private static void validateBeanCycle(Object auth, Set<String> beanNames) {
if(auth != null && !beanNames.isEmpty()) {
if(auth instanceof Advised){
Advised advised = (Advised) auth;
TargetSource targetSource = advised.getTargetSource();
if(targetSource instanceof LazyInitTargetSource) {
LazyInitTargetSource lits = (LazyInitTargetSource) targetSource;
if(beanNames.contains(lits.getTargetBeanName())) {
throw new FatalBeanException("A dependency cycle was detected when trying to resolve the AuthenticationManager. Please ensure you have configured authentication.");
}
}
}
beanNames = Collections.emptySet();
}
}
}
}
@@ -103,7 +103,7 @@ abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConf
* default {@link AccessDecisionManager}
*/
@SuppressWarnings("rawtypes")
abstract List<AccessDecisionVoter> getDecisionVoters(H http);
abstract List<AccessDecisionVoter<? extends Object>> getDecisionVoters(H http);
abstract class AbstractInterceptUrlRegistry<R extends AbstractInterceptUrlRegistry<R,T>,T> extends AbstractConfigAttributeRequestMatcherRegistry<T> {
@@ -97,7 +97,7 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>> extends Abst
* @return the {@link CsrfConfigurer} for further customizations
*/
public CsrfConfigurer<H> requireCsrfProtectionMatcher(RequestMatcher requireCsrfProtectionMatcher) {
Assert.notNull(csrfTokenRepository, "requireCsrfProtectionMatcher cannot be null");
Assert.notNull(requireCsrfProtectionMatcher, "requireCsrfProtectionMatcher cannot be null");
this.requireCsrfProtectionMatcher = requireCsrfProtectionMatcher;
return this;
}
@@ -141,8 +141,8 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
@Override
@SuppressWarnings("rawtypes")
final List<AccessDecisionVoter> getDecisionVoters(H http) {
List<AccessDecisionVoter> decisionVoters = new ArrayList<AccessDecisionVoter>();
final List<AccessDecisionVoter<? extends Object>> getDecisionVoters(H http) {
List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList<AccessDecisionVoter<? extends Object>>();
WebExpressionVoter expressionVoter = new WebExpressionVoter();
expressionVoter.setExpressionHandler(getExpressionHandler(http));
decisionVoters.add(expressionVoter);
@@ -213,8 +213,6 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
/**
* Negates the following expression.
*
* @param role the role to require (i.e. USER, ADMIN, etc). Note, it should not start with "ROLE_" as
* this is automatically inserted.
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
*/
public AuthorizedUrl not() {
@@ -294,7 +294,9 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends Ab
}
if(http.getConfigurer(CsrfConfigurer.class) != null) {
this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl, "POST");
} else {
this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl);
}
return new AntPathRequestMatcher(this.logoutUrl);
return this.logoutRequestMatcher;
}
}
@@ -15,7 +15,9 @@
*/
package org.springframework.security.config.annotation.web.configurers;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.http.MediaType;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
@@ -114,12 +116,13 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>> exte
return defaultCache;
}
@SuppressWarnings("unchecked")
private RequestMatcher createDefaultSavedRequestMatcher(H http) {
ContentNegotiationStrategy contentNegotiationStrategy = http.getSharedObject(ContentNegotiationStrategy.class);
if(contentNegotiationStrategy == null) {
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
}
RequestMatcher getRequests = new AntPathRequestMatcher("/**", "GET");
RequestMatcher notFavIcon = new NegatedRequestMatcher(new AntPathRequestMatcher("/**/favicon.ico"));
MediaTypeRequestMatcher jsonRequest = new MediaTypeRequestMatcher(contentNegotiationStrategy, MediaType.APPLICATION_JSON);
@@ -127,6 +130,18 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>> exte
RequestMatcher notJson = new NegatedRequestMatcher(jsonRequest);
RequestMatcher notXRequestedWith = new NegatedRequestMatcher(new RequestHeaderRequestMatcher("X-Requested-With","XMLHttpRequest"));
return new AndRequestMatcher(getRequests, notFavIcon, notJson, notXRequestedWith);
boolean isCsrfEnabled = http.getConfigurer(CsrfConfigurer.class) != null;
List<RequestMatcher> matchers = new ArrayList<RequestMatcher>();
if(isCsrfEnabled) {
RequestMatcher getRequests = new AntPathRequestMatcher("/**", "GET");
matchers.add(0, getRequests);
}
matchers.add(notFavIcon);
matchers.add(notJson);
matchers.add(notXRequestedWith);
return new AndRequestMatcher(matchers);
}
}
@@ -22,10 +22,15 @@ import java.util.List;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.GenericApplicationListenerAdapter;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.context.DelegatingApplicationListener;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
@@ -87,7 +92,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
private SessionAuthenticationStrategy sessionAuthenticationStrategy;
private InvalidSessionStrategy invalidSessionStrategy;
private List<SessionAuthenticationStrategy> sessionAuthenticationStrategies = new ArrayList<SessionAuthenticationStrategy>();
private SessionRegistry sessionRegistry = new SessionRegistryImpl();
private SessionRegistry sessionRegistry;
private Integer maximumSessions;
private String expiredUrl;
private boolean maxSessionsPreventsLogin;
@@ -367,14 +372,14 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
http.setSharedObject(RequestCache.class, new NullRequestCache());
}
}
http.setSharedObject(SessionAuthenticationStrategy.class, getSessionAuthenticationStrategy());
http.setSharedObject(SessionAuthenticationStrategy.class, getSessionAuthenticationStrategy(http));
http.setSharedObject(InvalidSessionStrategy.class, getInvalidSessionStrategy());
}
@Override
public void configure(H http) throws Exception {
SecurityContextRepository securityContextRepository = http.getSharedObject(SecurityContextRepository.class);
SessionManagementFilter sessionManagementFilter = new SessionManagementFilter(securityContextRepository, getSessionAuthenticationStrategy());
SessionManagementFilter sessionManagementFilter = new SessionManagementFilter(securityContextRepository, getSessionAuthenticationStrategy(http));
if(sessionAuthenticationErrorUrl != null) {
sessionManagementFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(sessionAuthenticationErrorUrl));
}
@@ -389,7 +394,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
http.addFilter(sessionManagementFilter);
if(isConcurrentSessionControlEnabled()) {
ConcurrentSessionFilter concurrentSessionFilter = new ConcurrentSessionFilter(sessionRegistry, expiredUrl);
ConcurrentSessionFilter concurrentSessionFilter = new ConcurrentSessionFilter(getSessionRegistry(http), expiredUrl);
concurrentSessionFilter = postProcess(concurrentSessionFilter);
http.addFilter(concurrentSessionFilter);
}
@@ -444,12 +449,13 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
*
* @return the {@link SessionAuthenticationStrategy} to use
*/
private SessionAuthenticationStrategy getSessionAuthenticationStrategy() {
private SessionAuthenticationStrategy getSessionAuthenticationStrategy(H http) {
if(sessionAuthenticationStrategy != null) {
return sessionAuthenticationStrategy;
}
List<SessionAuthenticationStrategy> delegateStrategies = sessionAuthenticationStrategies;
if(isConcurrentSessionControlEnabled()) {
SessionRegistry sessionRegistry = getSessionRegistry(http);
ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlStrategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry);
concurrentSessionControlStrategy.setMaximumSessions(maximumSessions);
concurrentSessionControlStrategy.setExceptionIfMaximumExceeded(maxSessionsPreventsLogin);
@@ -466,6 +472,28 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
return sessionAuthenticationStrategy;
}
private SessionRegistry getSessionRegistry(H http) {
if(sessionRegistry == null) {
SessionRegistryImpl sessionRegistry = new SessionRegistryImpl();
registerDelegateApplicationListener(http, sessionRegistry);
this.sessionRegistry = sessionRegistry;
}
return sessionRegistry;
}
private void registerDelegateApplicationListener(H http, ApplicationListener<?> delegate) {
ApplicationContext context = http.getSharedObject(ApplicationContext.class);
if(context == null) {
return;
}
if(context.getBeansOfType(DelegatingApplicationListener.class).isEmpty()) {
return;
}
DelegatingApplicationListener delegating = context.getBean(DelegatingApplicationListener.class);
SmartApplicationListener smartListener = new GenericApplicationListenerAdapter(delegate);
delegating.addListener(smartListener);
}
/**
* Returns true if the number of concurrent sessions per user should be restricted.
* @return
@@ -81,14 +81,12 @@ import org.springframework.util.Assert;
*
* <ul>
* <li>
* {@link org.springframework.security.config.annotation.web.builders.HttpSecurity#getAuthenticationManager()}
* AuthenticationManager
* </li>
* </ul>
*
* @param <H>
* the type of {@link HttpSecurityBuilder} that is being configured
* @param <C>
* the type of object that is being chained
*
* @author Rob Winch
* @since 3.2
@@ -144,15 +142,14 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Creates the default {@link AccessDecisionVoter} instances used if an
* {@link AccessDecisionManager} was not specified using
* {@link #accessDecisionManager(AccessDecisionManager)}.
* {@link AccessDecisionManager} was not specified.
*
* @param http the builder to use
*/
@Override
@SuppressWarnings("rawtypes")
final List<AccessDecisionVoter> getDecisionVoters(H http) {
List<AccessDecisionVoter> decisionVoters = new ArrayList<AccessDecisionVoter>();
final List<AccessDecisionVoter<? extends Object>> getDecisionVoters(H http) {
List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList<AccessDecisionVoter<? extends Object>>();
decisionVoters.add(new RoleVoter());
decisionVoters.add(new AuthenticatedVoter());
return decisionVoters;
@@ -236,7 +233,6 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Creates a new instance
* @param requestMatchers the {@link RequestMatcher} instances to map to some {@link ConfigAttribute} instances.
* @see UrlAuthorizationConfigurer#chainRequestMatchers(List)
*/
private AuthorizedUrl(List<RequestMatcher> requestMatchers) {
Assert.notEmpty(requestMatchers, "requestMatchers must contain at least one value");
@@ -0,0 +1,354 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.springframework.security.config.annotation.web.messaging;
import org.springframework.messaging.Message;
import org.springframework.messaging.simp.SimpMessageType;
import org.springframework.security.config.annotation.web.configurers.RememberMeConfigurer;
import org.springframework.security.messaging.access.expression.ExpressionBasedMessageSecurityMetadataSourceFactory;
import org.springframework.security.messaging.access.intercept.MessageSecurityMetadataSource;
import org.springframework.security.messaging.util.matcher.MessageMatcher;
import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
import org.springframework.security.messaging.util.matcher.SimpMessageTypeMatcher;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
import java.util.*;
/**
* Allows mapping security constraints using {@link MessageMatcher} to the security expressions.
*
* @since 4.0
* @author Rob Winch
*/
public class MessageSecurityMetadataSourceRegistry {
private static final String permitAll = "permitAll";
private static final String denyAll = "denyAll";
private static final String anonymous = "anonymous";
private static final String authenticated = "authenticated";
private static final String fullyAuthenticated = "fullyAuthenticated";
private static final String rememberMe = "rememberMe";
private final LinkedHashMap<MatcherBuilder,String> matcherToExpression = new LinkedHashMap<MatcherBuilder,String>();
private PathMatcher pathMatcher = new AntPathMatcher();
/**
* Maps any {@link Message} to a security expression.
*
* @return the Expression to associate
*/
public Constraint anyMessage() {
return matchers(MessageMatcher.ANY_MESSAGE);
}
/**
* Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances.
*
* @param typesToMatch the {@link SimpMessageType} instance to match on
* @return the {@link Constraint} associated to the matchers.
*/
public Constraint typeMatchers(SimpMessageType... typesToMatch) {
MessageMatcher<?>[] typeMatchers = new MessageMatcher<?>[typesToMatch.length];
for (int i = 0; i < typesToMatch.length; i++) {
SimpMessageType typeToMatch = typesToMatch[i];
typeMatchers[i] = new SimpMessageTypeMatcher(typeToMatch);
}
return matchers(typeMatchers);
}
/**
* Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances
* without regard to the {@link SimpMessageType}. If no destination is found
* on the Message, then the Matcher returns false.
*
* @param patterns
* the patterns to create
* {@link org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher}
* from. Uses
* {@link MessageSecurityMetadataSourceRegistry#pathMatcher(PathMatcher)}
* .
*
* @return the {@link Constraint} that is associated to the
* {@link MessageMatcher}
* @see {@link MessageSecurityMetadataSourceRegistry#pathMatcher(PathMatcher)}
*/
public Constraint antMatchers(String... patterns) {
return antMatchers(null, patterns);
}
/**
* Maps a {@link List} of {@link SimpDestinationMessageMatcher} instances.
* If no destination is found on the Message, then the Matcher returns
* false.
*
* @param type the {@link SimpMessageType} to match on. If null, the {@link SimpMessageType} is not considered for matching.
* @param patterns the patterns to create {@link org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher}
* from. Uses {@link MessageSecurityMetadataSourceRegistry#pathMatcher(PathMatcher)}.
*
* @return the {@link Constraint} that is associated to the {@link MessageMatcher}
* @see {@link MessageSecurityMetadataSourceRegistry#pathMatcher(PathMatcher)}
*/
public Constraint antMatchers(SimpMessageType type, String... patterns) {
List<MatcherBuilder> matchers = new ArrayList<MatcherBuilder>(patterns.length);
for(String pattern : patterns) {
matchers.add(new PathMatcherMessageMatcherBuilder(pattern, type));
}
return new Constraint(matchers);
}
/**
* The {@link PathMatcher} to be used with the {@link MessageSecurityMetadataSourceRegistry#antMatchers(String...)}.
* The default is to use the default constructor of {@link AntPathMatcher}.
*
* @param pathMatcher the {@link PathMatcher} to use. Cannot be null.
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization.
*/
public MessageSecurityMetadataSourceRegistry pathMatcher(PathMatcher pathMatcher) {
Assert.notNull(pathMatcher, "pathMatcher cannot be null");
this.pathMatcher = pathMatcher;
return this;
}
/**
* Maps a {@link List} of {@link MessageMatcher} instances to a security expression.
*
* @param matchers the {@link MessageMatcher} instances to map.
* @return The {@link Constraint} that is associated to the {@link MessageMatcher} instances
*/
public Constraint matchers(MessageMatcher<?>... matchers) {
List<MatcherBuilder> builders = new ArrayList<MatcherBuilder>(matchers.length);
for(MessageMatcher<?> matcher : matchers) {
builders.add(new PreBuiltMatcherBuilder(matcher));
}
return new Constraint(builders);
}
/**
* Allows subclasses to create creating a {@link MessageSecurityMetadataSource}.
*
* <p>This is not exposed so as not to confuse users of the API, which should never invoke this method.</p>
*
* @return the {@link MessageSecurityMetadataSource} to use
*/
protected MessageSecurityMetadataSource createMetadataSource() {
LinkedHashMap<MessageMatcher<?>,String> matcherToExpression = new LinkedHashMap<MessageMatcher<?>,String>();
for(Map.Entry<MatcherBuilder,String> entry : this.matcherToExpression.entrySet()) {
matcherToExpression.put(entry.getKey().build(), entry.getValue());
}
return ExpressionBasedMessageSecurityMetadataSourceFactory.createExpressionMessageMetadataSource(matcherToExpression);
}
/**
* Allows determining if a mapping was added.
*
* <p>This is not exposed so as not to confuse users of the API, which should never need to invoke this method.</p>
*
* @return true if a mapping was added, else false
*/
protected boolean containsMapping() {
return !this.matcherToExpression.isEmpty();
}
/**
* Represents the security constraint to be applied to the {@link MessageMatcher} instances.
*/
public class Constraint {
private final List<? extends MatcherBuilder> messageMatchers;
/**
* Creates a new instance
*
* @param messageMatchers the {@link MessageMatcher} instances to map to this constraint
*/
private Constraint(List<? extends MatcherBuilder> messageMatchers) {
Assert.notEmpty(messageMatchers, "messageMatchers cannot be null or empty");
this.messageMatchers = messageMatchers;
}
/**
* Shortcut for specifying {@link Message} instances require a particular role. If you do not want to have "ROLE_" automatically
* inserted see {@link #hasAuthority(String)}.
*
* @param role the role to require (i.e. USER, ADMIN, etc). Note, it should not start with "ROLE_" as
* this is automatically inserted.
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
*/
public MessageSecurityMetadataSourceRegistry hasRole(String role) {
return access(MessageSecurityMetadataSourceRegistry.hasRole(role));
}
/**
* Shortcut for specifying {@link Message} instances require any of a number of roles. If you
* do not want to have "ROLE_" automatically inserted see
* {@link #hasAnyAuthority(String...)}
*
* @param roles
* the roles to require (i.e. USER, ADMIN, etc). Note, it
* should not start with "ROLE_" as this is automatically
* inserted.
* @return the {@link MessageSecurityMetadataSourceRegistry} for further
* customization
*/
public MessageSecurityMetadataSourceRegistry hasAnyRole(String... roles) {
return access(MessageSecurityMetadataSourceRegistry.hasAnyRole(roles));
}
/**
* Specify that {@link Message} instances require a particular authority.
*
* @param authority the authority to require (i.e. ROLE_USER, ROLE_ADMIN, etc).
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
*/
public MessageSecurityMetadataSourceRegistry hasAuthority(String authority) {
return access(MessageSecurityMetadataSourceRegistry.hasAuthority(authority));
}
/**
* Specify that {@link Message} instances requires any of a number authorities.
*
* @param authorities the requests require at least one of the authorities (i.e. "ROLE_USER","ROLE_ADMIN" would
* mean either "ROLE_USER" or "ROLE_ADMIN" is required).
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
*/
public MessageSecurityMetadataSourceRegistry hasAnyAuthority(String... authorities) {
return access(MessageSecurityMetadataSourceRegistry.hasAnyAuthority(authorities));
}
/**
* Specify that Messages are allowed by anyone.
*
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
*/
public MessageSecurityMetadataSourceRegistry permitAll() {
return access(permitAll);
}
/**
* Specify that Messages are allowed by anonymous users.
*
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
*/
public MessageSecurityMetadataSourceRegistry anonymous() {
return access(anonymous);
}
/**
* Specify that Messages are allowed by users that have been remembered.
*
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
* @see {@link RememberMeConfigurer}
*/
public MessageSecurityMetadataSourceRegistry rememberMe() {
return access(rememberMe);
}
/**
* Specify that Messages are not allowed by anyone.
*
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
*/
public MessageSecurityMetadataSourceRegistry denyAll() {
return access(denyAll);
}
/**
* Specify that Messages are allowed by any authenticated user.
*
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
*/
public MessageSecurityMetadataSourceRegistry authenticated() {
return access(authenticated);
}
/**
* Specify that Messages are allowed by users who have authenticated and were not "remembered".
*
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
* @see {@link RememberMeConfigurer}
*/
public MessageSecurityMetadataSourceRegistry fullyAuthenticated() {
return access(fullyAuthenticated);
}
/**
* Allows specifying that Messages are secured by an arbitrary expression
*
* @param attribute the expression to secure the URLs (i.e. "hasRole('ROLE_USER') and hasRole('ROLE_SUPER')")
* @return the {@link MessageSecurityMetadataSourceRegistry} for further customization
*/
public MessageSecurityMetadataSourceRegistry access(String attribute) {
for(MatcherBuilder messageMatcher : messageMatchers) {
matcherToExpression.put(messageMatcher, attribute);
}
return MessageSecurityMetadataSourceRegistry.this;
}
}
private static String hasAnyRole(String... authorities) {
String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','ROLE_");
return "hasAnyRole('ROLE_" + anyAuthorities + "')";
}
private static String hasRole(String role) {
Assert.notNull(role, "role cannot be null");
if (role.startsWith("ROLE_")) {
throw new IllegalArgumentException("role should not start with 'ROLE_' since it is automatically inserted. Got '" + role + "'");
}
return "hasRole('ROLE_" + role + "')";
}
private static String hasAuthority(String authority) {
return "hasAuthority('" + authority + "')";
}
private static String hasAnyAuthority(String... authorities) {
String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','");
return "hasAnyAuthority('" + anyAuthorities + "')";
}
private class PreBuiltMatcherBuilder implements MatcherBuilder {
private MessageMatcher<?> matcher;
private PreBuiltMatcherBuilder(MessageMatcher<?> matcher) {
this.matcher = matcher;
}
public MessageMatcher<?> build() {
return matcher;
}
}
private class PathMatcherMessageMatcherBuilder implements MatcherBuilder {
private final String pattern;
private final SimpMessageType type;
private PathMatcherMessageMatcherBuilder(String pattern, SimpMessageType type) {
this.pattern = pattern;
this.type = type;
}
public MessageMatcher<?> build() {
return new SimpDestinationMessageMatcher(pattern, type, pathMatcher);
}
}
private interface MatcherBuilder {
MessageMatcher<?> build();
}
}
@@ -19,6 +19,7 @@ import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
@@ -27,6 +28,7 @@ import org.springframework.security.config.annotation.authentication.configurati
* Add this annotation to an {@code @Configuration} class to have the Spring Security
* configuration integrate with Spring MVC.
*
* @deprecated Use EnableWebSecurity instead which will automatically add the Spring MVC related Security items.
* @author Rob Winch
* @since 3.2
*/
@@ -35,5 +37,7 @@ import org.springframework.security.config.annotation.authentication.configurati
@Documented
@Import(WebMvcSecurityConfiguration.class)
@EnableGlobalAuthentication
@Configuration
@Deprecated
public @interface EnableWebMvcSecurity {
}
@@ -20,7 +20,7 @@ import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver;
import org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver;
import org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@@ -35,17 +35,19 @@ import org.springframework.web.servlet.support.RequestDataValueProcessor;
* {@link AuthenticationPrincipalArgumentResolver} as a
* {@link HandlerMethodArgumentResolver}.
*
* @deprecated This is applied internally using SpringWebMvcImportSelector
* @author Rob Winch
* @since 3.2
*/
@Configuration
@EnableWebSecurity
public class WebMvcSecurityConfiguration extends WebMvcConfigurerAdapter {
@Override
@SuppressWarnings("deprecation")
public void addArgumentResolvers(
List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new AuthenticationPrincipalArgumentResolver());
argumentResolvers.add(new org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver());
}
@Bean
@@ -0,0 +1,119 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.springframework.security.config.annotation.web.socket;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry;
import org.springframework.security.messaging.access.expression.MessageExpressionVoter;
import org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor;
import org.springframework.security.messaging.access.intercept.MessageSecurityMetadataSource;
import org.springframework.security.messaging.context.AuthenticationPrincipalArgumentResolver;
import org.springframework.security.messaging.context.SecurityContextChannelInterceptor;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import java.util.ArrayList;
import java.util.List;
/**
* Allows configuring WebSocket Authorization.
*
* <p>For example:</p>
*
* <pre>
* @Configuration
* public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
*
* @Override
* protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
* messages
* .antMatchers("/user/queue/errors").permitAll()
* .antMatchers("/admin/**").hasRole("ADMIN")
* .anyMessage().authenticated();
* }
* }
* </pre>
*
*
* @since 4.0
* @author Rob Winch
*/
@Order(Ordered.HIGHEST_PRECEDENCE + 100)
public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends AbstractWebSocketMessageBrokerConfigurer {
private final WebSocketMessageSecurityMetadataSourceRegistry inboundRegistry = new WebSocketMessageSecurityMetadataSourceRegistry();
public final void registerStompEndpoints(StompEndpointRegistry registry) {}
@Override
public void addArgumentResolvers(
List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new AuthenticationPrincipalArgumentResolver());
}
@Override
public final void configureClientInboundChannel(ChannelRegistration registration) {
ChannelSecurityInterceptor inboundChannelSecurity = inboundChannelSecurity();
if(inboundRegistry.containsMapping()) {
registration.setInterceptors(securityContextChannelInterceptor(),inboundChannelSecurity);
}
}
@Bean
public ChannelSecurityInterceptor inboundChannelSecurity() {
ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor(inboundMessageSecurityMetadataSource());
List<AccessDecisionVoter<? extends Object>> voters = new ArrayList<AccessDecisionVoter<? extends Object>>();
voters.add(new MessageExpressionVoter());
AffirmativeBased manager = new AffirmativeBased(voters);
channelSecurityInterceptor.setAccessDecisionManager(manager);
return channelSecurityInterceptor;
}
@Bean
public SecurityContextChannelInterceptor securityContextChannelInterceptor() {
return new SecurityContextChannelInterceptor();
}
@Bean
public MessageSecurityMetadataSource inboundMessageSecurityMetadataSource() {
configureInbound(inboundRegistry);
return inboundRegistry.createMetadataSource();
}
/**
*
* @param messages
*/
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {}
private class WebSocketMessageSecurityMetadataSourceRegistry extends MessageSecurityMetadataSourceRegistry {
@Override
public MessageSecurityMetadataSource createMetadataSource() {
return super.createMetadataSource();
}
@Override
protected boolean containsMapping() {
return super.containsMapping();
}
}
}
@@ -52,7 +52,6 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
String alias = element.getAttribute(ATT_ALIAS);
checkForDeprecatedSessionControllerRef(element, pc);
List<BeanMetadataElement> providers = new ManagedList<BeanMetadataElement>();
NamespaceHandlerResolver resolver = pc.getReaderContext().getNamespaceHandlerResolver();
@@ -113,16 +112,6 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition
return null;
}
private void checkForDeprecatedSessionControllerRef(Element element, ParserContext pc) {
final String ATT_SESSION_CONTROLLER_REF = "session-controller-ref";
if (StringUtils.hasText(element.getAttribute(ATT_SESSION_CONTROLLER_REF))) {
pc.getReaderContext().warning(ATT_SESSION_CONTROLLER_REF + " is not supported in Spring Security " +
" 3.0 and will be ignored. Use the attribute on the <concurrent-session-control> element instead.",
pc.extractSource(element));
}
}
/**
* Provider which doesn't provide any service. Only used to prevent a configuration exception if the provider list
* is empty (usually because a child ProviderManager from the &lt;http&gt; namespace, such as OpenID, is expected
@@ -6,8 +6,13 @@ import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.BeanIds;
import org.springframework.security.core.userdetails.UserDetailsService;
import java.util.Arrays;
/**
* Factory bean for the namespace AuthenticationManager, which allows a more meaningful error message
@@ -28,6 +33,13 @@ public class AuthenticationManagerFactoryBean implements FactoryBean<Authenticat
return (AuthenticationManager) bf.getBean(BeanIds.AUTHENTICATION_MANAGER);
} catch (NoSuchBeanDefinitionException e) {
if (BeanIds.AUTHENTICATION_MANAGER.equals(e.getBeanName())) {
try {
UserDetailsService uds = bf.getBean(UserDetailsService.class);
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(uds);
provider.afterPropertiesSet();
return new ProviderManager(Arrays.<AuthenticationProvider>asList(provider));
} catch(NoSuchBeanDefinitionException noUds) {}
throw new NoSuchBeanDefinitionException(BeanIds.AUTHENTICATION_MANAGER, MISSING_BEAN_ERROR_MESSAGE);
}
throw e;
@@ -84,7 +84,6 @@ final class AuthenticationConfigBuilder {
private static final String ATT_AUTO_CONFIG = "auto-config";
private static final String ATT_ACCESS_DENIED_PAGE = "access-denied-page";
private static final String ATT_ACCESS_DENIED_ERROR_PAGE = "error-page";
private static final String ATT_ENTRY_POINT_REF = "entry-point-ref";
@@ -131,12 +130,12 @@ final class AuthenticationConfigBuilder {
private String loginProcessingUrl;
private String openidLoginProcessingUrl;
public AuthenticationConfigBuilder(Element element, ParserContext pc, SessionCreationPolicy sessionPolicy,
public AuthenticationConfigBuilder(Element element, boolean forceAutoConfig, ParserContext pc, SessionCreationPolicy sessionPolicy,
BeanReference requestCache, BeanReference authenticationManager, BeanReference sessionStrategy, BeanReference portMapper, BeanReference portResolver, BeanMetadataElement csrfLogoutHandler) {
this.httpElt = element;
this.pc = pc;
this.requestCache = requestCache;
autoConfig = "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
autoConfig = forceAutoConfig | "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
this.allowSessionCreation = sessionPolicy != SessionCreationPolicy.NEVER
&& sessionPolicy != SessionCreationPolicy.STATELESS;
this.portMapper = portMapper;
@@ -194,7 +193,7 @@ final class AuthenticationConfigBuilder {
RootBeanDefinition formFilter = null;
if (formLoginElt != null || autoConfig) {
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_security_check",
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/login", "POST",
AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation, portMapper, portResolver);
parser.parse(formLoginElt, pc);
@@ -219,7 +218,7 @@ final class AuthenticationConfigBuilder {
RootBeanDefinition openIDFilter = null;
if (openIDLoginElt != null) {
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/j_spring_openid_security_check",
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser("/login/openid", null,
OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache, sessionStrategy, allowSessionCreation, portMapper, portResolver);
parser.parse(openIDLoginElt, pc);
@@ -493,7 +492,11 @@ final class AuthenticationConfigBuilder {
void createLogoutFilter() {
Element logoutElt = DomUtils.getChildElementByTagName(httpElt, Elements.LOGOUT);
if (logoutElt != null || autoConfig) {
LogoutBeanDefinitionParser logoutParser = new LogoutBeanDefinitionParser(rememberMeServicesId, csrfLogoutHandler);
String formLoginPage = getLoginFormUrl(formEntryPoint);
if(formLoginPage == null) {
formLoginPage = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL;
}
LogoutBeanDefinitionParser logoutParser = new LogoutBeanDefinitionParser(formLoginPage,rememberMeServicesId, csrfLogoutHandler);
logoutFilter = logoutParser.parse(logoutElt, pc);
logoutHandlers = logoutParser.getLogoutHandlers();
}
@@ -587,20 +590,9 @@ final class AuthenticationConfigBuilder {
}
private BeanMetadataElement createAccessDeniedHandler(Element element, ParserContext pc) {
String accessDeniedPage = element.getAttribute(ATT_ACCESS_DENIED_PAGE);
WebConfigUtils.validateHttpRedirect(accessDeniedPage, pc, pc.extractSource(element));
Element accessDeniedElt = DomUtils.getChildElementByTagName(element, Elements.ACCESS_DENIED_HANDLER);
BeanDefinitionBuilder accessDeniedHandler = BeanDefinitionBuilder.rootBeanDefinition(AccessDeniedHandlerImpl.class);
if (StringUtils.hasText(accessDeniedPage)) {
if (accessDeniedElt != null) {
pc.getReaderContext().error("The attribute " + ATT_ACCESS_DENIED_PAGE +
" cannot be used with <" + Elements.ACCESS_DENIED_HANDLER + ">", pc.extractSource(accessDeniedElt));
}
accessDeniedHandler.addPropertyValue("errorPage", accessDeniedPage);
}
if (accessDeniedElt != null) {
String errorPage = accessDeniedElt.getAttribute("error-page");
String ref = accessDeniedElt.getAttribute("ref");
@@ -56,6 +56,10 @@ public class CsrfBeanDefinitionParser implements BeanDefinitionParser {
private BeanDefinition csrfFilter;
public BeanDefinition parse(Element element, ParserContext pc) {
boolean disabled = element != null && "true".equals(element.getAttribute("disabled"));
if(disabled) {
return null;
}
boolean webmvcPresent = ClassUtils.isPresent(DISPATCHER_SERVLET_CLASS_NAME, getClass().getClassLoader());
if(webmvcPresent) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(CsrfRequestDataValueProcessor.class);
@@ -64,8 +68,11 @@ public class CsrfBeanDefinitionParser implements BeanDefinitionParser {
pc.registerBeanComponent(componentDefinition);
}
csrfRepositoryRef = element.getAttribute(ATT_REPOSITORY);
String matcherRef = element.getAttribute(ATT_MATCHER);
String matcherRef = null;
if(element != null) {
csrfRepositoryRef = element.getAttribute(ATT_REPOSITORY);
matcherRef = element.getAttribute(ATT_MATCHER);
}
if(!StringUtils.hasText(csrfRepositoryRef)) {
RootBeanDefinition csrfTokenRepository = new RootBeanDefinition(HttpSessionCsrfTokenRepository.class);
@@ -5,14 +5,17 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.config.Elements;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
@@ -29,7 +32,7 @@ public class FilterChainMapBeanDefinitionDecorator implements BeanDefinitionDeco
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder holder, ParserContext parserContext) {
BeanDefinition filterChainProxy = holder.getBeanDefinition();
Map filterChainMap = new LinkedHashMap();
ManagedList<BeanMetadataElement> securityFilterChains = new ManagedList<BeanMetadataElement>();
Element elt = (Element)node;
MatcherType matcherType = MatcherType.fromElement(elt);
@@ -53,7 +56,7 @@ public class FilterChainMapBeanDefinitionDecorator implements BeanDefinitionDeco
BeanDefinition matcher = matcherType.createMatcher(path, null);
if (filters.equals(HttpSecurityBeanDefinitionParser.OPT_FILTERS_NONE)) {
filterChainMap.put(matcher, Collections.EMPTY_LIST);
securityFilterChains.add(createSecurityFilterChain(matcher, new ManagedList(0)));
} else {
String[] filterBeanNames = StringUtils.tokenizeToStringArray(filters, ",");
ManagedList filterChain = new ManagedList(filterBeanNames.length);
@@ -62,15 +65,19 @@ public class FilterChainMapBeanDefinitionDecorator implements BeanDefinitionDeco
filterChain.add(new RuntimeBeanReference(name));
}
filterChainMap.put(matcher, filterChain);
securityFilterChains.add(createSecurityFilterChain(matcher, filterChain));
}
}
ManagedMap map = new ManagedMap(filterChainMap.size());
map.putAll(filterChainMap);
filterChainProxy.getPropertyValues().addPropertyValue("filterChainMap", map);
filterChainProxy.getConstructorArgumentValues().addGenericArgumentValue(securityFilterChains);
return holder;
}
private BeanDefinition createSecurityFilterChain(BeanDefinition matcher, ManagedList<?> filters) {
BeanDefinitionBuilder sfc = BeanDefinitionBuilder.rootBeanDefinition(DefaultSecurityFilterChain.class);
sfc.addConstructorArgValue(matcher);
sfc.addConstructorArgValue(filters);
return sfc.getBeanDefinition();
}
}
@@ -48,7 +48,7 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
}
}
BeanDefinition mds = createSecurityMetadataSource(interceptUrls, element, parserContext);
BeanDefinition mds = createSecurityMetadataSource(interceptUrls, false, element, parserContext);
String id = element.getAttribute(AbstractBeanDefinitionParser.ID_ATTRIBUTE);
@@ -60,16 +60,16 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
return mds;
}
static RootBeanDefinition createSecurityMetadataSource(List<Element> interceptUrls, Element elt, ParserContext pc) {
MatcherType matcherType = MatcherType.fromElement(elt);
boolean useExpressions = isUseExpressions(elt);
static RootBeanDefinition createSecurityMetadataSource(List<Element> interceptUrls, boolean addAllAuth, Element httpElt, ParserContext pc) {
MatcherType matcherType = MatcherType.fromElement(httpElt);
boolean useExpressions = isUseExpressions(httpElt);
ManagedMap<BeanDefinition, BeanDefinition> requestToAttributesMap = parseInterceptUrlsForFilterInvocationRequestMap(
matcherType, interceptUrls, useExpressions, pc);
matcherType, interceptUrls, useExpressions, addAllAuth, pc);
BeanDefinitionBuilder fidsBuilder;
if (useExpressions) {
Element expressionHandlerElt = DomUtils.getChildElementByTagName(elt, Elements.EXPRESSION_HANDLER);
Element expressionHandlerElt = DomUtils.getChildElementByTagName(httpElt, Elements.EXPRESSION_HANDLER);
String expressionHandlerRef = expressionHandlerElt == null ? null : expressionHandlerElt.getAttribute("ref");
if (StringUtils.hasText(expressionHandlerRef)) {
@@ -86,7 +86,7 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
fidsBuilder.addConstructorArgValue(requestToAttributesMap);
}
fidsBuilder.getRawBeanDefinition().setSource(pc.extractSource(elt));
fidsBuilder.getRawBeanDefinition().setSource(pc.extractSource(httpElt));
return (RootBeanDefinition) fidsBuilder.getBeanDefinition();
}
@@ -100,12 +100,13 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
}
static boolean isUseExpressions(Element elt) {
return "true".equals(elt.getAttribute(ATT_USE_EXPRESSIONS));
String useExpressions = elt.getAttribute(ATT_USE_EXPRESSIONS);
return !StringUtils.hasText(useExpressions) || "true".equals(useExpressions);
}
private static ManagedMap<BeanDefinition, BeanDefinition>
parseInterceptUrlsForFilterInvocationRequestMap(MatcherType matcherType,
List<Element> urlElts, boolean useExpressions, ParserContext parserContext) {
List<Element> urlElts, boolean useExpressions, boolean addAuthenticatedAll, ParserContext parserContext) {
ManagedMap<BeanDefinition, BeanDefinition> filterInvocationDefinitionMap = new ManagedMap<BeanDefinition, BeanDefinition>();
@@ -128,14 +129,15 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
BeanDefinition matcher = matcherType.createMatcher(path, method);
BeanDefinitionBuilder attributeBuilder = BeanDefinitionBuilder.rootBeanDefinition(SecurityConfig.class);
attributeBuilder.addConstructorArgValue(access);
if (useExpressions) {
logger.info("Creating access control expression attribute '" + access + "' for " + path);
// The single expression will be parsed later by the ExpressionFilterInvocationSecurityMetadataSource
attributeBuilder.setFactoryMethod("createSingleAttributeList");
attributeBuilder.addConstructorArgValue(new String[] { access });
attributeBuilder.setFactoryMethod("createList");
} else {
attributeBuilder.addConstructorArgValue(access);
attributeBuilder.setFactoryMethod("createListFromCommaDelimitedString");
}
@@ -146,6 +148,15 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
filterInvocationDefinitionMap.put(matcher, attributeBuilder.getBeanDefinition());
}
if(addAuthenticatedAll && filterInvocationDefinitionMap.isEmpty()) {
BeanDefinition matcher = matcherType.createMatcher("/**", null);
BeanDefinitionBuilder attributeBuilder = BeanDefinitionBuilder.rootBeanDefinition(SecurityConfig.class);
attributeBuilder.addConstructorArgValue(new String[] { "authenticated" });
attributeBuilder.setFactoryMethod("createList");
filterInvocationDefinitionMap.put(matcher, attributeBuilder.getBeanDefinition());
}
return filterInvocationDefinitionMap;
}
@@ -66,11 +66,13 @@ public class FormLoginBeanDefinitionParser {
private RootBeanDefinition filterBean;
private RootBeanDefinition entryPointBean;
private String loginPage;
private String loginMethod;
private String loginProcessingUrl;
FormLoginBeanDefinitionParser(String defaultLoginProcessingUrl, String filterClassName,
FormLoginBeanDefinitionParser(String defaultLoginProcessingUrl, String loginMethod, String filterClassName,
BeanReference requestCache, BeanReference sessionStrategy, boolean allowSessionCreation, BeanReference portMapper, BeanReference portResolver) {
this.defaultLoginProcessingUrl = defaultLoginProcessingUrl;
this.loginMethod = loginMethod;
this.filterClassName = filterClassName;
this.requestCache = requestCache;
this.sessionStrategy = sessionStrategy;
@@ -151,8 +153,11 @@ public class FormLoginBeanDefinitionParser {
this.loginProcessingUrl = loginUrl;
BeanDefinitionBuilder matcherBuilder = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.web.authentication.logout.LogoutFilter$FilterProcessUrlRequestMatcher");
BeanDefinitionBuilder matcherBuilder = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.web.util.matcher.AntPathRequestMatcher");
matcherBuilder.addConstructorArgValue(loginUrl);
if(loginMethod != null) {
matcherBuilder.addConstructorArgValue("POST");
}
filterBuilder.addPropertyValue("requiresAuthenticationRequestMatcher", matcherBuilder.getBeanDefinition());
@@ -80,14 +80,24 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
headerWriters = new ManagedList<BeanMetadataElement>();
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(HeaderWriterFilter.class);
parseCacheControlElement(element);
parseHstsElement(element);
parseXssElement(element, parserContext);
parseFrameOptionsElement(element, parserContext);
parseContentTypeOptionsElement(element);
if(element != null) {
parseHeaderElements(element);
parseCacheControlElement(element);
parseHstsElement(element);
parseXssElement(element, parserContext);
parseFrameOptionsElement(element, parserContext);
parseContentTypeOptionsElement(element);
parseHeaderElements(element);
}
boolean disabled = element != null && "true".equals(element.getAttribute("disabled"));
if(disabled) {
if(!headerWriters.isEmpty()) {
parserContext.getReaderContext().error("Cannot specify <headers disabled=\"true\"> with child elements.", element);
}
return null;
}
if(headerWriters.isEmpty()) {
addCacheControl();
addHsts(null);
@@ -208,7 +218,7 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
}
String fromParameter = getAttribute(frameElt, ATT_FROM_PARAMETER, "from");
allowFromStrategy.addPropertyValue("allowFromParameterName", fromParameter);
builder.addConstructorArgValue(allowFromStrategy);
builder.addConstructorArgValue(allowFromStrategy.getBeanDefinition());
}
} else {
parserContext.getReaderContext().error("One of 'strategy' and 'strategy-ref' must be set.",
@@ -133,10 +133,12 @@ class HttpConfigurationBuilder {
private CsrfBeanDefinitionParser csrfParser;
private BeanDefinition invalidSession;
private boolean addAllAuth;
public HttpConfigurationBuilder(Element element, ParserContext pc,
public HttpConfigurationBuilder(Element element, boolean addAllAuth, ParserContext pc,
BeanReference portMapper, BeanReference portResolver, BeanReference authenticationManager) {
this.httpElt = element;
this.addAllAuth = addAllAuth;
this.pc = pc;
this.portMapper = portMapper;
this.portResolver = portResolver;
@@ -583,7 +585,7 @@ class HttpConfigurationBuilder {
private void createFilterSecurityInterceptor(BeanReference authManager) {
boolean useExpressions = FilterInvocationSecurityMetadataSourceParser.isUseExpressions(httpElt);
RootBeanDefinition securityMds = FilterInvocationSecurityMetadataSourceParser.createSecurityMetadataSource(interceptUrls, httpElt, pc);
RootBeanDefinition securityMds = FilterInvocationSecurityMetadataSourceParser.createSecurityMetadataSource(interceptUrls, addAllAuth, httpElt, pc);
RootBeanDefinition accessDecisionMgr;
ManagedList<BeanDefinition> voters = new ManagedList<BeanDefinition>(2);
@@ -638,22 +640,22 @@ class HttpConfigurationBuilder {
private void createAddHeadersFilter() {
Element elmt = DomUtils.getChildElementByTagName(httpElt, Elements.HEADERS);
if (elmt != null) {
this.addHeadersFilter = new HeadersBeanDefinitionParser().parse(elmt, pc);
}
this.addHeadersFilter = new HeadersBeanDefinitionParser().parse(elmt, pc);
}
private CsrfBeanDefinitionParser createCsrfFilter() {
private void createCsrfFilter() {
Element elmt = DomUtils.getChildElementByTagName(httpElt, Elements.CSRF);
if (elmt != null) {
csrfParser = new CsrfBeanDefinitionParser();
csrfFilter = csrfParser.parse(elmt, pc);
this.csrfAuthStrategy = csrfParser.getCsrfAuthenticationStrategy();
this.csrfLogoutHandler = csrfParser.getCsrfLogoutHandler();
return csrfParser;
csrfParser = new CsrfBeanDefinitionParser();
csrfFilter = csrfParser.parse(elmt, pc);
if(csrfFilter == null) {
csrfParser = null;
return;
}
return null;
this.csrfAuthStrategy = csrfParser.getCsrfAuthenticationStrategy();
this.csrfLogoutHandler = csrfParser.getCsrfLogoutHandler();
}
BeanMetadataElement getCsrfLogoutHandler() {
@@ -132,10 +132,11 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
ManagedList<BeanReference> authenticationProviders = new ManagedList<BeanReference>();
BeanReference authenticationManager = createAuthenticationManager(element, pc, authenticationProviders);
HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, pc,
boolean forceAutoConfig = isDefaultHttpConfig(element);
HttpConfigurationBuilder httpBldr = new HttpConfigurationBuilder(element, forceAutoConfig, pc,
portMapper, portResolver, authenticationManager);
AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, pc,
AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, forceAutoConfig, pc,
httpBldr.getSessionCreationPolicy(), httpBldr.getRequestCache(), authenticationManager,
httpBldr.getSessionStrategy(), portMapper, portResolver, httpBldr.getCsrfLogoutHandler());
@@ -164,6 +165,10 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
return createSecurityFilterChainBean(element, pc, filterChain);
}
private static boolean isDefaultHttpConfig(Element httpElt) {
return httpElt.getChildNodes().getLength() == 0 && httpElt.getAttributes().getLength() == 0;
}
private BeanReference createSecurityFilterChainBean(Element element, ParserContext pc, List<?> filterChain) {
BeanMetadataElement filterChainMatcher;
@@ -35,21 +35,24 @@ import org.w3c.dom.Element;
*/
class LogoutBeanDefinitionParser implements BeanDefinitionParser {
static final String ATT_LOGOUT_SUCCESS_URL = "logout-success-url";
static final String DEF_LOGOUT_SUCCESS_URL = "/";
static final String ATT_INVALIDATE_SESSION = "invalidate-session";
static final String ATT_LOGOUT_URL = "logout-url";
static final String DEF_LOGOUT_URL = "/j_spring_security_logout";
static final String DEF_LOGOUT_URL = "/logout";
static final String ATT_LOGOUT_HANDLER = "success-handler-ref";
static final String ATT_DELETE_COOKIES = "delete-cookies";
final String rememberMeServices;
private final String defaultLogoutUrl;
private ManagedList<BeanMetadataElement> logoutHandlers = new ManagedList<BeanMetadataElement>();
private boolean csrfEnabled;
public LogoutBeanDefinitionParser(String rememberMeServices, BeanMetadataElement csrfLogoutHandler) {
public LogoutBeanDefinitionParser(String loginPageUrl, String rememberMeServices, BeanMetadataElement csrfLogoutHandler) {
this.defaultLogoutUrl = loginPageUrl + "?logout";
this.rememberMeServices = rememberMeServices;
if(csrfLogoutHandler != null) {
this.csrfEnabled = csrfLogoutHandler != null;
if (this.csrfEnabled) {
logoutHandlers.add(csrfLogoutHandler);
}
}
@@ -78,10 +81,9 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
if (!StringUtils.hasText(logoutUrl)) {
logoutUrl = DEF_LOGOUT_URL;
}
BeanDefinitionBuilder matcherBuilder = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter$FilterProcessUrlRequestMatcher");
matcherBuilder.addConstructorArgValue(logoutUrl);
builder.addPropertyValue("logoutRequestMatcher", matcherBuilder.getBeanDefinition());
builder.addPropertyValue("logoutRequestMatcher", getLogoutRequestMatcher(logoutUrl));
if (StringUtils.hasText(successHandlerRef)) {
if (StringUtils.hasText(logoutSuccessUrl)) {
@@ -92,7 +94,7 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
} else {
// Use the logout URL if no handler set
if (!StringUtils.hasText(logoutSuccessUrl)) {
logoutSuccessUrl = DEF_LOGOUT_SUCCESS_URL;
logoutSuccessUrl = defaultLogoutUrl;
}
builder.addConstructorArgValue(logoutSuccessUrl);
}
@@ -117,6 +119,16 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
return builder.getBeanDefinition();
}
private BeanDefinition getLogoutRequestMatcher(String logoutUrl) {
BeanDefinitionBuilder matcherBuilder = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.web.util.matcher.AntPathRequestMatcher");
matcherBuilder.addConstructorArgValue(logoutUrl);
if(this.csrfEnabled) {
matcherBuilder.addConstructorArgValue("POST");
}
return matcherBuilder.getBeanDefinition();
}
ManagedList<BeanMetadataElement> getLogoutHandlers() {
return logoutHandlers;
}
@@ -1,7 +1,5 @@
package org.springframework.security.config.http;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.RootBeanDefinition;
@@ -23,10 +21,7 @@ public enum MatcherType {
regex (RegexRequestMatcher.class),
ciRegex (RegexRequestMatcher.class);
private static final Log logger = LogFactory.getLog(MatcherType.class);
private static final String ATT_MATCHER_TYPE = "request-matcher";
private static final String ATT_PATH_TYPE = "path-type";
private final Class<? extends RequestMatcher> type;
@@ -56,11 +51,6 @@ public enum MatcherType {
return valueOf(elt.getAttribute(ATT_MATCHER_TYPE));
}
if (StringUtils.hasText(elt.getAttribute(ATT_PATH_TYPE))) {
logger.warn("'" + ATT_PATH_TYPE + "' is deprecated. Please use '" + ATT_MATCHER_TYPE +"' instead.");
return valueOf(elt.getAttribute(ATT_PATH_TYPE));
}
return ant;
}
}
@@ -0,0 +1,187 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.message;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.*;
import org.springframework.beans.factory.support.*;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.beans.factory.xml.XmlReaderContext;
import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler;
import org.springframework.security.access.vote.ConsensusBased;
import org.springframework.security.config.Elements;
import org.springframework.security.messaging.access.expression.ExpressionBasedMessageSecurityMetadataSourceFactory;
import org.springframework.security.messaging.access.expression.MessageExpressionVoter;
import org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor;
import org.springframework.security.messaging.context.AuthenticationPrincipalArgumentResolver;
import org.springframework.security.messaging.context.SecurityContextChannelInterceptor;
import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
import java.util.List;
/**
* Parses Spring Security's message namespace support. A simple example is:
*
* <code>
* &lt;messages&gt;
* &lt;message-interceptor pattern='/permitAll' access='permitAll' /&gt;
* &lt;message-interceptor pattern='/denyAll' access='denyAll' /&gt;
* &lt;/messages&gt;
* </code>
*
* <p>
* The above configuration will ensure that any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver
* registered as a custom argument resolver. It also ensures that the SecurityContextChannelInterceptor is automatically
* registered for the clientInboundChannel. Last, it ensures that a ChannelSecurityInterceptor is registered with the
* clientInboundChannel.
* </p>
*
* <p>
* If finer control is necessary, the id attribute can be used as shown below:
* </p>
*
* <code>
* &lt;messages id="channelSecurityInterceptor"&gt;
* &lt;message-interceptor pattern='/permitAll' access='permitAll' /&gt;
* &lt;message-interceptor pattern='/denyAll' access='denyAll' /&gt;
* &lt;/messages&gt;
* </code>
*
* <p>
* Now the configuration will only create a bean named ChannelSecurityInterceptor and assign it to the id of
* channelSecurityInterceptor. Users can explicitly wire Spring Security using the standard Spring Messaging XML
* namespace support.
* </p>
*
* @author Rob Winch
* @since 4.0
*/
public final class MessageSecurityBeanDefinitionParser implements BeanDefinitionParser {
private static final Log logger = LogFactory.getLog(MessageSecurityBeanDefinitionParser.class);
private static final String ID_ATTR = "id";
private static final String PATTERN_ATTR = "pattern";
private static final String ACCESS_ATTR = "access";
/**
* @param element
* @param parserContext
* @return
*/
public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinitionRegistry registry = parserContext.getRegistry();
XmlReaderContext context = parserContext.getReaderContext();
ManagedMap<BeanDefinition,String> matcherToExpression = new ManagedMap<BeanDefinition, String>();
String id = element.getAttribute(ID_ATTR);
List<Element> interceptMessages = DomUtils.getChildElementsByTagName(element, Elements.INTERCEPT_MESSAGE);
for(Element interceptMessage : interceptMessages) {
String matcherPattern = interceptMessage.getAttribute(PATTERN_ATTR);
String accessExpression = interceptMessage.getAttribute(ACCESS_ATTR);
BeanDefinitionBuilder matcher = BeanDefinitionBuilder.rootBeanDefinition(SimpDestinationMessageMatcher.class);
matcher.addConstructorArgValue(matcherPattern);
matcherToExpression.put(matcher.getBeanDefinition(), accessExpression);
}
BeanDefinitionBuilder mds = BeanDefinitionBuilder.rootBeanDefinition(ExpressionBasedMessageSecurityMetadataSourceFactory.class);
mds.setFactoryMethod("createExpressionMessageMetadataSource");
mds.addConstructorArgValue(matcherToExpression);
String mdsId = context.registerWithGeneratedName(mds.getBeanDefinition());
ManagedList<BeanDefinition> voters = new ManagedList<BeanDefinition>();
voters.add(new RootBeanDefinition(MessageExpressionVoter.class));
BeanDefinitionBuilder adm = BeanDefinitionBuilder.rootBeanDefinition(ConsensusBased.class);
adm.addConstructorArgValue(voters);
BeanDefinitionBuilder inboundChannelSecurityInterceptor = BeanDefinitionBuilder.rootBeanDefinition(ChannelSecurityInterceptor.class);
inboundChannelSecurityInterceptor.addConstructorArgValue(registry.getBeanDefinition(mdsId));
inboundChannelSecurityInterceptor.addPropertyValue("accessDecisionManager", adm.getBeanDefinition());
String inSecurityInterceptorName = context.registerWithGeneratedName(inboundChannelSecurityInterceptor.getBeanDefinition());
if(StringUtils.hasText(id)) {
registry.registerAlias(inSecurityInterceptorName, id);
} else {
BeanDefinitionBuilder mspp = BeanDefinitionBuilder.rootBeanDefinition(MessageSecurityPostProcessor.class);
mspp.addConstructorArgValue(inSecurityInterceptorName);
context.registerWithGeneratedName(mspp.getBeanDefinition());
}
return null;
}
static class MessageSecurityPostProcessor implements BeanDefinitionRegistryPostProcessor {
private static final String CLIENT_INBOUND_CHANNEL_BEAN_ID = "clientInboundChannel";
private static final String INTERCEPTORS_PROP = "interceptors";
private static final String CUSTOM_ARG_RESOLVERS_PROP = "customArgumentResolvers";
private final String inboundSecurityInterceptorId;
public MessageSecurityPostProcessor(String inboundSecurityInterceptorId) {
this.inboundSecurityInterceptorId = inboundSecurityInterceptorId;
}
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
String[] beanNames = registry.getBeanDefinitionNames();
for(String beanName : beanNames) {
BeanDefinition bd = registry.getBeanDefinition(beanName);
if(bd.getBeanClassName().equals(SimpAnnotationMethodMessageHandler.class.getName())) {
PropertyValue current = bd.getPropertyValues().getPropertyValue(CUSTOM_ARG_RESOLVERS_PROP);
ManagedList<Object> argResolvers = new ManagedList<Object>();
if(current != null) {
argResolvers.addAll((ManagedList<?>)current.getValue());
}
argResolvers.add(new RootBeanDefinition(AuthenticationPrincipalArgumentResolver.class));
bd.getPropertyValues().add(CUSTOM_ARG_RESOLVERS_PROP, argResolvers);
}
}
if(!registry.containsBeanDefinition(CLIENT_INBOUND_CHANNEL_BEAN_ID)) {
return;
}
ManagedList<Object> interceptors = new ManagedList();
interceptors.add(new RootBeanDefinition(SecurityContextChannelInterceptor.class));
interceptors.add(registry.getBeanDefinition(inboundSecurityInterceptorId));
BeanDefinition inboundChannel = registry.getBeanDefinition(CLIENT_INBOUND_CHANNEL_BEAN_ID);
PropertyValue currentInterceptorsPv = inboundChannel.getPropertyValues().getPropertyValue(INTERCEPTORS_PROP);
if(currentInterceptorsPv != null) {
ManagedList<?> currentInterceptors = (ManagedList<?>) currentInterceptorsPv.getValue();
interceptors.addAll(currentInterceptors);
}
inboundChannel.getPropertyValues().add(INTERCEPTORS_PROP, interceptors);
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
}
@@ -452,6 +452,9 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
}
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
if(!registry.containsBeanDefinition(beanName)) {
return;
}
BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
beanDefinition.setLazyInit(true);
}

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