1
0
mirror of synced 2026-09-08 02:09:55 +00:00

Compare commits

..

200 Commits

Author SHA1 Message Date
Spring Buildmaster 4619705e37 Release version 3.2.0.RELEASE 2013-12-16 11:27:09 -08:00
Rob Winch f09ce267b3 Polish MVC doc 2013-12-16 12:30:25 -06:00
Rob Winch 374aceed2b Polish form.asc 2013-12-16 11:13:23 -06:00
Rob Winch df703e0189 Polish hellomvc.asc 2013-12-16 10:39:18 -06:00
Rob Winch 8c580dc170 SEC-2444: Polish Thymeleaf for samples 2013-12-16 09:51:00 -06:00
Rob Winch 5205bf57c6 SEC-2453: Create 403 CSRF FAQ Entry 2013-12-16 09:02:02 -06:00
Rob Winch 994117ad75 SEC-2436: Fix CsrfConfigurerNoWebMvcTests 2013-12-14 14:48:47 -06:00
Rob Winch b7041ed00e SEC-2436: Add @EnableWebMvcSecurity 2013-12-14 14:40:01 -06:00
Rob Winch 053c890a69 SEC-2450: WebSecurityConfigurerAdapter have default Order of 100 2013-12-14 13:00:48 -06:00
Rob Winch 7838e3eeca SEC-2447: JdbcMutableAclServiceTests should invoke aclCache.clearCache() 2013-12-14 10:19:06 -06:00
Rob Winch 2df5541905 SEC-2448: Update to HSQL 2.3.1 2013-12-14 10:19:06 -06:00
Rob Winch 04fac30d75 SEC-2449: <ldap-server> default port should fallback to dynamic value 2013-12-14 10:19:06 -06:00
Rob Winch 54ffa28bde remove apacheDSWorkDir since custom tmp dir is created 2013-12-13 16:38:35 -06:00
Rob Winch ca1080fb96 SEC-2439: HttpSessionCsrfTokenRepository setHeaderName sets header instead of parameter 2013-12-13 15:47:28 -06:00
Rob Winch 4708287ad3 SEC-2444: Convert Java Config samples to thymeleaf and tiles 2013-12-13 15:47:28 -06:00
Rob Winch 0d12397662 SEC-2385: Polish Gradle Spring 4 usage doc 2013-12-12 08:20:37 -06:00
Rob Winch a34178bc40 SEC-2434: Update to Spring 3.2.6 and Spring 4.0 GA 2013-12-12 08:16:59 -06:00
Rob Winch aaa7cec32e SEC-2326: CsrfRequestDataValueProcessor implements RequestDataValueProcessor
Previously there was unecessary complexity in CsrfRequestDataValueProcessor
due to the non-passive changes in RequestDataValueProcessor. Now it simply
implements the interface with the methods for both versions of the interface.
This works since linking happens at runtime.
2013-12-12 08:07:22 -06:00
Rob Winch 6f9085dd5d SEC-2435: Update to Gradle 1.10-rc-2 2013-12-11 17:52:41 -06:00
Rob Winch 7f714ebb23 SEC-2422: Session timeout detection with CSRF protection 2013-12-11 17:38:17 -06:00
Rob Winch 00d668dc5c SEC-2431: UrlAuthorizationConfigurer missing <HttpSecurity> in doc 2013-12-11 11:07:05 -06:00
Rob Winch 035067caf4 SEC-2385: Polish Gradle Spring 4 usage doc 2013-12-11 08:08:51 -06:00
Rob Winch 0da9b6c64b Update to spring.io 2013-12-09 16:51:45 -06:00
Rob Winch 418bb57323 SEC-2430: Enable artifactoryPublish on bom 2013-12-09 16:29:29 -06:00
Rob Winch 4672c2a1f7 SEC-2430: Add Maven BOM 2013-12-09 15:51:49 -06:00
Rob Winch 4460e84b29 Updates to pom.xml author and repo 2013-12-09 08:57:30 -06:00
Rob Winch 548ed4e14a Update samples to declare repository already added 2013-12-06 14:46:52 -06:00
Rob Winch 6be4de854a Ensure artifactory uses customized pom 2013-12-06 14:46:52 -06:00
Rob Winch feeb380b51 Polish Guides 2013-12-06 11:12:07 -06:00
Rob Winch ec524da6cb SEC-2416: Fix Hello MVC guide 2013-12-05 15:47:38 -06:00
Rob Winch fc6fc19eed Fix guides 2013-12-05 13:16:59 -06:00
Rob Winch fa39ecd719 SEC-2367: ProviderManager rethrows InternalAuthenticationServiceExceptions 2013-12-04 16:19:33 -06:00
Rob Winch 7e274ea5b6 Fix typo in InternalAuthenticationServiceException javadoc 2013-12-04 16:18:59 -06:00
Rob Winch 8e8bdad8e6 SEC-2386: Remove stack for AuthenticationManagerBuilder with no authenticationProviders 2013-12-04 15:53:32 -06:00
Rob Winch f2fdc9d1f5 SEC-2425: Add Test for EnableGlobalMethodSecurity works on parent config 2013-12-04 14:54:56 -06:00
Rob Winch 74a6303b6f SEC-2385: Document how to use with Spring 4 2013-12-04 12:38:45 -06:00
Rob Winch be15213819 SEC-2388: Deploy spring-security-samples-messages-jc 2013-12-03 13:03:15 -06:00
Rob Winch 595b16d836 SEC-2377: Fix tests 2013-12-03 11:48:25 -06:00
Rob Winch 2a632a061e SEC-2377: Hhandle EnableWebSecurity in both child & parent ApplicationContext 2013-12-03 10:45:25 -06:00
Rob Winch 4308e72573 Polish CSRF log in caveat with link 2013-12-03 09:27:49 -06:00
Rob Winch b8cc42e3a3 SEC-2426: Add CSRF and logout with non-post example 2013-12-03 09:07:54 -06:00
Rob Winch ab08d99a52 SEC-2421: Remove filterProcessUrl from UsernamePasswordAuthenticationFilter doc 2013-12-02 16:47:57 -06:00
Rob Winch 135df149a3 SEC-2423: Document differences between defaults in Java & XML Config 2013-12-02 16:37:52 -06:00
Mat Booth c6a534cad8 SEC-2418: Minor fix to toString method in LdapUserDetailsImpl 2013-12-02 12:00:09 -06:00
Rob Winch 0b996c669f SEC-2424: Document ObjectPostProcessor 2013-12-02 10:17:08 -06:00
Rob Winch 13c5af5b91 SEC-2407: Better error message for missing securityFilterChainBuilders 2013-11-26 10:12:55 -06:00
Rob Winch e97758dd3a SEC-2412: Update to propdeps-plugin:0.0.5 2013-11-25 17:00:34 -06:00
Rob Winch 209cf317d6 SEC-2411: Update to Gradle 1.9 2013-11-25 16:57:42 -06:00
Rob Winch 5641ab98c1 SEC-2410: AclFormattingUtils.printBinary handles negative 2013-11-22 13:10:50 -06:00
Rob Winch c7b93e6cee SEC-2404: Fix CSRF config tests 2013-11-21 15:35:26 -06:00
Rob Winch 59e13e7bbb SEC-2404: CsrfAuthenticationStrategy creates new valid CsrfToken 2013-11-21 15:12:08 -06:00
Rob Winch 5a59c74d02 SEC-2327: Document SecurityExpressionRoot 2013-11-20 16:59:05 -06:00
Rob Winch 5bc6f64b03 SEC-2405: Added tests for OBJECT_FACTORIES 2013-11-20 14:04:15 -06:00
Mattias Hellborg Arthursson bc6fc518d3 SEC-2405: Use DirContextAdapter directly from search. Configure OBJECT_FACTORIES on DirContext created for ActiveDirectory. 2013-11-20 13:51:51 -06:00
Rob Winch 9dbe30c81d SEC-2165: remember-me@token-validity-seconds can be parameterized 2013-11-15 14:58:53 -06:00
Rob Winch 2d2f91484d SEC-2350: Fix broken test 2013-11-15 14:01:35 -06:00
Rob Winch afddb5eb39 SEC-2373: Update XSD doc to state security="none" 2013-11-15 13:50:49 -06:00
Rob Winch 1745715865 SEC-2350: Remove warning whe using Spring 4 2013-11-15 13:43:43 -06:00
Rob Winch 6382b6341a SEC-2355: Add test to validate intercept-url PATCH works 2013-11-15 11:57:47 -06:00
Collin Peters 85cd5627b6 SEC-2355: Add PATCH to intercept-url xsd 2013-11-15 11:46:34 -06:00
Rob Winch 4944e602cb SEC-2402: Reference cleanup
* Fix link rendering in CSRF section
* Remove static from MultiHttpSecurityConfig sample
* Decrease indention since can render w/ PDF now
* Remove invalid characters
2013-11-15 10:50:08 -06:00
Rob Winch f1f3acdf75 Fix guides spec 2013-11-01 14:21:37 -05:00
Rob Winch 2c8946c406 Next development version 2013-11-01 14:20:55 -05:00
Spring Buildmaster 9c703a3051 Release version 3.2.0.RC2 2013-11-01 14:20:49 -05:00
Rob Winch dc317b3602 WebSecurityConfigurerAdapter implements WebSecurityConfigurer 2013-11-01 12:26:32 -05:00
Rob Winch e657f89662 Remove checkRepositories 2013-11-01 09:32:24 -05:00
Rob Winch cda23443ac XsdDocumentedTests now uses asciidoc instead of asciidoctor 2013-11-01 09:32:05 -05:00
Rob Winch 2ef53234d0 spring4Test uses Spring 4.0.0.RC1 2013-11-01 09:31:27 -05:00
Rob Winch c135179029 Update to latest Asciidoctor version
We will temporarily remove PDF support until the plugin supports it.
2013-10-30 16:56:00 -05:00
Rob Winch cf3e2f2c6a Fix guide index's link to custom form 2013-10-30 16:19:51 -05:00
Rob Winch 26be54653b SEC-2382: AutowireBeanFactoryObjectPostProcessor works w/ BeanNameAutoProxyCreator 2013-10-30 11:20:42 -05:00
Rob Winch fa3d303f79 Remove repository release checks since init script adds automatically 2013-10-29 16:48:23 -05:00
Rob Winch 17b9f33351 SEC-2378: Fix CSRF MultipartFilter doc typo 2013-10-29 13:07:10 -05:00
Rob Winch 5427da6b27 Move reference to htmlsingle to match standard Spring reference layout 2013-10-29 12:56:29 -05:00
Rob Winch 1a1f577a8b SEC-2358: Add RequestHEaderRequestMatcher#toString() 2013-10-28 14:41:10 -05:00
Rob Winch 9e7fbf8067 SEC-2321: Refine to use X-Requested-With: XMLHttpRequest 2013-10-28 14:00:56 -05:00
Rob Winch 78f85cc129 SEC-2349: Number the reference 2013-10-23 17:46:57 -05:00
Rob Winch 85ec2429d9 SEC-2349: Externalize FAQ 2013-10-23 17:43:32 -05:00
Rob Winch e638f0a547 SEC-2357: old RequestMatcher interface extends new RequestMatcher 2013-10-23 17:09:33 -05:00
Rob Winch 355f884d22 SEC-2093: Document what is new in Spring Security 3.2 2013-10-18 16:39:01 -05:00
Rob Winch 4a24c81147 SEC-2299: Document @AuthenticationPrincipal 2013-10-18 15:46:29 -05:00
Rob Winch 5f290ba10f SEC-2371: Remove ObjectPostProcessor.QUIESENT_POSTPROCESSOR 2013-10-18 14:31:13 -05:00
Rob Winch a3009e303b SEC-2299: Document Web MVC integration 2013-10-18 11:23:58 -05:00
Rob Winch 6ea95cc3a3 SEC-2094: Document Concurrency Support 2013-10-18 09:50:49 -05:00
Rob Winch 04b091c385 SEC-2369: PreAuthenticatedGrantedAuthoritiesUserDetailsService fix case to createUserDetails method 2013-10-17 16:18:43 -05:00
Rob Winch 15a63c58a7 SEC-2368: DebugFilter outputs headers and HTTP method 2013-10-17 14:49:45 -05:00
Rob Winch 604c26eb0d Shis simplifies the class hieararchy significantly.EC-2366: Extract AbstractRequestMatcherRegistry from AbstractRequestMatcherConfigurer
This simplifies the class hierarchy significantly.
2013-10-17 13:37:51 -05:00
Rob Winch 348e3a22b6 SEC-2365: registerAuthentication->configure 2013-10-16 13:59:56 -05:00
Rob Winch db3c626ac9 SEC-2281: Document Java Configuration 2013-10-16 10:44:35 -05:00
Rob Winch e3f58fd9d3 Polish guide 2013-10-16 10:44:16 -05:00
Rob Winch bbefc62a87 Fix Security Header's link to HttpServletResponse.setHeader 2013-10-15 16:56:44 -05:00
Rob Winch 730dcffe6d Fix crossrefs in footnotes 2013-10-15 16:50:26 -05:00
Rob Winch bf3b5459cd Fix Authors of manual 2013-10-15 16:22:27 -05:00
Rob Winch 1351c8bada SEC-2362: Clarify AbstractRememberMeServices loginSuccess javadoc 2013-10-15 13:53:23 -05:00
Rob Winch 0978c12c47 SEC-2361: Java Config Sampels use @Autowired AuthenticationManagerBuilder 2013-10-15 12:35:32 -05:00
Adrien be e50b587d60 SEC-2360: AbstractRememberMeServices provide message for Assert on key fieldd 2013-10-14 15:06:11 -05:00
Rob Winch 0b0e7dbea9 SEC-2359: Merge DefaultLoginPageViewFilter w/ DefaultLoginPageGeneratingFilter 2013-10-14 15:00:24 -05:00
Rob Winch 51171efa7a SEC-2357: Move *RequestMatcher to .matcher package 2013-10-14 11:55:56 -05:00
Rob Winch 45ad74a0bd SEC-2357: Fix package cycles 2013-10-14 11:15:16 -05:00
Rob Winch 14b9050616 SEC-2357: Move *RequestMatchers to .matchers package 2013-10-14 10:36:31 -05:00
Rob Winch f2b44e6beb Fix javadoc whitespace issue in HttpBasicConfigurer 2013-10-11 14:53:11 -05:00
Rob Winch 4ef0460ef6 SEC-2321: Improve Java Config defaults for JavaScript clients 2013-10-11 14:53:11 -05:00
Rob Winch 7d99436740 SEC-2358: Add RequestHeaderRequestMatcher 2013-10-11 14:53:11 -05:00
Rob Winch 0ac1176152 Polish RequestMatcher logging and toString 2013-10-07 15:45:42 -05:00
Rob Winch 76a8bbe98d SEC-2354: Add failOnMissingWebXml=false to sample pom.xml 2013-10-07 08:12:35 -05:00
Rob Winch cffbefadd1 SEC-2306: Fix Session Fixation logging race condition
Previously session fixation protection could output an incorrect warning
that session fixation protection did not work.

The code now synchronizes on WebUtils.getSessionMutex(..).
2013-10-06 17:13:40 -05:00
kazuki43zoo 611a97023d SEC-2352: HttpSessionCsrfTokenRepository lazy session creation 2013-10-06 16:44:18 -05:00
Rob Winch 5f10d84bf5 SEC-2303: WebSecurity sets the Bean resolver 2013-10-06 13:37:51 -05:00
Rob Winch d28058303b SEC-2349: Move FAQ into reference 2013-10-03 21:28:55 -05:00
Rob Winch dd1c2483b5 SEC-2349: Fix documentation tests 2013-10-03 17:03:17 -05:00
Rob Winch 4b43cf3f50 SEC-2349: Convert Reference to Asciidoctor 2013-10-03 14:15:09 -05:00
Rob Winch df5e034fc3 SEC-2282: Polish CSRF Documentation 2013-09-27 17:14:21 -05:00
Rob Winch 8087cde628 SEC-2331: Include Expires: 0 in xsd and appendix 2013-09-27 17:10:42 -05:00
Rob Winch 8fed90c26c SEC-2282: Add links for AccessDeniedHandler in CSRF doc 2013-09-27 16:44:34 -05:00
Rob Winch 3e95f1c12e SEC-2282: Polish CSRF Documentation 2013-09-27 16:41:06 -05:00
Rob Winch ee33a6deeb SEC-2285: Headers doc explicitly state default headers 2013-09-27 16:29:10 -05:00
Rob Winch 17efd25717 SEC-2331: Include Expires: 0 in security headers documentation 2013-09-27 16:13:40 -05:00
Rob Winch 06a0ec1a9f SEC-2285: Polish Security Headers Documentation
Explain why (passivity) XML Namespace doesn't enable security headers by
default.
2013-09-27 16:13:18 -05:00
Rob Winch 9bb283044f SEC-2282: Polish CSRF Documentation
Explain why (passivity) XML Namespace doesn't enable csrf protection by
default.
2013-09-27 16:06:25 -05:00
Rob Winch 614c94187e SEC-2305: GlobalMethodSecurityConfiguration autowire PermissionEvaluator
If a single PermissionEvaluator bean is found the
DefaultMethodSecurityExpressionHandler is configured with the
PermissionEvaluator. If multiple PermissionEvaluator beans are found, the
beans are ignored.
2013-09-27 15:46:45 -05:00
Rob Winch e696890e8e SEC-2151: Fix spring4Test 2013-09-27 12:36:43 -05:00
Rob Winch 61e6acb3f4 SEC-2151: AnnotationParameterNameDiscoverer support single annotated param
This makes sense since often times only a single argument is necessary in
the expression.
2013-09-27 11:53:39 -05:00
Rob Winch e5f034bdef SEC-2151: Fix tests 2013-09-27 11:52:32 -05:00
Rob Winch a09756745f SEC-2151: Support binding method arguments with Annotations
This allow utilizing method arguments for method access control on
interfaces prior to JDK 8.
2013-09-27 11:18:37 -05:00
Rob Winch fb0a8d19e8 SEC-2322: Support StandardReflectionParameterNameDiscoverer 2013-09-26 15:55:11 -05:00
Rob Winch cea0cf9260 SEC-2243: Remove additional Debug Filter 2013-09-26 11:38:16 -05:00
Rob Winch 56ce7d284c SEC-2336: WebSecurityConfigurerAdapter#registerAuthentication javadoc fixes 2013-09-26 09:08:25 -05:00
Rob Winch 1f3b812a66 SEC-2282: Polish CSRF Documentation 2013-09-26 08:58:39 -05:00
Rob Winch ef7cc40389 SEC-2282: Polish CSRF Documentation 2013-09-25 17:30:50 -05:00
Rob Winch d16106ef56 SEC-2309: Document CSRF multipart/form-data 2013-09-25 15:14:32 -05:00
Rob Winch b591881e95 SEC-2302: Provide beforeSpringSecurityFilterChain hook
This allows inserting filters before the springSecurityFilterChain.
2013-09-25 14:52:40 -05:00
Rob Winch 88f41cdf62 SEC-2341: Update to Gradle 1.8
Some dependencies were necessary to update due to issues with JUnit
integration.
2013-09-24 15:35:51 -05:00
Rob Winch a888ddf8b3 SEC-2307: JavaConfig RequestCache ignores favicon.ico 2013-09-24 11:30:37 -05:00
Rob Winch ddc0ef7ab3 SEC-2339: Added Logical (Or, And, Negated) RequestMatchers 2013-09-23 20:55:49 -05:00
Rob Winch 28fb6ba14b SEC-2328: Add hasAnyRole to ExpressionUrlAuthorizationConfiguration 2013-09-23 10:51:08 -05:00
Rob Winch b16c17f70b SEC-2301: Remove invalid import 2013-09-20 16:09:23 -05:00
Rob Winch a3d112979f SEC-2301: GlobalMethodSecurityConfiguration sets DefaultWebSecurityExpressionHandler BeanResolver 2013-09-20 15:53:58 -05:00
Rob Winch f294480e6b SEC-2329: JC @Autowire(required=false) AuthenticationTrustResolver
Java Configuration now allows optional @Autowire of
AuthenticationTrustResolver. In the WebSecurityConfigurerAdapter this is
done by populating AuthenticationTrustResolver as a sharedObject.
2013-09-20 15:28:50 -05:00
Rob Winch 788ba9a1fa SEC-2329: Allow injecting of AuthenticationTrustResolver 2013-09-20 15:26:52 -05:00
Rob Winch 7537dfc33a SEC-2304: rm duplicate MethodExpressionHandler from GlobalMethodSecurityConfiguration 2013-09-20 15:13:02 -05:00
Rob Winch 5082a04626 SEC-2311: LogoutConfigurer allows other HTTP methods if CSRF is disabled 2013-09-19 16:05:26 -05:00
Rob Winch 9133c33f1d SEC-2246: HttpSessionRequestCache.getRequest casts to RequestCache
The method getRequest use to cast to DefaultRequestCache, but this
is not necessary.

Now the cast is to SavedRequest.
2013-09-19 15:08:32 -05:00
Rob Winch 8f8c6169e8 SEC-2331: Cache Control now includes Expires: 0 2013-09-19 14:06:37 -05:00
Rob Winch c5c1419521 SEC-2332: GlobalMethodSecurityConfiguration includes proper voters
Previously GlobalMethodSecurityConfiguration did not include the correct
voters. This updates the code and the tests to ensure that the proper
voters are added. Note this got past testing previously due to all the
voters abstaining, so tests were added for ensuring that methods could also
be invoked sucessfully using the configured annotation.
2013-09-18 18:27:12 -05:00
Rob Winch d33b9e2854 SEC-2324: Update Spring Security tld version 2013-09-18 17:40:00 -05:00
Rob Winch c156716be8 Ensure single version of org.slf4j 2013-09-18 16:13:03 -05:00
Rob Winch 0114b457c0 SEC-2330: CacheControlHeadersWriter use a single header 2013-09-18 16:12:34 -05:00
Rob Winch 05a7c58daa SEC-2228: Change openid4j to optional in template.mf 2013-09-13 22:06:42 -07:00
Rob Winch e5804d323b SEC-2256: Fix intercept-url doc precidence statement
Previously the documentation incorrectly stated "If a request matches
multiple patterns, the method-specific match will take precedence
regardless of ordering."

This has now been removed and InterceptUrlConfigTests was added previously
to ensure this was true.
2013-09-13 22:02:52 -07:00
Rob Winch be8aad8306 SEC-2196: Demonstrate Method Security works on Generic methods 2013-09-13 16:20:43 -07:00
Rob Winch d9c9cd7f84 Remove warnings from defaultSpringSecurityContextSource 2013-09-13 15:54:21 -07:00
Rob Winch b4cbcee7f0 SEC-2308: DefaultSpringSecurityContextSource allow empty baseUrl 2013-09-13 15:53:35 -07:00
Rob Winch f6587c8697 SEC-2312: Update javadoc link to Spring 3.2.x 2013-09-13 15:34:30 -07:00
Rob Winch 32e9239fd2 SEC-2320: AuthenticationPrincipal can be null on invalid type
Previously a ClassCastException was thrown if the type was invalid. Now
a flag exists on AuthenticationPrincipal which indicates if a
ClassCastException should be thrown or not with the default being no error.
2013-09-13 15:21:13 -07:00
Rob Winch b22acd0768 SEC-2314: AbstractSecurityWebApplicationInitializer.getSessionTrackingModes() uses EnumSet 2013-09-13 14:44:44 -07:00
Rob Winch 53a0db6be1 SEC-2313: Gradle javadoc hotfix 2013-09-11 15:30:50 -07:00
Rob Winch 662bb24370 SEC-1937: Added test to demonstrate SEC-1937 was invalid 2013-09-11 15:10:42 -07:00
Rob Winch 3c82e63ded Formatting cleanup 2013-09-11 15:10:20 -07:00
Rob Winch 8e74407381 SEC-2296: HttpServletRequest.login should throw ServletException if already authenticated
See throws documentation at
http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#login%28java.lang.String,%20java.lang.String%29
2013-08-31 11:55:24 -05:00
Rob Winch e8ac11641b SEC-2297: Add DispatchType.ASYNC as default for AbstractSecurityWebApplicationInitializer 2013-08-31 11:39:57 -05:00
Rob Winch 7203faf34f SEC-2300: Update Spring LDAP version to 1.3.2.RELEASE 2013-08-31 11:26:43 -05:00
Rob Winch 3d2f23602f SEC-2294: Update Spring Version to 3.2.4.RELEASE 2013-08-31 11:26:43 -05:00
Rob Winch 43f4d01cf3 SEC-2292: Add test to assert CSRF bypass of methods is case sensitive
HTTP methods should be case sensitive, so add test to ensure that this is
the case http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1
2013-08-31 10:40:49 -05:00
Rob Winch 6e9fb7930b SEC-2298: Add AuthenticationPrincipalArgumentResolver 2013-08-30 17:06:40 -05:00
Rob Winch 98fe2322cd SEC-2095: Fix Servlet API doc ids 2013-08-30 13:10:32 -05:00
Scott Andrews fc16450344 Demonstrate rest.js CSRF support in reference docs
rest.js 0.9.4 added support for applying the CSRF header and token to
Ajax requests.
2013-08-30 12:21:32 -05:00
Rob Winch 246c632f3a SEC-2095: Document Servlet API support 2013-08-30 12:20:35 -05:00
Rob Winch 664220f304 SEC-2295: Remove error logging when Spring version equals Spring Security 2013-08-29 16:48:49 -05:00
Rob Winch 86340b8016 SEC-2283: Polish headers doc 2013-08-29 13:47:54 -05:00
Rob Winch ae368829f4 Tweak PermGen for tests 2013-08-28 13:30:25 -05:00
Rob Winch d89cf6db29 SEC-2283: Update headers documentation and tests 2013-08-28 12:35:40 -05:00
Rob Winch 4761614c9f SEC-2291: Fix internal links within reference
Instead of using xlink:href="# use linkend="
2013-08-28 09:12:27 -05:00
Rob Winch 69aac09e1d SEC-2285: Added headers to to reference 2013-08-28 08:58:45 -05:00
Rob Winch 9483226d02 SEC-2282: Polish CSRF doc 2013-08-27 17:16:32 -05:00
Rob Winch aca2e4ff3a SEC-2289: Add spring4Test 2013-08-27 16:43:10 -05:00
Rob Winch 086056f191 SEC-2289: Make compatible with Spring 4 as well
There are a few subtle changes in Spring 4 that this commit addresses
2013-08-27 16:43:10 -05:00
Rob Winch 26166ef6e8 SEC-2272: CsrfRequestDataValueProcessor support Spring 4 and Spring 3 2013-08-27 16:26:16 -05:00
Rob Winch 3f69847a4e SEC-2286: Log invalid CSRF tokens at debug level 2013-08-25 22:35:20 -05:00
Rob Winch d60108eaf6 SEC-2229: Add optional dependencies to spring-security-config
spring-tx and spring-jdbc aren't pulled in transitively from
spring-security-web now, so we must include them as optional dependencies.
2013-08-25 19:47:57 -05:00
Rob Winch 98bdd32ca0 SEC-2282: Add CSRF documentation to the reference manual 2013-08-25 19:00:04 -05:00
Rob Winch 33db440961 SEC-2129: AntPathRequestMatcher also supports case sensitive comparisions 2013-08-25 16:26:18 -05:00
Rob Winch 7d1d856729 SEC-2229: spring-security-web dependency polish
- remove direct dependency on spring-aop
- spring-tx and spring-jdbc optional
2013-08-25 15:52:17 -05:00
Rob Winch 18bd82e7d4 SEC-2131: Update doc to state session authentication sends 401 if no page 2013-08-25 11:37:23 -05:00
Rob Winch cd7055f725 SEC-2171: Include Information about pooling in Spring LDAP documentation 2013-08-25 11:27:50 -05:00
Rob Winch 7f2308f46c SEC-2146: Document AspectJ does not inherit annotations 2013-08-25 11:06:36 -05:00
Rob Winch 534989c8ea SEC-2103: Fix tests to verify debug logging instead of info 2013-08-25 10:05:22 -05:00
Rob Winch acb2b680d0 SEC-2103: Change log of no results to debug 2013-08-24 23:39:56 -05:00
Nick Williams f29505d657 SEC-2280: Fix SessionFixationConfigurer#changeSessionId Javadoc
The Javadoc for SessionFixationConfigurer#changeSessionId() was copied and pasted from
SessionFixationConfigurer#none() and never updated. It is incorrect. This commit fixes that.
2013-08-24 23:31:05 -05:00
Rob Winch 48283ec004 SEC-2276: Delay saving CsrfToken until token is accessed
This also removed the CsrfToken from the response headers to prevent the
token from being saved. If user's wish to return the CsrfToken in the
response headers, they should use the CsrfToken found on the request.
2013-08-24 23:31:01 -05:00
Rob Winch c131fb6379 SEC-2139: named-security-filter are all defined and ordered correctly 2013-08-24 15:18:22 -05:00
Rob Winch 03b235295e SEC-2270: Remove duplicate version from guides index 2013-08-23 14:13:12 -05:00
Rob Winch efa9f4db93 SEC-2108: Fix typo in ldap section of manual 2013-08-23 14:09:58 -05:00
Rob Winch 379cbd2a8b SEC-2274: Add ApplicationContext as HttpSecurity shared object 2013-08-21 16:50:09 -05:00
Rob Winch e8788f2657 SEC-2269: Fix markup for CSRF link 2013-08-21 10:08:39 -05:00
Rob Winch 17c2a18fee SEC-2269: Fix CSRF link in appendix 2013-08-21 10:01:19 -05:00
Rob Winch 0247dd124f SEC-2271: LogoutConfigurer#logoutUrl explains about CSRF 2013-08-21 06:58:09 -05:00
Rob Winch a3a432f7b6 SEC-2269: Fix additional links 2013-08-20 14:02:33 -05:00
Rob Winch 3b2156969d SEC-2269: Fix headers link 2013-08-20 10:06:00 -05:00
Rob Winch f707101fdb SEC-2269: Fix headers documentation 2013-08-20 10:03:31 -05:00
Rob Winch eb95c500f5 Remove dockbook-reference from guides 2013-08-20 10:02:55 -05:00
564 changed files with 30897 additions and 88641 deletions
+1
View File
@@ -19,3 +19,4 @@ build/
*.iws
.gradle/
atlassian-ide-plugin.xml
/samples
+1 -1
View File
@@ -14,5 +14,5 @@ dependencies {
"org.springframework:spring-context-support:$springVersion",
"org.springframework:spring-test:$springVersion"
testRuntime "hsqldb:hsqldb:$hsqlVersion"
testRuntime "org.hsqldb:hsqldb:$hsqlVersion"
}
+25 -31
View File
@@ -4,13 +4,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-acl</artifactId>
<version>3.2.0.RC1</version>
<version>3.2.0.RELEASE</version>
<name>spring-security-acl</name>
<description>spring-security-acl</description>
<url>http://springsource.org/spring-security</url>
<url>http://spring.io/spring-security</url>
<organization>
<name>SpringSource</name>
<url>http://springsource.org/</url>
<name>spring.io</name>
<url>http://spring.io/</url>
</organization>
<licenses>
<license>
@@ -23,13 +23,13 @@
<developer>
<id>rwinch</id>
<name>Rob Winch</name>
<email>rwinch@vmware.com</email>
<email>rwinch@gopivotal.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/SpringSource/spring-security</connection>
<developerConnection>scm:git:git://github.com/SpringSource/spring-security</developerConnection>
<url>https://github.com/SpringSource/spring-security</url>
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<build>
<plugins>
@@ -42,12 +42,6 @@
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>http://repo.springsource.org/libs-snapshot</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>aopalliance</groupId>
@@ -58,25 +52,25 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.2.0.RC1</version>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -88,13 +82,13 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -117,16 +111,10 @@
<version>0.9.29</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -135,10 +123,16 @@
<version>1.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.8.5</version>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -150,19 +144,19 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -98,7 +98,7 @@ public abstract class AclFormattingUtils {
}
private static String printBinary(int i, char on, char off) {
String s = Integer.toString(i, 2);
String s = Integer.toBinaryString(i);
String pattern = Permission.THIRTY_TWO_RESERVED_OFF;
String temp2 = pattern.substring(0, pattern.length() - s.length()) + s;
@@ -119,6 +119,9 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
* @param acl containing the ACEs to insert
*/
protected void createEntries(final MutableAcl acl) {
if(acl.getEntries().isEmpty()) {
return;
}
jdbcTemplate.batchUpdate(insertEntry,
new BatchPreparedStatementSetter() {
public int getBatchSize() {
@@ -124,4 +124,12 @@ public class AclFormattingUtilsTests extends TestCase {
Assert.assertEquals("............................xxxx", AclFormattingUtils.printBinary(15, 'x'));
}
public void testPrintBinaryNegative() {
Assert.assertEquals("*...............................", AclFormattingUtils.printBinary(0x80000000));
}
public void testPrintBinaryMinusOne() {
Assert.assertEquals("********************************", AclFormattingUtils.printBinary(0xffffffff));
}
}
@@ -50,7 +50,7 @@ public class BasicLookupStrategyTests {
//~ Methods ========================================================================================================
@BeforeClass
public static void initCacheManaer() {
cacheManager = new CacheManager();
cacheManager = CacheManager.create();
cacheManager.addCache(new Cache("basiclookuptestcache", 500, false, false, 30, 30));
}
@@ -40,7 +40,7 @@ public class EhCacheBasedAclCacheTests {
@BeforeClass
public static void initCacheManaer() {
cacheManager = new CacheManager();
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));
}
@@ -105,6 +105,7 @@ public class JdbcMutableAclServiceTests extends AbstractTransactionalJUnit4Sprin
jdbcTemplate.execute("drop table acl_object_identity");
jdbcTemplate.execute("drop table acl_class");
jdbcTemplate.execute("drop table acl_sid");
aclCache.clearCache();
}
@Test
+16 -22
View File
@@ -4,13 +4,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-aspects</artifactId>
<version>3.2.0.RC1</version>
<version>3.2.0.RELEASE</version>
<name>spring-security-aspects</name>
<description>spring-security-aspects</description>
<url>http://springsource.org/spring-security</url>
<url>http://spring.io/spring-security</url>
<organization>
<name>SpringSource</name>
<url>http://springsource.org/</url>
<name>spring.io</name>
<url>http://spring.io/</url>
</organization>
<licenses>
<license>
@@ -23,13 +23,13 @@
<developer>
<id>rwinch</id>
<name>Rob Winch</name>
<email>rwinch@vmware.com</email>
<email>rwinch@gopivotal.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/SpringSource/spring-security</connection>
<developerConnection>scm:git:git://github.com/SpringSource/spring-security</developerConnection>
<url>https://github.com/SpringSource/spring-security</url>
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<build>
<plugins>
@@ -42,35 +42,29 @@
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>http://repo.springsource.org/libs-snapshot</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.2.0.RC1</version>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -108,7 +102,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -120,7 +114,7 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.8.5</version>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -132,13 +126,13 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
+9
View File
@@ -0,0 +1,9 @@
apply plugin: 'maven-bom'
apply from: "$rootDir/gradle/maven-deployment.gradle"
generatePom.enabled = false
sonarRunner.skipProject = true
mavenBom {
projects = coreModuleProjects
}
+34 -9
View File
@@ -3,15 +3,14 @@ import groovy.text.SimpleTemplateEngine
buildscript {
repositories {
maven { url "http://repo.springsource.org/plugins-release" }
maven { url "http://dl.bintray.com/content/aalmiray/asciidoctor" }
maven { url "http://jcenter.bintray.com"}
}
dependencies {
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.3")
classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.7")
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.asciidoctor:asciidoctor-gradle-plugin:0.4.1")
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')
}
}
@@ -26,12 +25,15 @@ allprojects {
ext.releaseBuild = version.endsWith('RELEASE')
ext.snapshotBuild = version.endsWith('SNAPSHOT')
ext.springVersion = '3.2.6.RELEASE'
ext.spring4Version = '4.0.0.RELEASE'
group = 'org.springframework.security'
repositories {
maven { url "http://repo.springsource.org/libs-release" }
mavenCentral()
maven { url "http://repo.springsource.org/plugins-release" }
maven { url "http://repo.terracotta.org/maven2/" }
}
eclipse.project.name = "${project.name}-3.2.x"
@@ -52,7 +54,7 @@ sonarRunner {
}
// Set up different subproject lists for individual configuration
ext.javaProjects = subprojects.findAll { project -> project.name != 'docs' && project.name != 'faq' && project.name != 'manual' && project.name != 'guides' }
ext.javaProjects = subprojects.findAll { project -> project.name != 'docs' && project.name != 'manual' && project.name != 'guides' && project.name != 'spring-security-bom' }
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
@@ -77,7 +79,7 @@ configure(allprojects - javaProjects) {
}
}
configure(subprojects - coreModuleProjects) {
configure(subprojects - coreModuleProjects - project(':spring-security-samples-messages-jc') - project(':spring-security-bom')) {
tasks.findByPath("artifactoryPublish")?.enabled = false
sonarRunner {
skipProject = true
@@ -102,7 +104,22 @@ configure(coreModuleProjects) {
}
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'
}
}
}
dependencies {
jacoco "org.jacoco:org.jacoco.agent:0.6.2.201302030002:runtime"
}
@@ -112,6 +129,14 @@ 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) {
@@ -163,5 +188,5 @@ artifacts {
}
task wrapper(type: Wrapper) {
gradleVersion = '1.7'
gradleVersion = '1.10-rc-2'
}
+4
View File
@@ -12,6 +12,10 @@ repositories {
}
}
dependencies {
compile gradleApi()
}
// GAE
dependencies {
compile 'com.google.appengine:appengine-tools-sdk:1.4.2'
@@ -0,0 +1,19 @@
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.plugins.*
import org.gradle.api.tasks.*
import org.gradle.api.tasks.TaskAction
public class MavenBomPlugin implements Plugin<Project> {
static String MAVEN_BOM_TASK_NAME = "mavenBom"
public void apply(Project project) {
project.plugins.apply(JavaPlugin)
project.plugins.apply(MavenPlugin)
project.task(MAVEN_BOM_TASK_NAME, type: MavenBomTask, group: 'Generate', description: 'Configures the pom as a Maven Build of Materials (BOM)')
project.install.dependsOn project.mavenBom
}
}
@@ -0,0 +1,55 @@
import groovy.xml.MarkupBuilder
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.tasks.*
public class MavenBomTask extends DefaultTask {
Set<Project> projects
File bomFile
public MavenBomTask() {
this.group = "Generate"
this.description = "Generates a Maven Build of Materials (BOM). See http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Importing_Dependencies"
this.projects = project.subprojects
this.bomFile = project.file("${->project.buildDir}/maven-bom/${->project.name}-${->project.version}.txt")
}
@TaskAction
public void configureBom() {
project.configurations.archives.artifacts.clear()
bomFile.parentFile.mkdirs()
bomFile.write("Maven Build of Materials (BOM). See http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Importing_Dependencies")
project.artifacts {
// work around GRADLE-2406 by attaching text artifact
archives(bomFile)
}
project.install {
repositories.mavenInstaller {
pom.whenConfigured {
packaging = "pom"
withXml {
asNode().children().last() + {
delegate.dependencyManagement {
delegate.dependencies {
projects.sort { dep -> "$dep.group:$dep.name" }.each { p ->
delegate.dependency {
delegate.groupId(p.group)
delegate.artifactId(p.name)
delegate.version(p.version)
}
}
}
}
}
}
}
}
}
}
}
@@ -0,0 +1 @@
implementation-class=MavenBomPlugin
+17 -23
View File
@@ -4,13 +4,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
<version>3.2.0.RC1</version>
<version>3.2.0.RELEASE</version>
<name>spring-security-cas</name>
<description>spring-security-cas</description>
<url>http://springsource.org/spring-security</url>
<url>http://spring.io/spring-security</url>
<organization>
<name>SpringSource</name>
<url>http://springsource.org/</url>
<name>spring.io</name>
<url>http://spring.io/</url>
</organization>
<licenses>
<license>
@@ -23,13 +23,13 @@
<developer>
<id>rwinch</id>
<name>Rob Winch</name>
<email>rwinch@vmware.com</email>
<email>rwinch@gopivotal.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/SpringSource/spring-security</connection>
<developerConnection>scm:git:git://github.com/SpringSource/spring-security</developerConnection>
<url>https://github.com/SpringSource/spring-security</url>
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<build>
<plugins>
@@ -42,12 +42,6 @@
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>http://repo.springsource.org/libs-snapshot</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.jasig.cas.client</groupId>
@@ -58,31 +52,31 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.2.0.RC1</version>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.2.0.RC1</version>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -94,7 +88,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -126,7 +120,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -138,7 +132,7 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.8.5</version>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -150,7 +144,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -39,7 +39,7 @@ public class EhCacheBasedTicketCacheTests extends AbstractStatelessTicketCacheTe
//~ Methods ========================================================================================================
@BeforeClass
public static void initCacheManaer() {
cacheManager = new CacheManager();
cacheManager = CacheManager.create();
cacheManager.addCache(new Cache("castickets", 500, false, false, 30, 30));
}
+4 -6
View File
@@ -20,7 +20,9 @@ dependencies {
project(':spring-security-openid'),
"org.springframework:spring-web:$springVersion",
"org.springframework:spring-webmvc:$springVersion",
"org.aspectj:aspectjweaver:$aspectjVersion"
"org.aspectj:aspectjweaver:$aspectjVersion",
"org.springframework:spring-jdbc:$springVersion",
"org.springframework:spring-tx:$springVersion"
provided "org.apache.tomcat:tomcat-servlet-api:$servletApiVersion"
@@ -50,7 +52,7 @@ dependencies {
}
testRuntime "hsqldb:hsqldb:$hsqlVersion",
testRuntime "org.hsqldb:hsqldb:$hsqlVersion",
"cglib:cglib-nodep:2.2"
}
@@ -58,10 +60,6 @@ test {
inputs.file file("$rootDir/docs/manual/src/docbook/appendix-namespace.xml")
}
integrationTest {
systemProperties['apacheDSWorkDir'] = "${buildDir}/apacheDSWork"
}
rncToXsd {
rncDir = file('src/main/resources/org/springframework/security/config/')
xsdDir = rncDir
+51 -55
View File
@@ -4,13 +4,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>3.2.0.RC1</version>
<version>3.2.0.RELEASE</version>
<name>spring-security-config</name>
<description>spring-security-config</description>
<url>http://springsource.org/spring-security</url>
<url>http://spring.io/spring-security</url>
<organization>
<name>SpringSource</name>
<url>http://springsource.org/</url>
<name>spring.io</name>
<url>http://spring.io/</url>
</organization>
<licenses>
<license>
@@ -23,13 +23,13 @@
<developer>
<id>rwinch</id>
<name>Rob Winch</name>
<email>rwinch@vmware.com</email>
<email>rwinch@gopivotal.com</email>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/SpringSource/spring-security</connection>
<developerConnection>scm:git:git://github.com/SpringSource/spring-security</developerConnection>
<url>https://github.com/SpringSource/spring-security</url>
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<build>
<plugins>
@@ -42,12 +42,6 @@
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>http://repo.springsource.org/libs-snapshot</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>aopalliance</groupId>
@@ -58,31 +52,31 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.2.0.RC1</version>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -108,35 +102,49 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
<version>3.2.0.RC1</version>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-openid</artifactId>
<version>3.2.0.RC1</version>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.2.0.RC1</version>
<version>3.2.0.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
@@ -158,12 +166,6 @@
<version>0.9.29</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
@@ -173,7 +175,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -242,10 +244,16 @@
<version>4.1.0.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.8.5</version>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -263,37 +271,37 @@
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.4.12</version>
<version>1.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-support</artifactId>
<version>1.4.12</version>
<version>1.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>1.4.12</version>
<version>1.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.4.12</version>
<version>1.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4-common</artifactId>
<version>1.4.12</version>
<version>1.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-reflect</artifactId>
<version>1.4.12</version>
<version>1.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -311,43 +319,31 @@
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap-core</artifactId>
<version>1.3.1.RELEASE</version>
<version>1.3.2.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
<version>3.2.0.RC1</version>
<version>3.2.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>3.2.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.3.RELEASE</version>
<version>3.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -53,8 +53,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
@Configuration
static class DefaultLdapConfig extends BaseLdapProviderConfig {
protected void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
@@ -71,7 +70,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
@Configuration
static class GroupRolesConfig extends BaseLdapProviderConfig {
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
@@ -89,8 +88,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
@Configuration
static class GroupSearchConfig extends BaseLdapProviderConfig {
protected void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
@@ -108,8 +106,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
@Configuration
static class RolePrefixConfig extends BaseLdapProviderConfig {
protected void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
@@ -128,8 +125,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
@Configuration
static class BindAuthenticationConfig extends BaseLdapServerConfig {
protected void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
@@ -154,15 +150,6 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp
@Configuration
static abstract class BaseLdapProviderConfig {
@Bean
public AuthenticationManager authenticationManager() {
AuthenticationManagerBuilder registry = new AuthenticationManagerBuilder();
registerAuthentication(registry);
return registry.build();
}
protected abstract void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception;
@Bean
public BaseLdapPathContextSource contextSource() throws Exception {
@@ -31,8 +31,7 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
@Configuration
@EnableWebSecurity
static class LdapAuthenticationProviderConfig extends WebSecurityConfigurerAdapter {
protected void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.groupSearchBase("ou=groups")
@@ -43,8 +42,7 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
@Configuration
@EnableWebSecurity
static class CustomLdapAuthenticationProviderConfig extends WebSecurityConfigurerAdapter {
protected void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.groupRoleAttribute("cn") // ldap-authentication-provider@group-role-attribute
@@ -70,8 +68,7 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
@Configuration
@EnableWebSecurity
static class PasswordCompareLdapConfig extends WebSecurityConfigurerAdapter {
protected void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.groupSearchBase("ou=groups")
@@ -12,7 +12,10 @@
*/
package org.springframework.security.config.ldap;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.net.ServerSocket;
import org.junit.After;
import org.junit.Test;
@@ -50,10 +53,11 @@ public class LdapServerBeanDefinitionParserTests {
}
@Test
public void useOfUrlAttributeCreatesCorrectContextSource() {
public void useOfUrlAttributeCreatesCorrectContextSource() throws Exception {
int port = getDefaultPort();
// Create second "server" with a url pointing at embedded one
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='33388'/>" +
"<ldap-server ldif='classpath:test-server.ldif' id='blah' url='ldap://127.0.0.1:33388/dc=springframework,dc=org' />");
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='" + port + "'/>" +
"<ldap-server ldif='classpath:test-server.ldif' id='blah' url='ldap://127.0.0.1:" + port + "/dc=springframework,dc=org' />");
// Check the default context source is still there.
appCtx.getBean(BeanIds.CONTEXT_SOURCE);
@@ -83,4 +87,16 @@ public class LdapServerBeanDefinitionParserTests {
assertEquals("classpath*:*.ldif", ReflectionTestUtils.getField(dsContainer, "ldifResources"));
}
private int getDefaultPort() throws IOException {
ServerSocket server = null;
try {
server = new ServerSocket(0);
return server.getLocalPort();
} finally {
try {
server.close();
} catch(IOException e) {}
}
}
}
@@ -66,13 +66,6 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
private ObjectPostProcessor<Object> objectPostProcessor;
/**
* Creates a new instance without post processing
*/
protected AbstractConfiguredSecurityBuilder() {
this(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR);
}
/***
* Creates a new instance with the provided {@link ObjectPostProcessor}.
* This post processor must support Object since there are many types of
@@ -39,7 +39,7 @@ public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
object = doBuild();
return object;
}
throw new IllegalStateException("This object has already been built");
throw new AlreadyBuiltException("This object has already been built");
}
/**
@@ -0,0 +1,31 @@
/*
* 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;
/**
* Thrown when {@link AbstractSecurityBuilder#build()} is two or more times.
*
* @author Rob Winch
* @since 3.2
*/
public class AlreadyBuiltException extends IllegalStateException {
public AlreadyBuiltException(String message) {
super(message);
}
private static final long serialVersionUID = -5891004752785553015L;
}
@@ -39,13 +39,4 @@ public interface ObjectPostProcessor<T> {
* @return the initialized version of the object
*/
<O extends T> O postProcess(O object);
/**
* A do nothing implementation of the {@link ObjectPostProcessor}
*/
ObjectPostProcessor<Object> QUIESCENT_POSTPROCESSOR = new ObjectPostProcessor<Object>() {
public <T> T postProcess(T object) {
return object;
}
};
}
}
@@ -29,7 +29,7 @@ public interface SecurityBuilder<O> {
* Builds the object and returns it or null.
*
* @return the Object to be built or null if the implementation allows it.
* @throws Exception if an error occured when building the Object
* @throws Exception if an error occurred when building the Object
*/
O build() throws Exception;
}
@@ -18,6 +18,8 @@ package org.springframework.security.config.annotation.authentication.builders;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.AuthenticationEventPublisher;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
@@ -45,6 +47,7 @@ import org.springframework.util.Assert;
* @since 3.2
*/
public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuilder<AuthenticationManager, AuthenticationManagerBuilder> implements ProviderManagerBuilder<AuthenticationManagerBuilder> {
private final Log logger = LogFactory.getLog(getClass());
private AuthenticationManager parentAuthenticationManager;
private List<AuthenticationProvider> authenticationProviders = new ArrayList<AuthenticationProvider>();
@@ -218,6 +221,10 @@ public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuil
@Override
protected ProviderManager performBuild() throws Exception {
if(authenticationProviders.isEmpty() && parentAuthenticationManager == null) {
logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
return null;
}
ProviderManager providerManager = new ProviderManager(authenticationProviders, parentAuthenticationManager);
if(eraseCredentials != null) {
providerManager.setEraseCredentialsAfterAuthentication(eraseCredentials);
@@ -52,7 +52,16 @@ final class AutowireBeanFactoryObjectPostProcessor implements ObjectPostProcesso
*/
@SuppressWarnings("unchecked")
public <T> T postProcess(T object) {
T result = (T) autowireBeanFactory.initializeBean(object, null);
if(object == null) {
return null;
}
T result = null;
try {
result = (T) autowireBeanFactory.initializeBean(object, object.toString());
} catch (RuntimeException e) {
Class<?> type = object.getClass();
throw new RuntimeException("Could not postProcess " + object + " of type " + type, e);
}
if(result instanceof DisposableBean) {
disposableBeans.add((DisposableBean) result);
}
@@ -39,7 +39,9 @@ import org.springframework.core.type.AnnotationMetadata;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.AfterInvocationProvider;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource;
import org.springframework.security.access.annotation.Jsr250Voter;
import org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.ExpressionBasedAnnotationAttributeFactory;
@@ -61,6 +63,7 @@ import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.access.vote.AuthenticatedVoter;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
@@ -84,8 +87,9 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
throw new IllegalStateException(ObjectPostProcessor.class.getName()+ " is a required bean. Ensure you have used @"+EnableGlobalMethodSecurity.class.getName());
}
};
private DefaultMethodSecurityExpressionHandler defaultMethodExpressionHandler = new DefaultMethodSecurityExpressionHandler();
private AuthenticationManager authenticationManager;
private AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR);
private AuthenticationManagerBuilder auth;
private boolean disableAuthenticationRegistry;
private AnnotationAttributes enableMethodSecurity;
private MethodSecurityExpressionHandler expressionHandler;
@@ -178,25 +182,33 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
List<AccessDecisionVoter> decisionVoters = new ArrayList<AccessDecisionVoter>();
ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
expressionAdvice.setExpressionHandler(getExpressionHandler());
decisionVoters.add(new PreInvocationAuthorizationAdviceVoter(
if(prePostEnabled()) {
decisionVoters.add(new PreInvocationAuthorizationAdviceVoter(
expressionAdvice));
}
if(jsr250Enabled()) {
decisionVoters.add(new Jsr250Voter());
}
decisionVoters.add(new RoleVoter());
decisionVoters.add(new AuthenticatedVoter());
return new AffirmativeBased(decisionVoters);
}
/**
* Provide a {@link MethodSecurityExpressionHandler} that is
* registered with the {@link ExpressionBasedPreInvocationAdvice}. The default is
* {@link DefaultMethodSecurityExpressionHandler}
* Provide a {@link MethodSecurityExpressionHandler} that is registered with
* the {@link ExpressionBasedPreInvocationAdvice}. The default is
* {@link DefaultMethodSecurityExpressionHandler} which optionally will
* Autowire an {@link AuthenticationTrustResolver}.
*
* <p>Subclasses may override this method to provide a custom {@link MethodSecurityExpressionHandler}</p>
* <p>
* Subclasses may override this method to provide a custom
* {@link MethodSecurityExpressionHandler}
* </p>
*
* @return
*/
protected MethodSecurityExpressionHandler expressionHandler() {
return new DefaultMethodSecurityExpressionHandler();
protected MethodSecurityExpressionHandler createExpressionHandler() {
return defaultMethodExpressionHandler;
}
/**
@@ -206,7 +218,7 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
*/
protected final MethodSecurityExpressionHandler getExpressionHandler() {
if(expressionHandler == null) {
expressionHandler = expressionHandler();
expressionHandler = createExpressionHandler();
}
return expressionHandler;
}
@@ -224,8 +236,8 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
/**
* Allows providing a custom {@link AuthenticationManager}. The default is
* to use any authentication mechanisms registered by {@link #registerAuthentication(AuthenticationManagerBuilder)}. If
* {@link #registerAuthentication(AuthenticationManagerBuilder)} was not overriden, then an {@link AuthenticationManager}
* to use any authentication mechanisms registered by {@link #configure(AuthenticationManagerBuilder)}. If
* {@link #configure(AuthenticationManagerBuilder)} was not overridden, then an {@link AuthenticationManager}
* is attempted to be autowired by type.
*
* @return
@@ -233,9 +245,9 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
protected AuthenticationManager authenticationManager() throws Exception {
if(authenticationManager == null) {
DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
auth = new AuthenticationManagerBuilder(objectPostProcessor);
auth.authenticationEventPublisher(eventPublisher);
auth.objectPostProcessor(objectPostProcessor);
registerAuthentication(auth);
configure(auth);
if(!disableAuthenticationRegistry) {
authenticationManager = auth.build();
}
@@ -255,13 +267,13 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
/**
* Sub classes can override this method to register different types of authentication. If not overridden,
* {@link #registerAuthentication(AuthenticationManagerBuilder)} will attempt to autowire by type.
* {@link #configure(AuthenticationManagerBuilder)} will attempt to autowire by type.
*
* @param auth the {@link AuthenticationManagerBuilder} used to register different authentication mechanisms for the
* global method security.
* @throws Exception
*/
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
this.disableAuthenticationRegistry = true;
}
@@ -277,7 +289,7 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
public MethodSecurityMetadataSource methodSecurityMetadataSource() {
List<MethodSecurityMetadataSource> sources = new ArrayList<MethodSecurityMetadataSource>();
ExpressionBasedAnnotationAttributeFactory attributeFactory = new ExpressionBasedAnnotationAttributeFactory(
methodExpressionHandler());
getExpressionHandler());
MethodSecurityMetadataSource customMethodSecurityMetadataSource = customMethodSecurityMetadataSource();
if (customMethodSecurityMetadataSource != null) {
sources.add(customMethodSecurityMetadataSource);
@@ -295,16 +307,6 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
return new DelegatingMethodSecurityMetadataSource(sources);
}
/**
* Creates the {@link MethodSecurityExpressionHandler} to be used.
*
* @return
*/
@Bean
public MethodSecurityExpressionHandler methodExpressionHandler() {
return new DefaultMethodSecurityExpressionHandler();
}
/**
* Creates the {@link PreInvocationAuthorizationAdvice} to be used. The
* default is {@link ExpressionBasedPreInvocationAdvice}.
@@ -314,7 +316,7 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
@Bean
public PreInvocationAuthorizationAdvice preInvocationAuthorizationAdvice() {
ExpressionBasedPreInvocationAdvice preInvocationAdvice = new ExpressionBasedPreInvocationAdvice();
preInvocationAdvice.setExpressionHandler(methodExpressionHandler());
preInvocationAdvice.setExpressionHandler(getExpressionHandler());
return preInvocationAdvice;
}
@@ -344,6 +346,11 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
.fromMap(annotationAttributes);
}
@Autowired(required = false)
public void setAuthenticationTrustResolver(AuthenticationTrustResolver trustResolver) {
this.defaultMethodExpressionHandler.setTrustResolver(trustResolver);
}
@Autowired
public void setApplicationContext(ApplicationContext context) {
this.context = context;
@@ -352,6 +359,15 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
@Autowired(required=false)
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
this.objectPostProcessor = objectPostProcessor;
this.defaultMethodExpressionHandler = objectPostProcessor.postProcess(defaultMethodExpressionHandler);
}
@Autowired(required = false)
public void setPermissionEvaluator(List<PermissionEvaluator> permissionEvaluators) {
if(permissionEvaluators.size() != 1) {
logger.debug("Not autwiring PermissionEvaluator since size != 1. Got " + permissionEvaluators);
}
this.defaultMethodExpressionHandler.setPermissionEvaluator(permissionEvaluators.get(0));
}
@SuppressWarnings("unchecked")
@@ -20,33 +20,29 @@ import java.util.Arrays;
import java.util.List;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.SecurityBuilder;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.AbstractRequestMatcherMappingConfigurer;
import org.springframework.security.web.util.AntPathRequestMatcher;
import org.springframework.security.web.util.AnyRequestMatcher;
import org.springframework.security.web.util.RegexRequestMatcher;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.security.config.annotation.web.configurers.AbstractConfigAttributeRequestMatcherRegistry;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
/**
* A base class for registering {@link RequestMatcher}'s. For example, it might allow for specifying which
* {@link RequestMatcher} require a certain level of authorization.
*
*
* @param <B> The Builder that is building Object O and is configured by this {@link AbstractRequestMatcherMappingConfigurer}
* @param <C> The object that is returned or Chained after creating the RequestMatcher
* @param <O> The Object being built by Builder B
*
* @author Rob Winch
* @since 3.2
*/
public abstract class AbstractRequestMatcherConfigurer<B extends SecurityBuilder<O>,C,O> extends SecurityConfigurerAdapter<O,B> {
private static final RequestMatcher ANY_REQUEST = new AnyRequestMatcher();
public abstract class AbstractRequestMatcherRegistry<C> {
private static final RequestMatcher ANY_REQUEST = AnyRequestMatcher.INSTANCE;
/**
* 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.AntPathRequestMatcher}
* @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}
@@ -56,10 +52,10 @@ public abstract class AbstractRequestMatcherConfigurer<B extends SecurityBuilder
}
/**
* Maps a {@link List} of {@link org.springframework.security.web.util.AntPathRequestMatcher} instances.
* Maps a {@link List} of {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher} instances.
*
* @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.AntPathRequestMatcher}
* @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}
@@ -69,10 +65,10 @@ public abstract class AbstractRequestMatcherConfigurer<B extends SecurityBuilder
}
/**
* Maps a {@link List} of {@link org.springframework.security.web.util.AntPathRequestMatcher} instances that do
* Maps a {@link List} of {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher} instances that do
* not care which {@link HttpMethod} is used.
*
* @param antPatterns the ant patterns to create {@link org.springframework.security.web.util.AntPathRequestMatcher}
* @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}
@@ -82,11 +78,11 @@ public abstract class AbstractRequestMatcherConfigurer<B extends SecurityBuilder
}
/**
* Maps a {@link List} of {@link org.springframework.security.web.util.RegexRequestMatcher} instances.
* Maps a {@link List} of {@link org.springframework.security.web.util.matcher.RegexRequestMatcher} instances.
*
* @param method the {@link HttpMethod} to use or {@code null} for any {@link HttpMethod}.
* @param regexPatterns the regular expressions to create
* {@link org.springframework.security.web.util.RegexRequestMatcher} from
* {@link org.springframework.security.web.util.matcher.RegexRequestMatcher} from
*
* @return the object that is chained after creating the {@link RequestMatcher}
*/
@@ -96,11 +92,11 @@ public abstract class AbstractRequestMatcherConfigurer<B extends SecurityBuilder
}
/**
* Create a {@link List} of {@link org.springframework.security.web.util.RegexRequestMatcher} instances that do not
* Create a {@link List} of {@link org.springframework.security.web.util.matcher.RegexRequestMatcher} instances that do not
* specify an {@link HttpMethod}.
*
* @param regexPatterns the regular expressions to create
* {@link org.springframework.security.web.util.RegexRequestMatcher} from
* {@link org.springframework.security.web.util.matcher.RegexRequestMatcher} from
*
* @return the object that is chained after creating the {@link RequestMatcher}
*/
@@ -109,7 +105,7 @@ public abstract class AbstractRequestMatcherConfigurer<B extends SecurityBuilder
}
/**
* Associates a list of {@link RequestMatcher} instances with the {@link AbstractRequestMatcherMappingConfigurer}
* Associates a list of {@link RequestMatcher} instances with the {@link AbstractConfigAttributeRequestMatcherRegistry}
*
* @param requestMatchers the {@link RequestMatcher} instances
*
@@ -152,7 +152,7 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends S
* <li>{@link UsernamePasswordAuthenticationFilter}</li>
* <li>{@link ConcurrentSessionFilter}</li>
* <li>{@link OpenIDAuthenticationFilter}</li>
* <li>{@link DefaultLoginPageViewFilter}</li>
* <li>{@link DefaultLoginPageGeneratingFilter}</li>
* <li>{@link ConcurrentSessionFilter}</li>
* <li>{@link DigestAuthenticationFilter}</li>
* <li>{@link BasicAuthenticationFilter}</li>
@@ -1,191 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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.builders;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.UrlUtils;
/**
* Spring Security debugging filter.
* <p>
* Logs information (such as session creation) to help the user understand how requests are being handled
* by Spring Security and provide them with other relevant information (such as when sessions are being created).
*
*
* @author Luke Taylor
* @author Rob Winch
* @since 3.1
*/
class DebugFilter implements Filter {
private static final String ALREADY_FILTERED_ATTR_NAME = DebugFilter.class.getName().concat(".FILTERED");
private final FilterChainProxy fcp;
private final Logger logger = new Logger();
public DebugFilter(FilterChainProxy fcp) {
this.fcp = fcp;
}
public final void doFilter(ServletRequest srvltRequest, ServletResponse srvltResponse, FilterChain filterChain)
throws ServletException, IOException {
if (!(srvltRequest instanceof HttpServletRequest) || !(srvltResponse instanceof HttpServletResponse)) {
throw new ServletException("DebugFilter just supports HTTP requests");
}
HttpServletRequest request = (HttpServletRequest) srvltRequest;
HttpServletResponse response = (HttpServletResponse) srvltResponse;
List<Filter> filters = getFilters(request);
logger.log("Request received for '" + UrlUtils.buildRequestUrl(request) + "':\n\n" +
request + "\n\n" +
"servletPath:" + request.getServletPath() + "\n" +
"pathInfo:" + request.getPathInfo() + "\n\n" +
formatFilters(filters));
if (request.getAttribute(ALREADY_FILTERED_ATTR_NAME) == null) {
invokeWithWrappedRequest(request, response, filterChain);
} else {
fcp.doFilter(request, response, filterChain);
}
}
private void invokeWithWrappedRequest(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
request.setAttribute(ALREADY_FILTERED_ATTR_NAME, Boolean.TRUE);
request = new DebugRequestWrapper(request);
try {
fcp.doFilter(request, response, filterChain);
}
finally {
request.removeAttribute(ALREADY_FILTERED_ATTR_NAME);
}
}
String formatFilters(List<Filter> filters) {
StringBuilder sb = new StringBuilder();
sb.append("Security filter chain: ");
if (filters == null) {
sb.append("no match");
} else if (filters.isEmpty()) {
sb.append("[] empty (bypassed by security='none') ");
} else {
sb.append("[\n");
for (Filter f : filters) {
sb.append(" ").append(f.getClass().getSimpleName()).append("\n");
}
sb.append("]");
}
return sb.toString();
}
private List<Filter> getFilters(HttpServletRequest request) {
for (SecurityFilterChain chain : fcp.getFilterChains()) {
if (chain.matches(request)) {
return chain.getFilters();
}
}
return null;
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {
}
}
class DebugRequestWrapper extends HttpServletRequestWrapper {
private static final Logger logger = new Logger();
public DebugRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public HttpSession getSession() {
boolean sessionExists = super.getSession(false) != null;
HttpSession session = super.getSession();
if (!sessionExists) {
logger.log("New HTTP session created: " + session.getId(), true);
}
return session;
}
@Override
public HttpSession getSession(boolean create) {
if (!create) {
return super.getSession(create);
}
return getSession();
}
}
/**
* Controls output for the Spring Security debug feature.
*
* @author Luke Taylor
* @since 3.1
*/
final class Logger {
final static Log logger = LogFactory.getLog("Spring Security Debugger");
void log(String message) {
log(message, false);
}
void log(String message, boolean dumpStack) {
StringBuilder output = new StringBuilder(256);
output.append("\n\n************************************************************\n\n");
output.append(message).append("\n");
if (dumpStack) {
StringWriter os = new StringWriter();
new Exception().printStackTrace(new PrintWriter(os));
StringBuffer buffer = os.getBuffer();
// Remove the exception in case it scares people.
int start = buffer.indexOf("java.lang.Exception");
buffer.replace(start, start + 19, "");
output.append("\nCall stack: \n").append(os.toString());
}
output.append("\n\n************************************************************\n\n");
logger.info(output.toString());
}
}
@@ -32,7 +32,7 @@ import org.springframework.security.web.authentication.preauth.AbstractPreAuthen
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter;
import org.springframework.security.web.authentication.switchuser.SwitchUserFilter;
import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFilter;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.authentication.www.DigestAuthenticationFilter;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
@@ -86,7 +86,7 @@ final class FilterComparator implements Comparator<Filter>, Serializable {
order += STEP;
filterToOrder.put("org.springframework.security.openid.OpenIDAuthenticationFilter", order);
order += STEP;
put(DefaultLoginPageViewFilter.class, order);
put(DefaultLoginPageGeneratingFilter.class, order);
order += STEP;
put(ConcurrentSessionFilter.class, order);
order += STEP;
@@ -31,7 +31,7 @@ import org.springframework.security.config.annotation.SecurityBuilder;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.AbstractRequestMatcherConfigurer;
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
@@ -63,10 +63,11 @@ import org.springframework.security.web.PortMapper;
import org.springframework.security.web.PortMapperImpl;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.security.web.util.AntPathRequestMatcher;
import org.springframework.security.web.util.AnyRequestMatcher;
import org.springframework.security.web.util.RegexRequestMatcher;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
/**
@@ -97,7 +98,7 @@ import org.springframework.util.Assert;
* }
*
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
* protected void configure(AuthenticationManagerBuilder auth) throws Exception {
* auth
* .inMemoryAuthentication()
* .withUser(&quot;user&quot;)
@@ -114,7 +115,7 @@ import org.springframework.util.Assert;
public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain,HttpSecurity> implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> {
private final RequestMatcherConfigurer requestMatcherConfigurer = new RequestMatcherConfigurer();
private List<Filter> filters = new ArrayList<Filter>();
private RequestMatcher requestMatcher = new AnyRequestMatcher();
private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE;
private FilterComparator comparitor = new FilterComparator();
/**
@@ -156,7 +157,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* }
*
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
* protected void configure(AuthenticationManagerBuilder auth) throws Exception {
* auth
* .inMemoryAuthentication()
* // the username must match the OpenID of the user you are
@@ -239,6 +240,75 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
return getOrApply(new OpenIDLoginConfigurer<HttpSecurity>());
}
/**
* Adds the Security headers to the response. This is activated by default
* when using {@link WebSecurityConfigurerAdapter}'s default constructor.
* Only invoking the {@link #headers()} without invoking additional methods
* on it, or accepting the default provided by
* {@link WebSecurityConfigurerAdapter}, is the equivalent of:
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter {
*
* &#064;Override
* protected void configure(HttpSecurity http) throws Exception {
* http
* .headers()
* .contentTypeOptions();
* .xssProtection()
* .cacheControl()
* .httpStrictTransportSecurity()
* .frameOptions()
* .and()
* ...;
* }
* }
* </pre>
*
* You can disable the headers using the following:
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter {
*
* &#064;Override
* protected void configure(HttpSecurity http) throws Exception {
* http
* .headers().disable()
* ...;
* }
* }
* </pre>
*
* You can enable only a few of the headers by invoking the appropriate
* methods on {@link #headers()} result. For example, the following will
* enable {@link HeadersConfigurer#cacheControl()} and
* {@link HeadersConfigurer#frameOptions()} only.
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter {
*
* &#064;Override
* protected void configure(HttpSecurity http) throws Exception {
* http
* .headers()
* .cacheControl()
* .frameOptions()
* .and()
* ...;
* }
* }
* </pre>
*
* @return
* @throws Exception
* @see {@link HeadersConfigurer}
*/
public HeadersConfigurer<HttpSecurity> headers() throws Exception {
return getOrApply(new HeadersConfigurer<HttpSecurity>());
}
@@ -275,7 +345,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* }
*
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth)
* protected void configure(AuthenticationManagerBuilder auth)
* throws Exception {
* auth.
* inMemoryAuthentication()
@@ -347,7 +417,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* }
*
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
* protected void configure(AuthenticationManagerBuilder auth) throws Exception {
* auth
* .inMemoryAuthentication()
* .withUser(&quot;user&quot;)
@@ -489,7 +559,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* public class RememberMeSecurityConfig extends WebSecurityConfigurerAdapter {
*
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth)
* protected void configure(AuthenticationManagerBuilder auth)
* throws Exception {
* auth
* .inMemoryAuthentication()
@@ -545,7 +615,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* }
*
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth)
* protected void configure(AuthenticationManagerBuilder auth)
* throws Exception {
* auth
* .inMemoryAuthentication()
@@ -580,7 +650,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* }
*
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth)
* protected void configure(AuthenticationManagerBuilder auth)
* throws Exception {
* auth
* .inMemoryAuthentication()
@@ -610,8 +680,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @return
* @throws Exception
*/
public ExpressionUrlAuthorizationConfigurer<HttpSecurity> authorizeRequests() throws Exception {
return getOrApply(new ExpressionUrlAuthorizationConfigurer<HttpSecurity>());
public ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequests() throws Exception {
return getOrApply(new ExpressionUrlAuthorizationConfigurer<HttpSecurity>()).getRegistry();
}
/**
@@ -664,7 +734,23 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
/**
* Adds CSRF support
* Adds CSRF support. This is activated by default when using
* {@link WebSecurityConfigurerAdapter}'s default constructor. You can
* disable it using:
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter {
*
* &#064;Override
* protected void configure(HttpSecurity http) throws Exception {
* http
* .csrf().disable()
* ...;
* }
* }
* </pre>
*
* @return the {@link ServletApiConfigurer} for further customizations
* @throws Exception
@@ -711,7 +797,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* }
*
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth)
* protected void configure(AuthenticationManagerBuilder auth)
* throws Exception {
* auth
* .inMemoryAuthentication()
@@ -759,7 +845,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* }
*
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth)
* protected void configure(AuthenticationManagerBuilder auth)
* throws Exception {
* auth
* .inMemoryAuthentication()
@@ -792,7 +878,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* }
*
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth)
* protected void configure(AuthenticationManagerBuilder auth)
* throws Exception {
* auth
* .inMemoryAuthentication()
@@ -837,7 +923,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* }
*
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth)
* protected void configure(AuthenticationManagerBuilder auth)
* throws Exception {
* auth
* .inMemoryAuthentication()
@@ -870,7 +956,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* }
*
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth)
* protected void configure(AuthenticationManagerBuilder auth)
* throws Exception {
* auth
* .inMemoryAuthentication()
@@ -919,7 +1005,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* }
*
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth)
* protected void configure(AuthenticationManagerBuilder auth)
* throws Exception {
* auth
* .inMemoryAuthentication()
@@ -934,8 +1020,8 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @return the {@link ChannelSecurityConfigurer} for further customizations
* @throws Exception
*/
public ChannelSecurityConfigurer<HttpSecurity> requiresChannel() throws Exception {
return getOrApply(new ChannelSecurityConfigurer<HttpSecurity>());
public ChannelSecurityConfigurer<HttpSecurity>.ChannelRequestMatcherRegistry requiresChannel() throws Exception {
return getOrApply(new ChannelSecurityConfigurer<HttpSecurity>()).getRegistry();
}
/**
@@ -962,7 +1048,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* }
*
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth)
* protected void configure(AuthenticationManagerBuilder auth)
* throws Exception {
* auth
* .inMemoryAuthentication()
@@ -1077,7 +1163,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* }
*
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth)
* protected void configure(AuthenticationManagerBuilder auth)
* throws Exception {
* auth
* .inMemoryAuthentication()
@@ -1108,7 +1194,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* }
*
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth)
* protected void configure(AuthenticationManagerBuilder auth)
* throws Exception {
* auth
* .inMemoryAuthentication()
@@ -1141,7 +1227,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* }
*
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth)
* protected void configure(AuthenticationManagerBuilder auth)
* throws Exception {
* auth
* .inMemoryAuthentication()
@@ -1226,7 +1312,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
* @author Rob Winch
* @since 3.2
*/
public final class RequestMatcherConfigurer extends AbstractRequestMatcherConfigurer<HttpSecurity,RequestMatcherConfigurer,DefaultSecurityFilterChain> {
public final class RequestMatcherConfigurer extends AbstractRequestMatcherRegistry<RequestMatcherConfigurer> {
protected RequestMatcherConfigurer chainRequestMatchers(List<RequestMatcher> requestMatchers) {
requestMatcher(new OrRequestMatcher(requestMatchers));
@@ -1261,29 +1347,4 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
}
return apply(configurer);
}
/**
* Internal {@link RequestMatcher} instance used by {@link RequestMatcher}
* that will match if any of the passed in {@link RequestMatcher} instances
* match.
*
* @author Rob Winch
* @since 3.2
*/
private static final class OrRequestMatcher implements RequestMatcher {
private final List<RequestMatcher> requestMatchers;
private OrRequestMatcher(List<RequestMatcher> requestMatchers) {
this.requestMatchers = requestMatchers;
}
public boolean matches(HttpServletRequest request) {
for(RequestMatcher matcher : requestMatchers) {
if(matcher.matches(request)) {
return true;
}
}
return false;
}
}
}
@@ -23,10 +23,14 @@ import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityBuilder;
import org.springframework.security.config.annotation.web.AbstractRequestMatcherConfigurer;
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
@@ -40,9 +44,10 @@ import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEval
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.debug.DebugFilter;
import org.springframework.security.web.firewall.DefaultHttpFirewall;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.web.filter.DelegatingFilterProxy;
@@ -67,7 +72,7 @@ import org.springframework.web.filter.DelegatingFilterProxy;
* @since 3.2
*/
public final class WebSecurity extends
AbstractConfiguredSecurityBuilder<Filter, WebSecurity> implements SecurityBuilder<Filter> {
AbstractConfiguredSecurityBuilder<Filter, WebSecurity> implements SecurityBuilder<Filter>, ApplicationContextAware {
private final Log logger = LogFactory.getLog(getClass());
private final List<RequestMatcher> ignoredRequests = new ArrayList<RequestMatcher>();
@@ -86,7 +91,10 @@ public final class WebSecurity extends
private WebInvocationPrivilegeEvaluator privilegeEvaluator;
private SecurityExpressionHandler<FilterInvocation> expressionHandler = new DefaultWebSecurityExpressionHandler();
private DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
private SecurityExpressionHandler<FilterInvocation> expressionHandler = defaultWebSecurityExpressionHandler;
private Runnable postBuildAction = new Runnable() {
public void run() {}
@@ -94,9 +102,11 @@ public final class WebSecurity extends
/**
* Creates a new instance
* @param objectPostProcessor the {@link ObjectPostProcessor} to use
* @see WebSecurityConfiguration
*/
public WebSecurity() {
public WebSecurity(ObjectPostProcessor<Object> objectPostProcessor) {
super(objectPostProcessor);
}
/**
@@ -270,7 +280,10 @@ public final class WebSecurity extends
@Override
protected Filter performBuild() throws Exception {
Assert.state(!securityFilterChainBuilders.isEmpty(), "At least one SecurityFilterBuilder needs to be specified. Invoke FilterChainProxyBuilder.securityFilterChains");
Assert.state(!securityFilterChainBuilders.isEmpty(),
"At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. More advanced users can invoke "
+ WebSecurity.class.getSimpleName()
+ ".addSecurityFilterChainBuilder directly");
int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
List<SecurityFilterChain> securityFilterChains = new ArrayList<SecurityFilterChain>(chainSize);
for(RequestMatcher ignoredRequest : ignoredRequests) {
@@ -306,7 +319,7 @@ public final class WebSecurity extends
* @author Rob Winch
* @since 3.2
*/
public final class IgnoredRequestConfigurer extends AbstractRequestMatcherConfigurer<WebSecurity,IgnoredRequestConfigurer,Filter> {
public final class IgnoredRequestConfigurer extends AbstractRequestMatcherRegistry<IgnoredRequestConfigurer> {
@Override
protected IgnoredRequestConfigurer chainRequestMatchers(List<RequestMatcher> requestMatchers) {
@@ -317,11 +330,15 @@ public final class WebSecurity extends
/**
* Returns the {@link WebSecurity} to be returned for chaining.
*/
@Override
public WebSecurity and() {
return WebSecurity.this;
}
private IgnoredRequestConfigurer(){}
}
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
defaultWebSecurityExpressionHandler.setApplicationContext(applicationContext);
}
}
@@ -56,7 +56,7 @@ import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
* }
*
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth) {
* protected void configure(AuthenticationManagerBuilder auth) {
* auth
* // enable in memory based authentication with a user named "user" and "admin"
* .inMemoryAuthentication()
@@ -77,7 +77,7 @@ 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,AuthenticationConfiguration.class, SpringWebMvcImportSelector.class})
@Import({WebSecurityConfiguration.class,ObjectPostProcessorConfiguration.class,AuthenticationConfiguration.class})
public @interface EnableWebSecurity {
/**
@@ -1,39 +0,0 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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 CsrfWebMvcConfiguration} 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.CsrfWebMvcConfiguration"} : new String[] {};
}
}
@@ -34,6 +34,8 @@ import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.config.annotation.AlreadyBuiltException;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
@@ -61,7 +63,9 @@ import org.springframework.util.ClassUtils;
*/
@Configuration
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
private final WebSecurity webSecurity = new WebSecurity();
private WebSecurity webSecurity;
private Boolean debugEnabled;
private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
@@ -84,7 +88,11 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
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());
}
return webSecurity.build();
try {
return webSecurity.build();
} catch (AlreadyBuiltException e) {
return webSecurity.getObject();
}
}
/**
@@ -101,12 +109,18 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
/**
* Sets the {@code <SecurityConfigurer<FilterChainProxy, WebSecurityBuilder>} instances used to create the web configuration.
*
* @param objectPostProcessor the {@link ObjectPostProcessor} used to create a {@link WebSecurity} instance
* @param webSecurityConfigurers the {@code <SecurityConfigurer<FilterChainProxy, WebSecurityBuilder>} instances used to create the web configuration
* @throws Exception
*/
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers) throws Exception {
webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
if(debugEnabled != null) {
webSecurity.debug(debugEnabled);
}
Collections.sort(webSecurityConfigurers, AnnotationAwareOrderComparator.INSTANCE);
Integer previousOrder = null;
@@ -174,8 +188,10 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
enableWebSecurityAttrs = AnnotationAttributes.fromMap(enableWebSecurityAttrMap);
}
}
boolean debugEnabled = enableWebSecurityAttrs.getBoolean("debug");
this.webSecurity.debug(debugEnabled);
debugEnabled = enableWebSecurityAttrs.getBoolean("debug");
if(webSecurity != null) {
webSecurity.debug(debugEnabled);
}
}
/* (non-Javadoc)
@@ -16,17 +16,20 @@
package org.springframework.security.config.annotation.web.configuration;
import javax.servlet.Filter;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
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.HttpSecurity;
@@ -51,7 +54,8 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
*
* @author Rob Winch
*/
public abstract class WebSecurityConfigurerAdapter implements SecurityConfigurer<Filter,WebSecurity> {
@Order(100)
public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer<WebSecurity> {
private final Log logger = LogFactory.getLog(WebSecurityConfigurerAdapter.class);
private ApplicationContext context;
@@ -64,18 +68,12 @@ public abstract class WebSecurityConfigurerAdapter implements SecurityConfigurer
}
};
private final AuthenticationManagerBuilder authenticationBuilder = new AuthenticationManagerBuilder(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR);
private final AuthenticationManagerBuilder parentAuthenticationBuilder = new AuthenticationManagerBuilder(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR) {
@Override
public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {
authenticationBuilder.eraseCredentials(eraseCredentials);
return super.eraseCredentials(eraseCredentials);
}
};
private AuthenticationManagerBuilder authenticationBuilder;
private AuthenticationManagerBuilder parentAuthenticationBuilder;
private boolean disableAuthenticationRegistration;
private boolean authenticationManagerInitialized;
private AuthenticationManager authenticationManager;
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private HttpSecurity http;
private boolean disableDefaults;
@@ -101,32 +99,53 @@ public abstract class WebSecurityConfigurerAdapter implements SecurityConfigurer
}
/**
* Used by the default implementation of {@link #authenticationManager()} to attempt to obtain an
* {@link AuthenticationManager}. If overridden, the {@link AuthenticationManagerBuilder} should be used to specify
* the {@link AuthenticationManager}. The resulting {@link AuthenticationManager}
* will be exposed as a Bean as will the last populated {@link UserDetailsService} that is created with the
* {@link AuthenticationManagerBuilder}. The {@link UserDetailsService} will also automatically be populated on
* {@link HttpSecurity#getSharedObject(Class)} for use with other {@link SecurityContextConfigurer}
* (i.e. RememberMeConfigurer )
* Used by the default implementation of {@link #authenticationManager()} to
* attempt to obtain an {@link AuthenticationManager}. If overridden, the
* {@link AuthenticationManagerBuilder} should be used to specify the
* {@link AuthenticationManager}.
*
* <p>For example, the following configuration could be used to register
* in memory authentication that exposes an in memory {@link UserDetailsService}:</p>
* <p>
* The {@link #authenticationManagerBean()} method can be used to expose the
* resulting {@link AuthenticationManager} as a Bean. The
* {@link #userDetailsServiceBean()} can be used to expose the last
* populated {@link UserDetailsService} that is created with the
* {@link AuthenticationManagerBuilder} as a Bean. The
* {@link UserDetailsService} will also automatically be populated on
* {@link HttpSecurity#getSharedObject(Class)} for use with other
* {@link SecurityContextConfigurer} (i.e. RememberMeConfigurer )
* </p>
*
* <p>
* For example, the following configuration could be used to register in
* memory authentication that exposes an in memory
* {@link UserDetailsService}:
* </p>
*
* <pre>
* &#064;Override
* protected void registerAuthentication(AuthenticationManagerBuilder auth) {
* protected void configure(AuthenticationManagerBuilder auth) {
* auth
* // enable in memory based authentication with a user named "user" and "admin"
* // enable in memory based authentication with a user named
* // &quot;user&quot; and &quot;admin&quot;
* .inMemoryAuthentication()
* .withUser("user").password("password").roles("USER").and()
* .withUser("admin").password("password").roles("USER", "ADMIN");
* .withUser(&quot;user&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;).and()
* .withUser(&quot;admin&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;, &quot;ADMIN&quot;);
* }
*
* // Expose the UserDetailsService as a Bean
* &#064;Bean
* &#064;Override
* public UserDetailsService userDetailsServiceBean() throws Exception {
* return super.userDetailsServiceBean();
* }
*
* </pre>
*
* @param auth the {@link AuthenticationManagerBuilder} to use
* @param auth
* the {@link AuthenticationManagerBuilder} to use
* @throws Exception
*/
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
this.disableAuthenticationRegistration = true;
}
@@ -141,9 +160,6 @@ public abstract class WebSecurityConfigurerAdapter implements SecurityConfigurer
return http;
}
authenticationBuilder.objectPostProcessor(objectPostProcessor);
parentAuthenticationBuilder.objectPostProcessor(objectPostProcessor);
DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
parentAuthenticationBuilder.authenticationEventPublisher(eventPublisher);
@@ -151,7 +167,9 @@ public abstract class WebSecurityConfigurerAdapter implements SecurityConfigurer
authenticationBuilder.parentAuthenticationManager(authenticationManager);
http = new HttpSecurity(objectPostProcessor,authenticationBuilder, parentAuthenticationBuilder.getSharedObjects());
http.setSharedObject(UserDetailsService.class, userDetailsService());
http.setSharedObject(ApplicationContext.class, context);
http.setSharedObject(ContentNegotiationStrategy.class, contentNegotiationStrategy);
http.setSharedObject(AuthenticationTrustResolver.class, trustResolver);
if(!disableDefaults) {
http
.csrf().and()
@@ -172,7 +190,7 @@ public abstract class WebSecurityConfigurerAdapter implements SecurityConfigurer
/**
* Override this method to expose the {@link AuthenticationManager} from
* {@link #registerAuthentication(AuthenticationManagerBuilder)} to be exposed as
* {@link #configure(AuthenticationManagerBuilder)} to be exposed as
* a Bean. For example:
*
* <pre>
@@ -192,7 +210,7 @@ public abstract class WebSecurityConfigurerAdapter implements SecurityConfigurer
/**
* Gets the {@link AuthenticationManager} to use. The default strategy is if
* {@link #registerAuthentication(AuthenticationManagerBuilder)} method is
* {@link #configure(AuthenticationManagerBuilder)} method is
* overridden to use the {@link AuthenticationManagerBuilder} that was passed in.
* Otherwise, autowire the {@link AuthenticationManager} by type.
*
@@ -201,7 +219,7 @@ public abstract class WebSecurityConfigurerAdapter implements SecurityConfigurer
*/
protected AuthenticationManager authenticationManager() throws Exception {
if(!authenticationManagerInitialized) {
registerAuthentication(parentAuthenticationBuilder);
configure(parentAuthenticationBuilder);
if(disableAuthenticationRegistration) {
try {
authenticationManager = context.getBean(AuthenticationManagerBuilder.class).getOrBuild();
@@ -225,7 +243,7 @@ public abstract class WebSecurityConfigurerAdapter implements SecurityConfigurer
/**
* Override this method to expose a {@link UserDetailsService} created from
* {@link #registerAuthentication(AuthenticationManagerBuilder)} as a bean. In
* {@link #configure(AuthenticationManagerBuilder)} as a bean. In
* general only the following override should be done of this method:
*
* <pre>
@@ -243,7 +261,8 @@ public abstract class WebSecurityConfigurerAdapter implements SecurityConfigurer
* @see {@link #userDetailsService()}
*/
public UserDetailsService userDetailsServiceBean() throws Exception {
return new UserDetailsServiceDelegator(parentAuthenticationBuilder);
AuthenticationManagerBuilder globalAuthBuilder = context.getBean(AuthenticationManagerBuilder.class);
return new UserDetailsServiceDelegator(Arrays.asList(parentAuthenticationBuilder, globalAuthBuilder));
}
/**
@@ -255,7 +274,8 @@ public abstract class WebSecurityConfigurerAdapter implements SecurityConfigurer
* @return
*/
protected UserDetailsService userDetailsService() {
return parentAuthenticationBuilder.getDefaultUserDetailsService();
AuthenticationManagerBuilder globalAuthBuilder = context.getBean(AuthenticationManagerBuilder.class);
return new UserDetailsServiceDelegator(Arrays.asList(parentAuthenticationBuilder, globalAuthBuilder));
}
public void init(final WebSecurity web) throws Exception {
@@ -311,6 +331,11 @@ public abstract class WebSecurityConfigurerAdapter implements SecurityConfigurer
this.context = context;
}
@Autowired(required=false)
public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
this.trustResolver = trustResolver;
}
@Autowired(required=false)
public void setContentNegotationStrategy(ContentNegotiationStrategy contentNegotiationStrategy) {
this.contentNegotiationStrategy = contentNegotiationStrategy;
@@ -319,6 +344,16 @@ public abstract class WebSecurityConfigurerAdapter implements SecurityConfigurer
@Autowired(required=false)
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
this.objectPostProcessor = objectPostProcessor;
authenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor);
parentAuthenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor) {
@Override
public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {
authenticationBuilder.eraseCredentials(eraseCredentials);
return super.eraseCredentials(eraseCredentials);
}
};
}
@@ -331,12 +366,15 @@ public abstract class WebSecurityConfigurerAdapter implements SecurityConfigurer
* @since 3.2
*/
static final class UserDetailsServiceDelegator implements UserDetailsService {
private AuthenticationManagerBuilder delegateBuilder;
private List<AuthenticationManagerBuilder> delegateBuilders;
private UserDetailsService delegate;
private final Object delegateMonitor = new Object();
UserDetailsServiceDelegator(AuthenticationManagerBuilder authentication) {
this.delegateBuilder = authentication;
UserDetailsServiceDelegator(List<AuthenticationManagerBuilder> delegateBuilders) {
if(delegateBuilders.contains(null)) {
throw new IllegalArgumentException("delegateBuilders cannot contain null values. Got " + delegateBuilders);
}
this.delegateBuilders = delegateBuilders;
}
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
@@ -346,8 +384,17 @@ public abstract class WebSecurityConfigurerAdapter implements SecurityConfigurer
synchronized(delegateMonitor) {
if (delegate == null) {
delegate = this.delegateBuilder.getDefaultUserDetailsService();
this.delegateBuilder = null;
for(AuthenticationManagerBuilder delegateBuilder : delegateBuilders) {
delegate = delegateBuilder.getDefaultUserDetailsService();
if(delegate != null) {
break;
}
}
if(delegate == null) {
throw new IllegalStateException("UserDetailsService is required.");
}
this.delegateBuilders = null;
}
}
@@ -15,6 +15,8 @@
*/
package org.springframework.security.config.annotation.web.configurers;
import java.util.Collections;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.MediaType;
@@ -34,8 +36,8 @@ import org.springframework.security.web.authentication.SavedRequestAwareAuthenti
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.util.MediaTypeRequestMatcher;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
import org.springframework.web.accept.ContentNegotiationStrategy;
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
@@ -235,7 +237,8 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecu
if(contentNegotiationStrategy == null) {
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
}
RequestMatcher preferredMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy, MediaType.APPLICATION_XHTML_XML, new MediaType("image","*"), MediaType.TEXT_HTML, MediaType.TEXT_PLAIN);
MediaTypeRequestMatcher preferredMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy, MediaType.APPLICATION_XHTML_XML, new MediaType("image","*"), MediaType.TEXT_HTML, MediaType.TEXT_PLAIN);
preferredMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
exceptionHandling.defaultAuthenticationEntryPointFor(postProcess(authenticationEntryPoint), preferredMatcher);
}
@@ -21,9 +21,8 @@ import java.util.LinkedHashMap;
import java.util.List;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.config.annotation.SecurityBuilder;
import org.springframework.security.config.annotation.web.AbstractRequestMatcherConfigurer;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
import org.springframework.security.web.util.matcher.RequestMatcher;
/**
* A base class for registering {@link RequestMatcher}'s. For example, it might allow for specifying which
@@ -32,15 +31,13 @@ import org.springframework.security.web.util.RequestMatcher;
* @author Rob Winch
* @since 3.2
*
* @param <B> The Builder that is building Object O and is configured by this {@link AbstractRequestMatcherMappingConfigurer}
* @param <C> The object that is returned or Chained after creating the RequestMatcher
* @param <O> The Object being built by Builder B
*
* @see ChannelSecurityConfigurer
* @see UrlAuthorizationConfigurer
* @see ExpressionUrlAuthorizationConfigurer
*/
public abstract class AbstractRequestMatcherMappingConfigurer<B extends SecurityBuilder<O>,C,O> extends AbstractRequestMatcherConfigurer<B,C,O> {
public abstract class AbstractConfigAttributeRequestMatcherRegistry<C> extends AbstractRequestMatcherRegistry<C> {
private List<UrlMapping> urlMappings = new ArrayList<UrlMapping>();
private List<RequestMatcher> unmappedMatchers;
@@ -23,7 +23,6 @@ import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
@@ -53,56 +52,28 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
* <li>{@link org.springframework.security.config.annotation.web.builders.HttpSecurity#getAuthenticationManager()}</li>
* </ul>
*
*
* @param <C> the AbstractInterceptUrlConfigurer
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured
* @param <C> the type of object that is changed
* @param <R> the type of object that is changed for the {@link AbstractRequestMatcherMappingConfigurer}
*
* @author Rob Winch
* @since 3.2
* @see ExpressionUrlAuthorizationConfigurer
* @see UrlAuthorizationConfigurer
*/
abstract class AbstractInterceptUrlConfigurer<H extends HttpSecurityBuilder<H>,C,R> extends
AbstractRequestMatcherMappingConfigurer<H,R,DefaultSecurityFilterChain> implements
SecurityConfigurer<DefaultSecurityFilterChain,H> {
abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConfigurer<C,H>, H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<C, H>{
private Boolean filterSecurityInterceptorOncePerRequest;
private AccessDecisionManager accessDecisionManager;
/**
* Allows setting the {@link AccessDecisionManager}. If none is provided, a default {@l AccessDecisionManager} is
* created.
*
* @param accessDecisionManager the {@link AccessDecisionManager} to use
* @return the {@link AbstractInterceptUrlConfigurer} for further customization
*/
public C accessDecisionManager(
AccessDecisionManager accessDecisionManager) {
this.accessDecisionManager = accessDecisionManager;
return getSelf();
}
/**
* Allows setting if the {@link FilterSecurityInterceptor} should be only applied once per request (i.e. if the
* filter intercepts on a forward, should it be applied again).
*
* @param filterSecurityInterceptorOncePerRequest if the {@link FilterSecurityInterceptor} should be only applied
* once per request
* @return the {@link AbstractInterceptUrlConfigurer} for further customization
*/
public C filterSecurityInterceptorOncePerRequest(
boolean filterSecurityInterceptorOncePerRequest) {
this.filterSecurityInterceptorOncePerRequest = filterSecurityInterceptorOncePerRequest;
return getSelf();
}
@Override
public void configure(H http) throws Exception {
FilterInvocationSecurityMetadataSource metadataSource = createMetadataSource();
FilterInvocationSecurityMetadataSource metadataSource = createMetadataSource(http);
if(metadataSource == null) {
return;
}
FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(metadataSource, http.getSharedObject(AuthenticationManager.class));
FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(http, metadataSource, http.getSharedObject(AuthenticationManager.class));
if(filterSecurityInterceptorOncePerRequest != null) {
securityInterceptor.setObserveOncePerRequest(filterSecurityInterceptorOncePerRequest);
}
@@ -115,38 +86,85 @@ abstract class AbstractInterceptUrlConfigurer<H extends HttpSecurityBuilder<H>,C
* Subclasses should implement this method to provide a {@link FilterInvocationSecurityMetadataSource} for the
* {@link FilterSecurityInterceptor}.
*
* @param http the builder to use
*
* @return the {@link FilterInvocationSecurityMetadataSource} to set on the {@link FilterSecurityInterceptor}.
* Cannot be null.
*/
abstract FilterInvocationSecurityMetadataSource createMetadataSource();
abstract FilterInvocationSecurityMetadataSource createMetadataSource(H http);
/**
* Subclasses should implement this method to provide the {@link AccessDecisionVoter} instances used to create the
* default {@link AccessDecisionManager}
*
* @param http the builder to use
*
* @return the {@link AccessDecisionVoter} instances used to create the
* default {@link AccessDecisionManager}
*/
@SuppressWarnings("rawtypes")
abstract List<AccessDecisionVoter> getDecisionVoters();
abstract List<AccessDecisionVoter> getDecisionVoters(H http);
abstract class AbstractInterceptUrlRegistry<R extends AbstractInterceptUrlRegistry<R,T>,T> extends AbstractConfigAttributeRequestMatcherRegistry<T> {
/**
* Allows setting the {@link AccessDecisionManager}. If none is provided, a default {@l AccessDecisionManager} is
* created.
*
* @param accessDecisionManager the {@link AccessDecisionManager} to use
* @return the {@link AbstractInterceptUrlConfigurer} for further customization
*/
public R accessDecisionManager(
AccessDecisionManager accessDecisionManager) {
AbstractInterceptUrlConfigurer.this.accessDecisionManager = accessDecisionManager;
return getSelf();
}
/**
* Allows setting if the {@link FilterSecurityInterceptor} should be only applied once per request (i.e. if the
* filter intercepts on a forward, should it be applied again).
*
* @param filterSecurityInterceptorOncePerRequest if the {@link FilterSecurityInterceptor} should be only applied
* once per request
* @return the {@link AbstractInterceptUrlConfigurer} for further customization
*/
public R filterSecurityInterceptorOncePerRequest(
boolean filterSecurityInterceptorOncePerRequest) {
AbstractInterceptUrlConfigurer.this.filterSecurityInterceptorOncePerRequest = filterSecurityInterceptorOncePerRequest;
return getSelf();
}
/**
* Returns a reference to the current object with a single suppression of
* the type
*
* @return a reference to the current object
*/
@SuppressWarnings("unchecked")
private R getSelf() {
return (R) this;
}
}
/**
* Creates the default {@code AccessDecisionManager}
* @return the default {@code AccessDecisionManager}
*/
private AccessDecisionManager createDefaultAccessDecisionManager() {
return new AffirmativeBased(getDecisionVoters());
private AccessDecisionManager createDefaultAccessDecisionManager(H http) {
return new AffirmativeBased(getDecisionVoters(http));
}
/**
* If currently null, creates a default {@link AccessDecisionManager} using
* {@link #createDefaultAccessDecisionManager()}. Otherwise returns the {@link AccessDecisionManager}.
*
* @param http the builder to use
*
* @return the {@link AccessDecisionManager} to use
*/
private AccessDecisionManager getAccessDecisionManager() {
private AccessDecisionManager getAccessDecisionManager(H http) {
if (accessDecisionManager == null) {
accessDecisionManager = createDefaultAccessDecisionManager();
accessDecisionManager = createDefaultAccessDecisionManager(http);
}
return accessDecisionManager;
}
@@ -154,29 +172,19 @@ abstract class AbstractInterceptUrlConfigurer<H extends HttpSecurityBuilder<H>,C
/**
* Creates the {@link FilterSecurityInterceptor}
*
* @param http the builder to use
* @param metadataSource the {@link FilterInvocationSecurityMetadataSource} to use
* @param authenticationManager the {@link AuthenticationManager} to use
* @return the {@link FilterSecurityInterceptor}
* @throws Exception
*/
private FilterSecurityInterceptor createFilterSecurityInterceptor(FilterInvocationSecurityMetadataSource metadataSource,
private FilterSecurityInterceptor createFilterSecurityInterceptor(H http, FilterInvocationSecurityMetadataSource metadataSource,
AuthenticationManager authenticationManager) throws Exception {
FilterSecurityInterceptor securityInterceptor = new FilterSecurityInterceptor();
securityInterceptor.setSecurityMetadataSource(metadataSource);
securityInterceptor.setAccessDecisionManager(getAccessDecisionManager());
securityInterceptor.setAccessDecisionManager(getAccessDecisionManager(http));
securityInterceptor.setAuthenticationManager(authenticationManager);
securityInterceptor.afterPropertiesSet();
return securityInterceptor;
}
/**
* Returns a reference to the current object with a single suppression of
* the type
*
* @return a reference to the current object
*/
@SuppressWarnings("unchecked")
private C getSelf() {
return (C) this;
}
}
@@ -23,9 +23,10 @@ import java.util.List;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityBuilder;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.PortMapper;
import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
@@ -35,7 +36,7 @@ import org.springframework.security.web.access.channel.RetryWithHttpEntryPoint;
import org.springframework.security.web.access.channel.RetryWithHttpsEntryPoint;
import org.springframework.security.web.access.channel.SecureChannelProcessor;
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
/**
* Adds channel security (i.e. requires HTTPS or HTTP) to an application. In order for
@@ -72,11 +73,13 @@ import org.springframework.security.web.util.RequestMatcher;
* @since 3.2
*/
public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractRequestMatcherMappingConfigurer<H,ChannelSecurityConfigurer<H>.RequiresChannelUrl,DefaultSecurityFilterChain> {
AbstractHttpConfigurer<ChannelSecurityConfigurer<H>, H> {
private ChannelProcessingFilter channelFilter = new ChannelProcessingFilter();
private LinkedHashMap<RequestMatcher,Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestMatcher,Collection<ConfigAttribute>>();
private List<ChannelProcessor> channelProcessors;
private final ChannelRequestMatcherRegistry REGISTRY = new ChannelRequestMatcherRegistry();
/**
* Creates a new instance
* @see HttpSecurity#requiresChannel()
@@ -84,6 +87,10 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> e
public ChannelSecurityConfigurer() {
}
public ChannelRequestMatcherRegistry getRegistry() {
return REGISTRY;
}
@Override
public void configure(H http) throws Exception {
ChannelDecisionManagerImpl channelDecisionManager = new ChannelDecisionManagerImpl();
@@ -100,27 +107,6 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> e
http.addFilter(channelFilter);
}
/**
* Adds an {@link ObjectPostProcessor} for this class.
*
* @param objectPostProcessor
* @return the {@link ChannelSecurityConfigurer} for further customizations
*/
public ChannelSecurityConfigurer<H> withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
addObjectPostProcessor(objectPostProcessor);
return this;
}
/**
* Sets the {@link ChannelProcessor} instances to use in {@link ChannelDecisionManagerImpl}
* @param channelProcessors
* @return
*/
public ChannelSecurityConfigurer<H> channelProcessors(List<ChannelProcessor> channelProcessors) {
this.channelProcessors = channelProcessors;
return this;
}
private List<ChannelProcessor> getChannelProcessors(H http) {
if(channelProcessors != null) {
return channelProcessors;
@@ -145,17 +131,53 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> e
}
private ChannelSecurityConfigurer<H> addAttribute(String attribute, List<RequestMatcher> matchers) {
private ChannelRequestMatcherRegistry addAttribute(String attribute, List<RequestMatcher> matchers) {
for(RequestMatcher matcher : matchers) {
Collection<ConfigAttribute> attrs = Arrays.<ConfigAttribute>asList(new SecurityConfig(attribute));
requestMap.put(matcher, attrs);
}
return this;
return REGISTRY;
}
@Override
protected RequiresChannelUrl chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
return new RequiresChannelUrl(requestMatchers);
public final class ChannelRequestMatcherRegistry extends AbstractConfigAttributeRequestMatcherRegistry<RequiresChannelUrl> {
@Override
protected RequiresChannelUrl chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
return new RequiresChannelUrl(requestMatchers);
}
/**
* Adds an {@link ObjectPostProcessor} for this class.
*
* @param objectPostProcessor
* @return the {@link ChannelSecurityConfigurer} for further customizations
*/
public ChannelRequestMatcherRegistry withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
addObjectPostProcessor(objectPostProcessor);
return this;
}
/**
* Sets the {@link ChannelProcessor} instances to use in {@link ChannelDecisionManagerImpl}
* @param channelProcessors
* @return
*/
public ChannelRequestMatcherRegistry channelProcessors(List<ChannelProcessor> channelProcessors) {
ChannelSecurityConfigurer.this.channelProcessors = channelProcessors;
return this;
}
/**
* Return the {@link SecurityBuilder} when done using the
* {@link SecurityConfigurer}. This is useful for method chaining.
*
* @return
*/
public H and() {
return ChannelSecurityConfigurer.this.and();
}
private ChannelRequestMatcherRegistry() {}
}
public final class RequiresChannelUrl {
@@ -165,15 +187,15 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> e
this.requestMatchers = requestMatchers;
}
public ChannelSecurityConfigurer<H> requiresSecure() {
public ChannelRequestMatcherRegistry requiresSecure() {
return requires("REQUIRES_SECURE_CHANNEL");
}
public ChannelSecurityConfigurer<H> requiresInsecure() {
public ChannelRequestMatcherRegistry requiresInsecure() {
return requires("REQUIRES_INSECURE_CHANNEL");
}
public ChannelSecurityConfigurer<H> requires(String attribute) {
public ChannelRequestMatcherRegistry requires(String attribute) {
return addAttribute(attribute, requestMatchers);
}
}
@@ -15,15 +15,23 @@
*/
package org.springframework.security.config.annotation.web.configurers;
import java.util.LinkedHashMap;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.access.DelegatingAccessDeniedHandler;
import org.springframework.security.web.csrf.CsrfAuthenticationStrategy;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.security.web.csrf.CsrfLogoutHandler;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.security.web.csrf.MissingCsrfTokenException;
import org.springframework.security.web.session.InvalidSessionAccessDeniedHandler;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
/**
@@ -50,6 +58,7 @@ import org.springframework.util.Assert;
* <li>
* {@link ExceptionHandlingConfigurer#accessDeniedHandler(AccessDeniedHandler)}
* is used to determine how to handle CSRF attempts</li>
* <li>{@link InvalidSessionStrategy}</li>
* </ul>
*
* @author Rob Winch
@@ -100,12 +109,9 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>> extends Abst
if(requireCsrfProtectionMatcher != null) {
filter.setRequireCsrfProtectionMatcher(requireCsrfProtectionMatcher);
}
ExceptionHandlingConfigurer<H> exceptionConfig = http.getConfigurer(ExceptionHandlingConfigurer.class);
if(exceptionConfig != null) {
AccessDeniedHandler accessDeniedHandler = exceptionConfig.getAccessDeniedHandler();
if(accessDeniedHandler != null) {
filter.setAccessDeniedHandler(accessDeniedHandler);
}
AccessDeniedHandler accessDeniedHandler = createAccessDeniedHandler(http);
if(accessDeniedHandler != null) {
filter.setAccessDeniedHandler(accessDeniedHandler);
}
LogoutConfigurer<H> logoutConfigurer = http.getConfigurer(LogoutConfigurer.class);
if(logoutConfigurer != null) {
@@ -118,4 +124,70 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>> extends Abst
filter = postProcess(filter);
http.addFilter(filter);
}
/**
* Gets the default {@link AccessDeniedHandler} from the
* {@link ExceptionHandlingConfigurer#getAccessDeniedHandler()} or create a
* {@link AccessDeniedHandlerImpl} if not available.
*
* @param http the {@link HttpSecurityBuilder}
* @return the {@link AccessDeniedHandler}
*/
@SuppressWarnings("unchecked")
private AccessDeniedHandler getDefaultAccessDeniedHandler(H http) {
ExceptionHandlingConfigurer<H> exceptionConfig = http.getConfigurer(ExceptionHandlingConfigurer.class);
AccessDeniedHandler handler = null;
if(exceptionConfig != null) {
handler = exceptionConfig.getAccessDeniedHandler();
}
if(handler == null) {
handler = new AccessDeniedHandlerImpl();
}
return handler;
}
/**
* Gets the default {@link InvalidSessionStrategy} from the
* {@link SessionManagementConfigurer#getInvalidSessionStrategy()} or null
* if not available.
*
* @param http
* the {@link HttpSecurityBuilder}
* @return the {@link InvalidSessionStrategy}
*/
@SuppressWarnings("unchecked")
private InvalidSessionStrategy getInvalidSessionStrategy(H http) {
SessionManagementConfigurer<H> sessionManagement = http.getConfigurer(SessionManagementConfigurer.class);
if(sessionManagement == null) {
return null;
}
return sessionManagement.getInvalidSessionStrategy();
}
/**
* Creates the {@link AccessDeniedHandler} from the result of
* {@link #getDefaultAccessDeniedHandler(HttpSecurityBuilder)} and
* {@link #getInvalidSessionStrategy(HttpSecurityBuilder)}. If
* {@link #getInvalidSessionStrategy(HttpSecurityBuilder)} is non-null, then
* a {@link DelegatingAccessDeniedHandler} is used in combination with
* {@link InvalidSessionAccessDeniedHandler} and the
* {@link #getDefaultAccessDeniedHandler(HttpSecurityBuilder)}. Otherwise,
* only {@link #getDefaultAccessDeniedHandler(HttpSecurityBuilder)} is used.
*
* @param http the {@link HttpSecurityBuilder}
* @return the {@link AccessDeniedHandler}
*/
private AccessDeniedHandler createAccessDeniedHandler(H http) {
InvalidSessionStrategy invalidSessionStrategy = getInvalidSessionStrategy(http);
AccessDeniedHandler defaultAccessDeniedHandler = getDefaultAccessDeniedHandler(http);
if(invalidSessionStrategy == null) {
return defaultAccessDeniedHandler;
}
InvalidSessionAccessDeniedHandler invalidSessionDeniedHandler = new InvalidSessionAccessDeniedHandler(invalidSessionStrategy);
LinkedHashMap<Class<? extends AccessDeniedException>, AccessDeniedHandler> handlers =
new LinkedHashMap<Class<? extends AccessDeniedException>, AccessDeniedHandler>();
handlers.put(MissingCsrfTokenException.class, invalidSessionDeniedHandler);
return new DelegatingAccessDeniedHandler(handlers, defaultAccessDeniedHandler);
}
}
@@ -18,7 +18,7 @@ package org.springframework.security.config.annotation.web.configurers;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFilter;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
/**
* Adds a Filter that will generate a login page if one is not specified otherwise when using {@link WebSecurityConfigurerAdapter}.
@@ -32,7 +32,7 @@ import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFi
* The following Filters are conditionally populated
*
* <ul>
* <li>{@link DefaultLoginPageViewFilter} if the {@link FormLoginConfigurer} did not have a login page specified</li>
* <li>{@link DefaultLoginPageGeneratingFilter} if the {@link FormLoginConfigurer} did not have a login page specified</li>
* </ul>
*
* <h2>Shared Objects Created</h2>
@@ -56,11 +56,11 @@ import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFi
public final class DefaultLoginPageConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<DefaultLoginPageConfigurer<H>,H> {
private DefaultLoginPageViewFilter loginPageGeneratingFilter = new DefaultLoginPageViewFilter();
private DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = new DefaultLoginPageGeneratingFilter();
@Override
public void init(H http) throws Exception {
http.setSharedObject(DefaultLoginPageViewFilter.class, loginPageGeneratingFilter);
http.setSharedObject(DefaultLoginPageGeneratingFilter.class, loginPageGeneratingFilter);
}
@Override
@@ -27,7 +27,7 @@ import org.springframework.security.web.authentication.DelegatingAuthenticationE
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
/**
* Adds exception handling for Spring Security related exceptions to an application. All properties have reasonable
@@ -24,6 +24,7 @@ import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@@ -31,7 +32,7 @@ import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.expression.WebExpressionVoter;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -56,7 +57,9 @@ import org.springframework.util.StringUtils;
*
* <h2>Shared Objects Used</h2>
*
* No shared objects are used.
* <ul>
* <li>{@link AuthenticationTrustResolver} is optionally used to populate the {@link DefaultWebSecurityExpressionHandler}</li>
* </ul>
*
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured
*
@@ -64,7 +67,7 @@ import org.springframework.util.StringUtils;
* @since 3.2
* @see {@link org.springframework.security.config.annotation.web.builders.HttpSecurity#authorizeRequests()}
*/
public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractInterceptUrlConfigurer<H,ExpressionUrlAuthorizationConfigurer<H>,ExpressionUrlAuthorizationConfigurer<H>.AuthorizedUrl> {
public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractInterceptUrlConfigurer<ExpressionUrlAuthorizationConfigurer<H>,H> {
static final String permitAll = "permitAll";
private static final String denyAll = "denyAll";
private static final String anonymous = "anonymous";
@@ -72,7 +75,9 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
private static final String fullyAuthenticated = "fullyAuthenticated";
private static final String rememberMe = "rememberMe";
private SecurityExpressionHandler<FilterInvocation> expressionHandler = new DefaultWebSecurityExpressionHandler();
private final ExpressionInterceptUrlRegistry REGISTRY = new ExpressionInterceptUrlRegistry();
private SecurityExpressionHandler<FilterInvocation> expressionHandler;
/**
* Creates a new instance
@@ -81,52 +86,47 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
public ExpressionUrlAuthorizationConfigurer() {
}
/**
* Allows customization of the {@link SecurityExpressionHandler} to be used. The default is {@link DefaultWebSecurityExpressionHandler}
*
* @param expressionHandler the {@link SecurityExpressionHandler} to be used
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization.
*/
public ExpressionUrlAuthorizationConfigurer<H> expressionHandler(SecurityExpressionHandler<FilterInvocation> expressionHandler) {
this.expressionHandler = expressionHandler;
return this;
public ExpressionInterceptUrlRegistry getRegistry() {
return REGISTRY;
}
/**
* Adds an {@link ObjectPostProcessor} for this class.
*
* @param objectPostProcessor
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customizations
*/
public ExpressionUrlAuthorizationConfigurer<H> withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
addObjectPostProcessor(objectPostProcessor);
return this;
}
public class ExpressionInterceptUrlRegistry extends ExpressionUrlAuthorizationConfigurer<H>.AbstractInterceptUrlRegistry<ExpressionInterceptUrlRegistry,AuthorizedUrl> {
@Override
protected final AuthorizedUrl chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
return new AuthorizedUrl(requestMatchers);
}
@Override
@SuppressWarnings("rawtypes")
final List<AccessDecisionVoter> getDecisionVoters() {
List<AccessDecisionVoter> decisionVoters = new ArrayList<AccessDecisionVoter>();
WebExpressionVoter expressionVoter = new WebExpressionVoter();
expressionVoter.setExpressionHandler(expressionHandler);
decisionVoters.add(expressionVoter);
return decisionVoters;
}
@Override
final ExpressionBasedFilterInvocationSecurityMetadataSource createMetadataSource() {
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = createRequestMap();
if(requestMap.isEmpty()) {
throw new IllegalStateException("At least one mapping is required (i.e. authorizeRequests().anyRequest.authenticated())");
@Override
protected final AuthorizedUrl chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
return new AuthorizedUrl(requestMatchers);
}
return new ExpressionBasedFilterInvocationSecurityMetadataSource(requestMap, expressionHandler);
/**
* Allows customization of the {@link SecurityExpressionHandler} to be used. The default is {@link DefaultWebSecurityExpressionHandler}
*
* @param expressionHandler the {@link SecurityExpressionHandler} to be used
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization.
*/
public ExpressionInterceptUrlRegistry expressionHandler(SecurityExpressionHandler<FilterInvocation> expressionHandler) {
ExpressionUrlAuthorizationConfigurer.this.expressionHandler = expressionHandler;
return this;
}
/**
* Adds an {@link ObjectPostProcessor} for this class.
*
* @param objectPostProcessor
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customizations
*/
public ExpressionInterceptUrlRegistry withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
addObjectPostProcessor(objectPostProcessor);
return this;
}
public H and() {
return ExpressionUrlAuthorizationConfigurer.this.and();
}
}
/**
* Allows registering multiple {@link RequestMatcher} instances to a collection of {@link ConfigAttribute} instances
*
@@ -136,9 +136,46 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
*/
private ExpressionUrlAuthorizationConfigurer<H> interceptUrl(Iterable<? extends RequestMatcher> requestMatchers, Collection<ConfigAttribute> configAttributes) {
for(RequestMatcher requestMatcher : requestMatchers) {
addMapping(new UrlMapping(requestMatcher, configAttributes));
REGISTRY.addMapping(new AbstractConfigAttributeRequestMatcherRegistry.UrlMapping(requestMatcher, configAttributes));
}
return this;
return null;
}
@Override
@SuppressWarnings("rawtypes")
final List<AccessDecisionVoter> getDecisionVoters(H http) {
List<AccessDecisionVoter> decisionVoters = new ArrayList<AccessDecisionVoter>();
WebExpressionVoter expressionVoter = new WebExpressionVoter();
expressionVoter.setExpressionHandler(getExpressionHandler(http));
decisionVoters.add(expressionVoter);
return decisionVoters;
}
@Override
final ExpressionBasedFilterInvocationSecurityMetadataSource createMetadataSource(H http) {
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = REGISTRY.createRequestMap();
if(requestMap.isEmpty()) {
throw new IllegalStateException("At least one mapping is required (i.e. authorizeRequests().anyRequest.authenticated())");
}
return new ExpressionBasedFilterInvocationSecurityMetadataSource(requestMap, getExpressionHandler(http));
}
private SecurityExpressionHandler<FilterInvocation> getExpressionHandler(H http) {
if(expressionHandler == null) {
DefaultWebSecurityExpressionHandler defaultHandler = new DefaultWebSecurityExpressionHandler();
AuthenticationTrustResolver trustResolver = http.getSharedObject(AuthenticationTrustResolver.class);
if(trustResolver != null) {
defaultHandler.setTrustResolver(trustResolver);
}
expressionHandler = postProcess(defaultHandler);
}
return expressionHandler;
}
private static String hasAnyRole(String... authorities) {
String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','ROLE_");
return "hasAnyRole('ROLE_" + anyAuthorities + "')";
}
private static String hasRole(String role) {
@@ -195,17 +232,33 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
* this is automatically inserted.
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
*/
public ExpressionUrlAuthorizationConfigurer<H> hasRole(String role) {
public ExpressionInterceptUrlRegistry hasRole(String role) {
return access(ExpressionUrlAuthorizationConfigurer.hasRole(role));
}
/**
* Shortcut for specifying URLs 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 ExpressionUrlAuthorizationConfigurer} for further
* customization
*/
public ExpressionInterceptUrlRegistry hasAnyRole(String... roles) {
return access(ExpressionUrlAuthorizationConfigurer.hasAnyRole(roles));
}
/**
* Specify that URLs require a particular authority.
*
* @param authority the authority to require (i.e. ROLE_USER, ROLE_ADMIN, etc).
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
*/
public ExpressionUrlAuthorizationConfigurer<H> hasAuthority(String authority) {
public ExpressionInterceptUrlRegistry hasAuthority(String authority) {
return access(ExpressionUrlAuthorizationConfigurer.hasAuthority(authority));
}
@@ -216,7 +269,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
* mean either "ROLE_USER" or "ROLE_ADMIN" is required).
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
*/
public ExpressionUrlAuthorizationConfigurer<H> hasAnyAuthority(String... authorities) {
public ExpressionInterceptUrlRegistry hasAnyAuthority(String... authorities) {
return access(ExpressionUrlAuthorizationConfigurer.hasAnyAuthority(authorities));
}
@@ -227,7 +280,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
* @param ipaddressExpression the ipaddress (i.e. 192.168.1.79) or local subnet (i.e. 192.168.0/24)
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
*/
public ExpressionUrlAuthorizationConfigurer<H> hasIpAddress(String ipaddressExpression) {
public ExpressionInterceptUrlRegistry hasIpAddress(String ipaddressExpression) {
return access(ExpressionUrlAuthorizationConfigurer.hasIpAddress(ipaddressExpression));
}
@@ -236,7 +289,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
*
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
*/
public ExpressionUrlAuthorizationConfigurer<H> permitAll() {
public ExpressionInterceptUrlRegistry permitAll() {
return access(permitAll);
}
@@ -245,7 +298,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
*
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
*/
public ExpressionUrlAuthorizationConfigurer<H> anonymous() {
public ExpressionInterceptUrlRegistry anonymous() {
return access(anonymous);
}
@@ -255,7 +308,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
* @see {@link RememberMeConfigurer}
*/
public ExpressionUrlAuthorizationConfigurer<H> rememberMe() {
public ExpressionInterceptUrlRegistry rememberMe() {
return access(rememberMe);
}
@@ -264,7 +317,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
*
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
*/
public ExpressionUrlAuthorizationConfigurer<H> denyAll() {
public ExpressionInterceptUrlRegistry denyAll() {
return access(denyAll);
}
@@ -273,7 +326,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
*
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
*/
public ExpressionUrlAuthorizationConfigurer<H> authenticated() {
public ExpressionInterceptUrlRegistry authenticated() {
return access(authenticated);
}
@@ -283,7 +336,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
* @see {@link RememberMeConfigurer}
*/
public ExpressionUrlAuthorizationConfigurer<H> fullyAuthenticated() {
public ExpressionInterceptUrlRegistry fullyAuthenticated() {
return access(fullyAuthenticated);
}
@@ -293,12 +346,12 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
* @param attribute the expression to secure the URLs (i.e. "hasRole('ROLE_USER') and hasRole('ROLE_SUPER')")
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization
*/
public ExpressionUrlAuthorizationConfigurer<H> access(String attribute) {
public ExpressionInterceptUrlRegistry access(String attribute) {
if(not) {
attribute = "!" + attribute;
}
interceptUrl(requestMatchers, SecurityConfig.createList(attribute));
return ExpressionUrlAuthorizationConfigurer.this;
return ExpressionUrlAuthorizationConfigurer.this.REGISTRY;
}
}
}
@@ -22,9 +22,9 @@ import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFilter;
import org.springframework.security.web.util.AntPathRequestMatcher;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
/**
* Adds form based authentication. All attributes have reasonable defaults
@@ -57,7 +57,7 @@ import org.springframework.security.web.util.RequestMatcher;
* <li>{@link AuthenticationManager}</li>
* <li>{@link RememberMeServices} - is optionally used. See {@link RememberMeConfigurer}</li>
* <li>{@link SessionAuthenticationStrategy} - is optionally used. See {@link SessionManagementConfigurer}</li>
* <li>{@link DefaultLoginPageViewFilter} - if present will be populated with information from the configuration</li>
* <li>{@link DefaultLoginPageGeneratingFilter} - if present will be populated with information from the configuration</li>
* </ul>
*
* @author Rob Winch
@@ -245,12 +245,12 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
}
/**
* If available, initializes the {@link DefaultLoginPageViewFilter} shared object.
* If available, initializes the {@link DefaultLoginPageGeneratingFilter} shared object.
*
* @param http the {@link HttpSecurityBuilder} to use
*/
private void initDefaultLoginFilter(H http) {
DefaultLoginPageViewFilter loginPageGeneratingFilter = http.getSharedObject(DefaultLoginPageViewFilter.class);
DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = http.getSharedObject(DefaultLoginPageGeneratingFilter.class);
if(loginPageGeneratingFilter != null && !isCustomLoginPage()) {
loginPageGeneratingFilter.setFormLoginEnabled(true);
loginPageGeneratingFilter.setUsernameParameter(getUsernameParameter());
@@ -20,6 +20,7 @@ import java.util.List;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.header.HeaderWriter;
import org.springframework.security.web.header.HeaderWriterFilter;
import org.springframework.security.web.header.writers.CacheControlHeadersWriter;
@@ -30,15 +31,80 @@ import org.springframework.security.web.header.writers.frameoptions.XFrameOption
import org.springframework.util.Assert;
/**
* Adds the Security headers to the response. This is activated by default when
* using {@link WebSecurityConfigurerAdapter}'s default constructor. Only
* invoking the {@link #headers()} without invoking additional methods on it, or
* accepting the default provided by {@link WebSecurityConfigurerAdapter}, is
* the equivalent of:
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter {
*
* &#064;Override
* protected void configure(HttpSecurity http) throws Exception {
* http
* .headers()
* .contentTypeOptions();
* .xssProtection()
* .cacheControl()
* .httpStrictTransportSecurity()
* .frameOptions()
* .and()
* ...;
* }
* }
* </pre>
*
* You can disable the headers using the following:
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter {
*
* &#064;Override
* protected void configure(HttpSecurity http) throws Exception {
* http
* .headers().disable()
* ...;
* }
* }
* </pre>
*
* You can enable only a few of the headers by invoking the appropriate methods
* on {@link #headers()} result. For example, the following will enable
* {@link HeadersConfigurer#cacheControl()} and
* {@link HeadersConfigurer#frameOptions()} only.
*
* <pre>
* &#064;Configuration
* &#064;EnableWebSecurity
* public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter {
*
* &#064;Override
* protected void configure(HttpSecurity http) throws Exception {
* http
* .headers()
* .cacheControl()
* .frameOptions()
* .and()
* ...;
* }
* }
* </pre>
*
* @author Rob Winch
* @since 3.2
* @see RememberMeConfigurer
*/
public final class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<HeadersConfigurer<H>,H> {
public final class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<HeadersConfigurer<H>, H> {
private List<HeaderWriter> headerWriters = new ArrayList<HeaderWriter>();
/**
* Creates a new instance
*
* @see HttpSecurity#headers()
*/
public HeadersConfigurer() {
@@ -46,7 +112,9 @@ public final class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends A
/**
* Adds a {@link HeaderWriter} instance
* @param headerWriter the {@link HeaderWriter} instance to add
*
* @param headerWriter
* the {@link HeaderWriter} instance to add
* @return the {@link HeadersConfigurer} for additional customizations
*/
public HeadersConfigurer<H> addHeaderWriter(HeaderWriter headerWriter) {
@@ -56,7 +124,13 @@ public final class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends A
}
/**
* Adds {@link XContentTypeOptionsHeaderWriter}
* Adds {@link XContentTypeOptionsHeaderWriter} which inserts the <a href=
* "http://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx"
* >X-Content-Type-Options</a>:
*
* <pre>
* X-Content-Type-Options: nosniff
* </pre>
*
* @return the {@link HeadersConfigurer} for additional customizations
*/
@@ -65,8 +139,11 @@ public final class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends A
}
/**
* Adds {@link XXssProtectionHeaderWriter}. Note this is not comprehensive
* XSS protection!
* <strong>Note this is not comprehensive XSS protection!</strong>
*
* <para>Adds {@link XXssProtectionHeaderWriter} which adds the <a href=
* "http://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx"
* >X-XSS-Protection header</a>
*
* @return the {@link HeadersConfigurer} for additional customizations
*/
@@ -75,7 +152,13 @@ public final class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends A
}
/**
* Adds {@link CacheControlHeadersWriter}.
* Adds {@link CacheControlHeadersWriter}. Specifically it adds the
* following headers:
* <ul>
* <li>Cache-Control: no-cache, no-store, max-age=0, must-revalidate</li>
* <li>Pragma: no-cache</li>
* <li>Expires: 0</li>
* </ul>
*
* @return the {@link HeadersConfigurer} for additional customizations
*/
@@ -84,7 +167,15 @@ public final class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends A
}
/**
* Adds {@link HstsHeaderWriter}.
* Adds {@link HstsHeaderWriter} which provides support for <a
* href="http://tools.ietf.org/html/rfc6797">HTTP Strict Transport Security
* (HSTS)</a>.
*
* <p>
* For additional configuration options, use
* {@link #addHeaderWriter(HeaderWriter)} and {@link HstsHeaderWriter}
* directly.
* </p>
*
* @return the {@link HeadersConfigurer} for additional customizations
*/
@@ -93,7 +184,10 @@ public final class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends A
}
/**
* Adds {@link XFrameOptionsHeaderWriter} with all the default settings.
* Adds {@link XFrameOptionsHeaderWriter} with all the default settings. For
* additional configuration options, use
* {@link #addHeaderWriter(HeaderWriter)} and
* {@link XFrameOptionsHeaderWriter} directly.
*
* @return the {@link HeadersConfigurer} for additional customizations
*/
@@ -109,20 +203,24 @@ public final class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends A
/**
* Creates the {@link HeaderWriter}
*
* @return the {@link HeaderWriter}
*/
private HeaderWriterFilter createHeaderWriterFilter() {
HeaderWriterFilter headersFilter = new HeaderWriterFilter(getHeaderWriters());
HeaderWriterFilter headersFilter = new HeaderWriterFilter(
getHeaderWriters());
headersFilter = postProcess(headersFilter);
return headersFilter;
}
/**
* Gets the {@link HeaderWriter} instances and possibly initializes with the defaults.
* Gets the {@link HeaderWriter} instances and possibly initializes with the
* defaults.
*
* @return
*/
private List<HeaderWriter> getHeaderWriters() {
if(headerWriters.isEmpty()) {
if (headerWriters.isEmpty()) {
addDefaultHeaderWriters();
}
return headerWriters;
@@ -15,21 +15,29 @@
*/
package org.springframework.security.config.annotation.web.configurers;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.util.MediaTypeRequestMatcher;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
import org.springframework.web.accept.ContentNegotiationStrategy;
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
@@ -66,10 +74,11 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
* @since 3.2
*/
public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends AbstractHttpConfigurer<HttpBasicConfigurer<B>,B> {
private static final String DEFAULT_REALM = "Spring Security Application";
private static final String DEFAULT_REALM = "Realm";
private AuthenticationEntryPoint authenticationEntryPoint = new BasicAuthenticationEntryPoint();
private AuthenticationEntryPoint authenticationEntryPoint;
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource;
private BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
/**
* Creates a new instance
@@ -78,12 +87,19 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
*/
public HttpBasicConfigurer() throws Exception {
realmName(DEFAULT_REALM);
LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> entryPoints = new LinkedHashMap<RequestMatcher, AuthenticationEntryPoint>();
entryPoints.put(new RequestHeaderRequestMatcher("X-Requested-With","XMLHttpRequest"), new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
DelegatingAuthenticationEntryPoint defaultEntryPoint = new DelegatingAuthenticationEntryPoint(entryPoints);
defaultEntryPoint.setDefaultEntryPoint(basicAuthEntryPoint);
authenticationEntryPoint = defaultEntryPoint;
}
/**
* Shortcut for {@link #authenticationEntryPoint(AuthenticationEntryPoint)}
* specifying a {@link BasicAuthenticationEntryPoint} with the specified
* realm name.
* Allows easily changing the realm, but leaving the remaining defaults in
* place. If {@link #authenticationEntryPoint(AuthenticationEntryPoint)} has
* been invoked, invoking this method will result in an error.
*
* @param realmName
* the HTTP Basic realm to use
@@ -91,14 +107,13 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
* @throws Exception
*/
public HttpBasicConfigurer<B> realmName(String realmName) throws Exception {
BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
basicAuthEntryPoint.setRealmName(realmName);
basicAuthEntryPoint.afterPropertiesSet();
return authenticationEntryPoint(basicAuthEntryPoint);
return this;
}
/**
* The {@link AuthenticationEntryPoint} to be po pulated on
* The {@link AuthenticationEntryPoint} to be populated on
* {@link BasicAuthenticationFilter} in the event that authentication fails.
* The default to use {@link BasicAuthenticationEntryPoint} with the realm
* "Spring Security Application".
@@ -141,6 +156,8 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
MediaTypeRequestMatcher preferredMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy, MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON, MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_XML, MediaType.MULTIPART_FORM_DATA, MediaType.TEXT_XML);
preferredMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
exceptionHandling.defaultAuthenticationEntryPointFor(postProcess(authenticationEntryPoint), preferredMatcher);
}
@Override
@@ -153,4 +170,20 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
basicAuthenticationFilter = postProcess(basicAuthenticationFilter);
http.addFilter(basicAuthenticationFilter);
}
}
private static class HttpStatusEntryPoint implements AuthenticationEntryPoint {
private final HttpStatus httpStatus;
public HttpStatusEntryPoint(HttpStatus httpStatus) {
super();
this.httpStatus = httpStatus;
}
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException,
ServletException {
response.setStatus(httpStatus.value());
}
}
}
@@ -29,9 +29,9 @@ import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFilter;
import org.springframework.security.web.util.AntPathRequestMatcher;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
/**
* Adds logout support. Other {@link SecurityConfigurer} instances may invoke
@@ -64,7 +64,8 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends Ab
private SecurityContextLogoutHandler contextLogoutHandler = new SecurityContextLogoutHandler();
private String logoutSuccessUrl = "/login?logout";
private LogoutSuccessHandler logoutSuccessHandler;
private RequestMatcher logoutRequestMatcher = new AntPathRequestMatcher("/logout", "POST");
private String logoutUrl = "/logout";
private RequestMatcher logoutRequestMatcher;
private boolean permitAll;
private boolean customLogoutSuccess;
@@ -98,18 +99,41 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends Ab
}
/**
* The URL that triggers logout to occur on HTTP POST. The default is "/logout"
* @param logoutUrl the URL that will invoke logout.
* The URL that triggers log out to occur (default is "/logout"). If CSRF
* protection is enabled (default), then the request must also be a POST.
* This means that by default POST "/logout" is required to trigger a log
* out. If CSRF protection is disabled, then any HTTP method is allowed.
*
* <p>
* It is considered best practice to use an HTTP POST on any action that
* changes state (i.e. log out) to protect against <a
* href="http://en.wikipedia.org/wiki/Cross-site_request_forgery">CSRF
* attacks</a>. If you really want to use an HTTP GET, you can use
* <code>logoutRequestMatcher(new AntPathRequestMatcher(logoutUrl, "GET"));</code>
* </p>
*
* @see #logoutRequestMatcher(RequestMatcher)
* @see HttpSecurity#csrf()
*
* @param logoutUrl
* the URL that will invoke logout.
* @return the {@link LogoutConfigurer} for further customization
*/
public LogoutConfigurer<H> logoutUrl(String logoutUrl) {
return logoutRequestMatcher(new AntPathRequestMatcher(logoutUrl, "POST"));
this.logoutRequestMatcher = null;
this.logoutUrl = logoutUrl;
return this;
}
/**
* The RequestMatcher that triggers logout to occur on HTTP POST. The default is "/logout"
* @param logoutRequestMatcher the RequestMatcher used to determine if logout should occur.
* The RequestMatcher that triggers log out to occur. In most circumstances
* users will use {@link #logoutUrl(String)} which helps enforce good
* practices.
*
* @see #logoutUrl(String)
*
* @param logoutRequestMatcher
* the RequestMatcher used to determine if logout should occur.
* @return the {@link LogoutConfigurer} for further customization
*/
public LogoutConfigurer<H> logoutRequestMatcher(RequestMatcher logoutRequestMatcher) {
@@ -201,10 +225,10 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends Ab
public void init(H http) throws Exception {
if(permitAll) {
PermitAllSupport.permitAll(http, this.logoutSuccessUrl);
PermitAllSupport.permitAll(http, this.logoutRequestMatcher);
PermitAllSupport.permitAll(http, this.getLogoutRequestMatcher(http));
}
DefaultLoginPageViewFilter loginPageGeneratingFilter = http.getSharedObject(DefaultLoginPageViewFilter.class);
DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = http.getSharedObject(DefaultLoginPageGeneratingFilter.class);
if(loginPageGeneratingFilter != null && !isCustomLogoutSuccess()) {
loginPageGeneratingFilter.setLogoutSuccessUrl(getLogoutSuccessUrl());
}
@@ -212,7 +236,7 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends Ab
@Override
public void configure(H http) throws Exception {
LogoutFilter logoutFilter = createLogoutFilter();
LogoutFilter logoutFilter = createLogoutFilter(http);
http.addFilter(logoutFilter);
}
@@ -250,15 +274,27 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends Ab
* instances, the {@link #logoutSuccessHandler(LogoutSuccessHandler)} and
* the {@link #logoutUrl(String)}.
*
* @param http the builder to use
* @return the {@link LogoutFilter} to use.
* @throws Exception
*/
private LogoutFilter createLogoutFilter() throws Exception {
private LogoutFilter createLogoutFilter(H http) throws Exception {
logoutHandlers.add(contextLogoutHandler);
LogoutHandler[] handlers = logoutHandlers.toArray(new LogoutHandler[logoutHandlers.size()]);
LogoutFilter result = new LogoutFilter(getLogoutSuccessHandler(), handlers);
result.setLogoutRequestMatcher(logoutRequestMatcher);
result.setLogoutRequestMatcher(getLogoutRequestMatcher(http));
result = postProcess(result);
return result;
}
@SuppressWarnings("unchecked")
private RequestMatcher getLogoutRequestMatcher(H http) {
if(logoutRequestMatcher != null) {
return logoutRequestMatcher;
}
if(http.getConfigurer(CsrfConfigurer.class) != null) {
this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl, "POST");
}
return new AntPathRequestMatcher(this.logoutUrl);
}
}
@@ -20,8 +20,8 @@ import javax.servlet.http.HttpServletRequest;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.configurers.AbstractRequestMatcherMappingConfigurer.UrlMapping;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.security.config.annotation.web.configurers.AbstractConfigAttributeRequestMatcherRegistry.UrlMapping;
import org.springframework.security.web.util.matcher.RequestMatcher;
/**
@@ -49,7 +49,7 @@ final class PermitAllSupport {
for(RequestMatcher matcher : requestMatchers) {
if(matcher != null) {
configurer.addMapping(0, new UrlMapping(matcher, SecurityConfig.createList(ExpressionUrlAuthorizationConfigurer.permitAll)));
configurer.getRegistry().addMapping(0, new UrlMapping(matcher, SecurityConfig.createList(ExpressionUrlAuthorizationConfigurer.permitAll)));
}
}
}
@@ -32,7 +32,7 @@ import org.springframework.security.web.authentication.rememberme.PersistentToke
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFilter;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
/**
* Configures Remember Me authentication. This typically involves the user
@@ -67,7 +67,7 @@ import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFi
* <ul>
* <li>{@link AuthenticationManager}</li>
* <li>{@link UserDetailsService} if no {@link #userDetailsService(UserDetailsService)} was specified.</li>
* <li> {@link DefaultLoginPageViewFilter} - if present will be populated with information from the configuration</li>
* <li> {@link DefaultLoginPageGeneratingFilter} - if present will be populated with information from the configuration</li>
* </ul>
*
* @author Rob Winch
@@ -124,7 +124,7 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>> extend
* {@link UserDetails} when a remember me token is valid. The default is to
* use the {@link UserDetailsService} found by invoking
* {@link HttpSecurity#getSharedObject(Class)} which is set when using
* {@link WebSecurityConfigurerAdapter#registerAuthentication(org.springframework.security.config.annotation.authentication.AuthenticationManagerBuilder)}.
* {@link WebSecurityConfigurerAdapter#configure(AuthenticationManagerBuilder)}.
* Alternatively, one can populate {@link #rememberMeServices(RememberMeServices)}.
*
* @param userDetailsService
@@ -229,12 +229,12 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>> extend
}
/**
* If available, initializes the {@link DefaultLoginPageViewFilter} shared object.
* If available, initializes the {@link DefaultLoginPageGeneratingFilter} shared object.
*
* @param http the {@link HttpSecurityBuilder} to use
*/
private void initDefaultLoginFilter(H http) {
DefaultLoginPageViewFilter loginPageGeneratingFilter = http.getSharedObject(DefaultLoginPageViewFilter.class);
DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = http.getSharedObject(DefaultLoginPageGeneratingFilter.class);
if(loginPageGeneratingFilter != null) {
loginPageGeneratingFilter.setRememberMeParameter(getRememberMeParameter());
}
@@ -15,12 +15,22 @@
*/
package org.springframework.security.config.annotation.web.configurers;
import java.util.Collections;
import org.springframework.http.MediaType;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
import org.springframework.security.web.util.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.AndRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.web.accept.ContentNegotiationStrategy;
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
/**
* Adds request cache for Spring Security. Specifically this ensures that
@@ -100,7 +110,23 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>> exte
return result;
}
HttpSessionRequestCache defaultCache = new HttpSessionRequestCache();
defaultCache.setRequestMatcher(new AntPathRequestMatcher("/**", "GET"));
defaultCache.setRequestMatcher(createDefaultSavedRequestMatcher(http));
return defaultCache;
}
}
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);
jsonRequest.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
RequestMatcher notJson = new NegatedRequestMatcher(jsonRequest);
RequestMatcher notXRequestedWith = new NegatedRequestMatcher(new RequestHeaderRequestMatcher("X-Requested-With","XMLHttpRequest"));
return new AndRequestMatcher(getRequests, notFavIcon, notJson, notXRequestedWith);
}
}
@@ -20,6 +20,7 @@ import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.authentication.AuthenticationManager;
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.core.context.SecurityContext;
@@ -45,7 +46,9 @@ import org.springframework.security.web.servletapi.SecurityContextHolderAwareReq
*
* <h2>Shared Objects Used</h2>
*
* No shared Objects are used.
* <ul>
* <li>{@link AuthenticationTrustResolver} is optionally used to populate the {@link SecurityContextHolderAwareRequestFilter}</li>
* </ul>
*
* @author Rob Winch
* @since 3.2
@@ -75,6 +78,10 @@ public final class ServletApiConfigurer<H extends HttpSecurityBuilder<H>> extend
LogoutConfigurer<H> logoutConf = http.getConfigurer(LogoutConfigurer.class);
List<LogoutHandler> logoutHandlers = logoutConf == null ? null : logoutConf.getLogoutHandlers();
securityContextRequestFilter.setLogoutHandlers(logoutHandlers);
AuthenticationTrustResolver trustResolver = http.getSharedObject(AuthenticationTrustResolver.class);
if(trustResolver != null) {
securityContextRequestFilter.setTrustResolver(trustResolver);
}
securityContextRequestFilter = postProcess(securityContextRequestFilter);
http.addFilter(securityContextRequestFilter);
}
@@ -22,6 +22,7 @@ import java.util.List;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
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;
@@ -41,6 +42,7 @@ import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy;
import org.springframework.util.Assert;
@@ -65,12 +67,14 @@ import org.springframework.util.Assert;
* <li>{@link RequestCache}</li>
* <li>{@link SecurityContextRepository}</li>
* <li>{@link SessionManagementConfigurer}</li>
* <li>{@link InvalidSessionStrategy}</li>
* </ul>
*
* <h2>Shared Objects Used</h2>
*
* <ul>
* <li>{@link SecurityContextRepository}</li>
* <li>{@link AuthenticationTrustResolver} is optionally used to populate the {@link HttpSessionSecurityContextRepository} and {@link SessionManagementFilter}</li>
* </ul>
*
* @author Rob Winch
@@ -81,6 +85,7 @@ import org.springframework.util.Assert;
public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<SessionManagementConfigurer<H>,H> {
private SessionAuthenticationStrategy sessionFixationAuthenticationStrategy = createDefaultSessionFixationProtectionStrategy();
private SessionAuthenticationStrategy sessionAuthenticationStrategy;
private InvalidSessionStrategy invalidSessionStrategy;
private List<SessionAuthenticationStrategy> sessionAuthenticationStrategies = new ArrayList<SessionAuthenticationStrategy>();
private SessionRegistry sessionRegistry = new SessionRegistryImpl();
private Integer maximumSessions;
@@ -242,14 +247,17 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
}
/**
* Specifies that no session fixation protection should be enabled. This
* may be useful when utilizing other mechanisms for protecting against
* session fixation. For example, if application container session
* fixation protection is already in use. Otherwise, this option is not
* recommended.
* Specifies that the Servlet container-provided session fixation
* protection should be used. When a session authenticates, the
* Servlet 3.1 method {@code HttpServletRequest#changeSessionId()} is
* called to change the session ID and retain all session attributes.
* Using this option in a Servlet 3.0 or older container results in an
* {@link IllegalStateException}.
*
* @return the {@link SessionManagementConfigurer} for further
* customizations
* @throws IllegalStateException if the container is not Servlet 3.1 or
* newer.
*/
public SessionManagementConfigurer<H> changeSessionId() {
setSessionFixationAuthenticationStrategy(new ChangeSessionIdAuthenticationStrategy());
@@ -334,28 +342,33 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
}
@Override
public void init(H builder) throws Exception {
SecurityContextRepository securityContextRepository = builder.getSharedObject(SecurityContextRepository.class);
public void init(H http) throws Exception {
SecurityContextRepository securityContextRepository = http.getSharedObject(SecurityContextRepository.class);
boolean stateless = isStateless();
if(securityContextRepository == null) {
if(stateless) {
builder.setSharedObject(SecurityContextRepository.class, new NullSecurityContextRepository());
http.setSharedObject(SecurityContextRepository.class, new NullSecurityContextRepository());
} else {
HttpSessionSecurityContextRepository httpSecurityRepository = new HttpSessionSecurityContextRepository();
httpSecurityRepository.setDisableUrlRewriting(!enableSessionUrlRewriting);
httpSecurityRepository.setAllowSessionCreation(isAllowSessionCreation());
builder.setSharedObject(SecurityContextRepository.class, httpSecurityRepository);
AuthenticationTrustResolver trustResolver = http.getSharedObject(AuthenticationTrustResolver.class);
if(trustResolver != null) {
httpSecurityRepository.setTrustResolver(trustResolver);
}
http.setSharedObject(SecurityContextRepository.class, httpSecurityRepository);
}
}
RequestCache requestCache = builder.getSharedObject(RequestCache.class);
RequestCache requestCache = http.getSharedObject(RequestCache.class);
if(requestCache == null) {
if(stateless) {
builder.setSharedObject(RequestCache.class, new NullRequestCache());
http.setSharedObject(RequestCache.class, new NullRequestCache());
}
}
builder.setSharedObject(SessionAuthenticationStrategy.class, getSessionAuthenticationStrategy());
http.setSharedObject(SessionAuthenticationStrategy.class, getSessionAuthenticationStrategy());
http.setSharedObject(InvalidSessionStrategy.class, getInvalidSessionStrategy());
}
@Override
@@ -366,7 +379,11 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
sessionManagementFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(sessionAuthenticationErrorUrl));
}
if(invalidSessionUrl != null) {
sessionManagementFilter.setInvalidSessionStrategy(new SimpleRedirectInvalidSessionStrategy(invalidSessionUrl));
sessionManagementFilter.setInvalidSessionStrategy(getInvalidSessionStrategy());
}
AuthenticationTrustResolver trustResolver = http.getSharedObject(AuthenticationTrustResolver.class);
if(trustResolver != null) {
sessionManagementFilter.setTrustResolver(trustResolver);
}
sessionManagementFilter = postProcess(sessionManagementFilter);
@@ -378,6 +395,23 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
}
}
/**
* Gets the {@link InvalidSessionStrategy} to use. If
* {@link #invalidSessionUrl} is null, returns null otherwise
* {@link SimpleRedirectInvalidSessionStrategy} is used.
*
* @return the {@link InvalidSessionStrategy} to use
*/
InvalidSessionStrategy getInvalidSessionStrategy() {
if(invalidSessionUrl == null) {
return null;
}
if(invalidSessionStrategy == null) {
invalidSessionStrategy = new SimpleRedirectInvalidSessionStrategy(invalidSessionUrl);
}
return invalidSessionStrategy;
}
/**
* Gets the {@link SessionCreationPolicy}. Can not be null.
* @return the {@link SessionCreationPolicy}
@@ -451,4 +485,4 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
return new SessionFixationProtectionStrategy();
}
}
}
}
@@ -27,29 +27,52 @@ import org.springframework.security.access.vote.AuthenticatedVoter;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
/**
* Adds URL based authorization using {@link DefaultFilterInvocationSecurityMetadataSource}. At least one
* {@link org.springframework.web.bind.annotation.RequestMapping} needs to be mapped to {@link ConfigAttribute}'s for
* this {@link SecurityContextConfigurer} to have meaning.
* <h2>Security Filters</h2>
* Adds URL based authorization using
* {@link DefaultFilterInvocationSecurityMetadataSource}. At least one
* {@link org.springframework.web.bind.annotation.RequestMapping} needs to be
* mapped to {@link ConfigAttribute}'s for this
* {@link SecurityContextConfigurer} to have meaning. <h2>Security Filters</h2>
*
* <p>
* Usage includes applying the {@link UrlAuthorizationConfigurer} and then
* modifying the StandardInterceptUrlRegistry. For example:
* </p>
*
* <pre>
* protected void configure(HttpSecurity http) throws Exception {
* http
* .apply(new UrlAuthorizationConfigurer<HttpSecurity>()).getRegistry()
* .antMatchers("/users**","/sessions/**").hasRole("USER")
* .antMatchers("/signup").hasRole("ANONYMOUS")
* .anyRequest().hasRole("USER");
* }
* </pre>
*
* The following Filters are populated
*
* <ul>
* <li>{@link org.springframework.security.web.access.intercept.FilterSecurityInterceptor}</li>
* <li>
* {@link org.springframework.security.web.access.intercept.FilterSecurityInterceptor}
* </li>
* </ul>
*
* <h2>Shared Objects Created</h2>
*
* The following shared objects are populated to allow other {@link org.springframework.security.config.annotation.SecurityConfigurer}'s to customize:
* The following shared objects are populated to allow other
* {@link org.springframework.security.config.annotation.SecurityConfigurer}'s
* to customize:
* <ul>
* <li>{@link org.springframework.security.web.access.intercept.FilterSecurityInterceptor}</li>
* <li>
* {@link org.springframework.security.web.access.intercept.FilterSecurityInterceptor}
* </li>
* </ul>
*
* <h2>Shared Objects Used</h2>
@@ -57,17 +80,32 @@ import org.springframework.util.Assert;
* The following shared objects are used:
*
* <ul>
* <li>{@link org.springframework.security.config.annotation.web.builders.HttpSecurity#getAuthenticationManager()}</li>
* <li>
* {@link org.springframework.security.config.annotation.web.builders.HttpSecurity#getAuthenticationManager()}
* </li>
* </ul>
*
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured
* @param <C> the type of object that is being chained
* @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
* @see ExpressionUrlAuthorizationConfigurer
*/
public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>, C> extends AbstractInterceptUrlConfigurer<H,C,UrlAuthorizationConfigurer<H,C>.AuthorizedUrl> {
public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractInterceptUrlConfigurer<UrlAuthorizationConfigurer<H>,H> {
private final StandardInterceptUrlRegistry REGISTRY = new StandardInterceptUrlRegistry();
/**
* The StandardInterceptUrlRegistry is what users will interact with after
* applying the {@link UrlAuthorizationConfigurer}.
*
* @return
*/
public StandardInterceptUrlRegistry getRegistry() {
return REGISTRY;
}
/**
* Adds an {@link ObjectPostProcessor} for this class.
@@ -75,19 +113,45 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>,
* @param objectPostProcessor
* @return the {@link UrlAuthorizationConfigurer} for further customizations
*/
public UrlAuthorizationConfigurer<H,C> withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
public UrlAuthorizationConfigurer<H> withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
addObjectPostProcessor(objectPostProcessor);
return this;
}
public class StandardInterceptUrlRegistry extends ExpressionUrlAuthorizationConfigurer<H>.AbstractInterceptUrlRegistry<StandardInterceptUrlRegistry,AuthorizedUrl> {
@Override
protected final AuthorizedUrl chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
return new AuthorizedUrl(requestMatchers);
}
/**
* Adds an {@link ObjectPostProcessor} for this class.
*
* @param objectPostProcessor
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customizations
*/
public StandardInterceptUrlRegistry withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
addObjectPostProcessor(objectPostProcessor);
return this;
}
public H and() {
return UrlAuthorizationConfigurer.this.and();
}
}
/**
* Creates the default {@link AccessDecisionVoter} instances used if an
* {@link AccessDecisionManager} was not specified using
* {@link #accessDecisionManager(AccessDecisionManager)}.
*
* @param http the builder to use
*/
@Override
@SuppressWarnings("rawtypes")
final List<AccessDecisionVoter> getDecisionVoters() {
final List<AccessDecisionVoter> getDecisionVoters(H http) {
List<AccessDecisionVoter> decisionVoters = new ArrayList<AccessDecisionVoter>();
decisionVoters.add(new RoleVoter());
decisionVoters.add(new AuthenticatedVoter());
@@ -96,20 +160,13 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>,
/**
* Creates the {@link FilterInvocationSecurityMetadataSource} to use. The
* implementation is a {@link DefaultFilterInvocationSecurityMetadataSource}
* .
* implementation is a {@link DefaultFilterInvocationSecurityMetadataSource}.
*
* @param http the builder to use
*/
@Override
FilterInvocationSecurityMetadataSource createMetadataSource() {
return new DefaultFilterInvocationSecurityMetadataSource(createRequestMap());
}
/**
* Chains the {@link RequestMatcher} creation to the {@link AuthorizedUrl} class.
*/
@Override
protected AuthorizedUrl chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
return new AuthorizedUrl(requestMatchers);
FilterInvocationSecurityMetadataSource createMetadataSource(H http) {
return new DefaultFilterInvocationSecurityMetadataSource(REGISTRY.createRequestMap());
}
/**
@@ -118,11 +175,11 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>,
* @param configAttributes the {@link ConfigAttribute} instances that should be mapped by the {@link RequestMatcher} instances
* @return the {@link UrlAuthorizationConfigurer} for further customizations
*/
private UrlAuthorizationConfigurer<H,C> addMapping(Iterable<? extends RequestMatcher> requestMatchers, Collection<ConfigAttribute> configAttributes) {
private StandardInterceptUrlRegistry addMapping(Iterable<? extends RequestMatcher> requestMatchers, Collection<ConfigAttribute> configAttributes) {
for(RequestMatcher requestMatcher : requestMatchers) {
addMapping(new UrlMapping(requestMatcher, configAttributes));
REGISTRY.addMapping(new AbstractConfigAttributeRequestMatcherRegistry.UrlMapping(requestMatcher, configAttributes));
}
return this;
return REGISTRY;
}
/**
@@ -195,7 +252,7 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>,
* with ROLE_
* the {@link UrlAuthorizationConfigurer} for further customization
*/
public UrlAuthorizationConfigurer<H,C> hasRole(String role) {
public StandardInterceptUrlRegistry hasRole(String role) {
return access(UrlAuthorizationConfigurer.hasRole(role));
}
@@ -208,7 +265,7 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>,
* it is automatically prepended already.
* @return the {@link UrlAuthorizationConfigurer} for further customization
*/
public UrlAuthorizationConfigurer<H,C> hasAnyRole(String... roles) {
public StandardInterceptUrlRegistry hasAnyRole(String... roles) {
return access(UrlAuthorizationConfigurer.hasAnyRole(roles));
}
@@ -219,7 +276,7 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>,
* the authority that should be required
* @return the {@link UrlAuthorizationConfigurer} for further customization
*/
public UrlAuthorizationConfigurer<H,C> hasAuthority(String authority) {
public StandardInterceptUrlRegistry hasAuthority(String authority) {
return access(authority);
}
@@ -228,7 +285,7 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>,
* @param authorities the authorities that the user should have at least one of (i.e. ROLE_USER, ROLE_ADMIN, etc).
* @return the {@link UrlAuthorizationConfigurer} for further customization
*/
public UrlAuthorizationConfigurer<H,C> hasAnyAuthority(String... authorities) {
public StandardInterceptUrlRegistry hasAnyAuthority(String... authorities) {
return access(UrlAuthorizationConfigurer.hasAnyAuthority(authorities));
}
@@ -236,7 +293,7 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>,
* Specifies that an anonymous user is allowed access
* @return the {@link UrlAuthorizationConfigurer} for further customization
*/
public UrlAuthorizationConfigurer<H,C> anonymous() {
public StandardInterceptUrlRegistry anonymous() {
return hasRole("ROLE_ANONYMOUS");
}
@@ -245,9 +302,9 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>,
* @param attributes the {@link ConfigAttribute}'s that restrict access to a URL
* @return the {@link UrlAuthorizationConfigurer} for further customization
*/
public UrlAuthorizationConfigurer<H,C> access(String... attributes) {
public StandardInterceptUrlRegistry access(String... attributes) {
addMapping(requestMatchers, SecurityConfig.createList(attributes));
return UrlAuthorizationConfigurer.this;
return UrlAuthorizationConfigurer.this.REGISTRY;
}
}
}
@@ -49,9 +49,9 @@ import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFilter;
import org.springframework.security.web.util.AntPathRequestMatcher;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
/**
* Adds support for OpenID based authentication.
@@ -75,7 +75,7 @@ import org.springframework.security.web.util.RequestMatcher;
* }
*
* &#064;Override
* protected void registerAuthentication(
* protected void configure(AuthenticationManagerBuilder auth)(
* AuthenticationManagerBuilder auth) throws Exception {
* auth
* .inMemoryAuthentication()
@@ -340,12 +340,12 @@ public final class OpenIDLoginConfigurer<H extends HttpSecurityBuilder<H>> exten
}
/**
* If available, initializes the {@link DefaultLoginPageViewFilter} shared object.
* If available, initializes the {@link DefaultLoginPageGeneratingFilter} shared object.
*
* @param http the {@link HttpSecurityBuilder} to use
*/
private void initDefaultLoginFilter(H http) {
DefaultLoginPageViewFilter loginPageGeneratingFilter = http.getSharedObject(DefaultLoginPageViewFilter.class);
DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = http.getSharedObject(DefaultLoginPageGeneratingFilter.class);
if(loginPageGeneratingFilter != null && !isCustomLoginPage()) {
loginPageGeneratingFilter.setOpenIdEnabled(true);
loginPageGeneratingFilter.setOpenIDauthenticationUrl(getLoginProcessingUrl());
@@ -0,0 +1,37 @@
/*
* 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.servlet.configuration;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
/**
* Add this annotation to an {@code @Configuration} class to have the Spring Security
* configuration integrate with Spring MVC.
*
* @author Rob Winch
* @since 3.2
*/
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value={java.lang.annotation.ElementType.TYPE})
@Documented
@Import(WebMvcSecurityConfiguration.class)
public @interface EnableWebMvcSecurity {
}
@@ -13,25 +13,40 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration;
package org.springframework.security.config.annotation.web.servlet.configuration;
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.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;
/**
* 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.
* DispatcherServlet is present on the classpath. It also adds the
* {@link AuthenticationPrincipalArgumentResolver} as a
* {@link HandlerMethodArgumentResolver}.
*
* @author Rob Winch
* @since 3.2
*/
@Configuration
class CsrfWebMvcConfiguration {
@EnableWebSecurity
public class WebMvcSecurityConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addArgumentResolvers(
List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new AuthenticationPrincipalArgumentResolver());
}
@Bean
public RequestDataValueProcessor requestDataValueProcessor() {
@@ -15,6 +15,8 @@
*/
package org.springframework.security.config.debug;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
@@ -22,15 +24,17 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.security.config.BeanIds;
import org.springframework.security.web.debug.DebugFilter;
/**
* @author Luke Taylor
* @author Rob Winch
*/
public class SecurityDebugBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
private final Log logger = LogFactory.getLog(getClass());
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
Logger.logger.warn("\n\n" +
logger.warn("\n\n" +
"********************************************************************\n" +
"********** Security debugging is enabled. *************\n" +
"********** This may include sensitive information. *************\n" +
@@ -15,17 +15,26 @@
*/
package org.springframework.security.config.http;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.DelegatingAccessDeniedHandler;
import org.springframework.security.web.csrf.CsrfAuthenticationStrategy;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.security.web.csrf.CsrfLogoutHandler;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.security.web.csrf.MissingCsrfTokenException;
import org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor;
import org.springframework.security.web.session.InvalidSessionAccessDeniedHandler;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
@@ -44,6 +53,7 @@ public class CsrfBeanDefinitionParser implements BeanDefinitionParser {
private static final String ATT_REPOSITORY = "token-repository-ref";
private String csrfRepositoryRef;
private BeanDefinition csrfFilter;
public BeanDefinition parse(Element element, ParserContext pc) {
boolean webmvcPresent = ClassUtils.isPresent(DISPATCHER_SERVLET_CLASS_NAME, getClass().getClassLoader());
@@ -57,21 +67,64 @@ public class CsrfBeanDefinitionParser implements BeanDefinitionParser {
csrfRepositoryRef = element.getAttribute(ATT_REPOSITORY);
String matcherRef = element.getAttribute(ATT_MATCHER);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(CsrfFilter.class);
if(!StringUtils.hasText(csrfRepositoryRef)) {
RootBeanDefinition csrfTokenRepository = new RootBeanDefinition(HttpSessionCsrfTokenRepository.class);
csrfRepositoryRef = pc.getReaderContext().generateBeanName(csrfTokenRepository);
pc.registerBeanComponent(new BeanComponentDefinition(csrfTokenRepository, csrfRepositoryRef));
}
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(CsrfFilter.class);
builder.addConstructorArgReference(csrfRepositoryRef);
if(StringUtils.hasText(matcherRef)) {
builder.addPropertyReference("requireCsrfProtectionMatcher", matcherRef);
}
return builder.getBeanDefinition();
csrfFilter = builder.getBeanDefinition();
return csrfFilter;
}
/**
* Populate the AccessDeniedHandler on the {@link CsrfFilter}
*
* @param invalidSessionStrategy the {@link InvalidSessionStrategy} to use
* @param defaultDeniedHandler the {@link AccessDeniedHandler} to use
*/
void initAccessDeniedHandler(BeanDefinition invalidSessionStrategy, BeanMetadataElement defaultDeniedHandler) {
BeanMetadataElement accessDeniedHandler = createAccessDeniedHandler(invalidSessionStrategy, defaultDeniedHandler);
csrfFilter.getPropertyValues().addPropertyValue("accessDeniedHandler", accessDeniedHandler);
}
/**
* Creates the {@link AccessDeniedHandler} from the result of
* {@link #getDefaultAccessDeniedHandler(HttpSecurityBuilder)} and
* {@link #getInvalidSessionStrategy(HttpSecurityBuilder)}. If
* {@link #getInvalidSessionStrategy(HttpSecurityBuilder)} is non-null, then
* a {@link DelegatingAccessDeniedHandler} is used in combination with
* {@link InvalidSessionAccessDeniedHandler} and the
* {@link #getDefaultAccessDeniedHandler(HttpSecurityBuilder)}. Otherwise,
* only {@link #getDefaultAccessDeniedHandler(HttpSecurityBuilder)} is used.
*
* @param invalidSessionStrategy the {@link InvalidSessionStrategy} to use
* @param defaultDeniedHandler the {@link AccessDeniedHandler} to use
*
* @return the {@link BeanMetadataElement} that is the {@link AccessDeniedHandler} to populate on the {@link CsrfFilter}
*/
private BeanMetadataElement createAccessDeniedHandler(BeanDefinition invalidSessionStrategy, BeanMetadataElement defaultDeniedHandler) {
if(invalidSessionStrategy == null) {
return defaultDeniedHandler;
}
ManagedMap<Class<? extends AccessDeniedException>,BeanDefinition> handlers =
new ManagedMap<Class<? extends AccessDeniedException>, BeanDefinition>();
BeanDefinitionBuilder invalidSessionHandlerBldr = BeanDefinitionBuilder.rootBeanDefinition(InvalidSessionAccessDeniedHandler.class);
invalidSessionHandlerBldr.addConstructorArgValue(invalidSessionStrategy);
handlers.put(MissingCsrfTokenException.class, invalidSessionHandlerBldr.getBeanDefinition());
BeanDefinitionBuilder deniedBldr = BeanDefinitionBuilder.rootBeanDefinition(DelegatingAccessDeniedHandler.class);
deniedBldr.addConstructorArgValue(handlers);
deniedBldr.addConstructorArgValue(defaultDeniedHandler);
return deniedBldr.getBeanDefinition();
}
BeanDefinition getCsrfAuthenticationStrategy() {
@@ -25,7 +25,8 @@ import org.springframework.security.web.context.SecurityContextPersistenceFilter
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.security.web.util.AnyRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
public class DefaultFilterChainValidator implements FilterChainProxy.FilterChainValidator {
private final Log logger = LogFactory.getLog(getClass());
@@ -45,7 +46,8 @@ public class DefaultFilterChainValidator implements FilterChainProxy.FilterChain
Iterator<SecurityFilterChain> chains = filterChains.iterator();
while (chains.hasNext()) {
if (((DefaultSecurityFilterChain)chains.next()).getRequestMatcher() instanceof AnyRequestMatcher && chains.hasNext()) {
RequestMatcher matcher = ((DefaultSecurityFilterChain)chains.next()).getRequestMatcher();
if (AnyRequestMatcher.INSTANCE.equals(matcher) && chains.hasNext()) {
throw new IllegalArgumentException("A universal match pattern ('/**') is defined " +
" before other patterns in the filter chain, causing them to be ignored. Please check the " +
"ordering in your <security:http> namespace or FilterChainProxy bean configuration");
@@ -70,7 +70,7 @@ import org.springframework.security.web.servletapi.SecurityContextHolderAwareReq
import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy;
import org.springframework.security.web.util.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
@@ -130,6 +130,10 @@ class HttpConfigurationBuilder {
private BeanMetadataElement csrfLogoutHandler;
private BeanMetadataElement csrfAuthStrategy;
private CsrfBeanDefinitionParser csrfParser;
private BeanDefinition invalidSession;
public HttpConfigurationBuilder(Element element, ParserContext pc,
BeanReference portMapper, BeanReference portResolver, BeanReference authenticationManager) {
this.httpElt = element;
@@ -200,8 +204,8 @@ class HttpConfigurationBuilder {
}
void setAccessDeniedHandler(BeanMetadataElement accessDeniedHandler) {
if(csrfFilter != null) {
csrfFilter.getPropertyValues().add("accessDeniedHandler", accessDeniedHandler);
if(csrfParser != null ) {
csrfParser.initAccessDeniedHandler(this.invalidSession, accessDeniedHandler);
}
}
@@ -381,7 +385,10 @@ class HttpConfigurationBuilder {
}
if (StringUtils.hasText(invalidSessionUrl)) {
sessionMgmtFilter.addPropertyValue("invalidSessionStrategy", new SimpleRedirectInvalidSessionStrategy(invalidSessionUrl));
BeanDefinitionBuilder invalidSessionBldr = BeanDefinitionBuilder.rootBeanDefinition(SimpleRedirectInvalidSessionStrategy.class);
invalidSessionBldr.addConstructorArgValue(invalidSessionUrl);
invalidSession = invalidSessionBldr.getBeanDefinition();
sessionMgmtFilter.addPropertyValue("invalidSessionStrategy", invalidSession);
}
sessionMgmtFilter.addConstructorArgReference(sessionAuthStratRef);
@@ -637,14 +644,16 @@ class HttpConfigurationBuilder {
}
private void createCsrfFilter() {
private CsrfBeanDefinitionParser createCsrfFilter() {
Element elmt = DomUtils.getChildElementByTagName(httpElt, Elements.CSRF);
if (elmt != null) {
CsrfBeanDefinitionParser csrfParser = new CsrfBeanDefinitionParser();
this.csrfFilter = csrfParser.parse(elmt, pc);
csrfParser = new CsrfBeanDefinitionParser();
csrfFilter = csrfParser.parse(elmt, pc);
this.csrfAuthStrategy = csrfParser.getCsrfAuthenticationStrategy();
this.csrfLogoutHandler = csrfParser.getCsrfLogoutHandler();
return csrfParser;
}
return null;
}
BeanMetadataElement getCsrfLogoutHandler() {
@@ -40,7 +40,7 @@ import org.springframework.security.config.authentication.AuthenticationManagerF
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.PortResolverImpl;
import org.springframework.security.web.util.AnyRequestMatcher;
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
@@ -5,10 +5,10 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.security.web.util.AntPathRequestMatcher;
import org.springframework.security.web.util.AnyRequestMatcher;
import org.springframework.security.web.util.RegexRequestMatcher;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
@@ -132,12 +132,12 @@ class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
}
if (tokenValiditySet) {
int tokenValidity = Integer.parseInt(tokenValiditySeconds);
if (tokenValidity < 0 && isPersistent) {
boolean isTokenValidityNegative = tokenValiditySeconds.startsWith("-");
if (isTokenValidityNegative && isPersistent) {
pc.getReaderContext().error(ATT_TOKEN_VALIDITY + " cannot be negative if using" +
" a persistent remember-me token repository", source);
}
services.getPropertyValues().addPropertyValue("tokenValiditySeconds", tokenValidity);
services.getPropertyValues().addPropertyValue("tokenValiditySeconds", tokenValiditySeconds);
}
if (remembermeParameterSet) {
@@ -1,5 +1,8 @@
package org.springframework.security.config.ldap;
import java.io.IOException;
import java.net.ServerSocket;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -9,6 +12,7 @@ import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.config.BeanIds;
import org.springframework.security.ldap.server.ApacheDSContainer;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
@@ -40,7 +44,8 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
/** Defines the port the LDAP_PROVIDER server should run on */
public static final String ATT_PORT = "port";
public static final String OPT_DEFAULT_PORT = "33389";
private static final int DEFAULT_PORT = 33389;
public static final String OPT_DEFAULT_PORT = String.valueOf(DEFAULT_PORT);
public BeanDefinition parse(Element elt, ParserContext parserContext) {
@@ -101,7 +106,10 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
String port = element.getAttribute(ATT_PORT);
if (!StringUtils.hasText(port)) {
port = OPT_DEFAULT_PORT;
port = getDefaultPort();
if(logger.isDebugEnabled()) {
logger.debug("Using default port of " + port);
}
}
String url = "ldap://127.0.0.1:" + port + "/" + suffix;
@@ -134,4 +142,26 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
return (RootBeanDefinition) contextSource.getBeanDefinition();
}
private String getDefaultPort() {
ServerSocket serverSocket = null;
try {
try {
serverSocket = new ServerSocket(DEFAULT_PORT);
} catch (IOException e) {
try {
serverSocket = new ServerSocket(0);
} catch(IOException e2) {
return String.valueOf(DEFAULT_PORT);
}
}
return String.valueOf(serverSocket.getLocalPort());
} finally {
if(serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {}
}
}
}
}
@@ -280,7 +280,7 @@ http-firewall =
element http-firewall {ref}
http =
## Container element for HTTP security configuration. Multiple elements can now be defined, each with a specific pattern to which the enclosed security configuration applies. A pattern can also be configured to bypass Spring Security's filters completely by setting the "secured" attribute to "false".
## Container element for HTTP security configuration. Multiple elements can now be defined, each with a specific pattern to which the enclosed security configuration applies. A pattern can also be configured to bypass Spring Security's filters completely by setting the "security" attribute to "none".
element http {http.attlist, (intercept-url* & access-denied-handler? & form-login? & openid-login? & x509? & jee? & http-basic? & logout? & session-management & remember-me? & anonymous? & port-mappings & custom-filter* & request-cache? & expression-handler?) }
http.attlist &=
## The request URL pattern which will be mapped to the filter chain created by this <http> element. If omitted, the filter chain will match all requests.
@@ -524,7 +524,7 @@ session-management.attlist &=
## Allows injection of the SessionAuthenticationStrategy instance used by the SessionManagementFilter
attribute session-authentication-strategy-ref {xsd:token}?
session-management.attlist &=
## Defines the URL of the error page which should be shown when the SessionAuthenticationStrategy raises an exception. If not set, an unauthorized (402) error code will be returned to the client. Note that this attribute doesn't apply if the error occurs during a form-based login, where the URL for authentication failure will take precedence.
## Defines the URL of the error page which should be shown when the SessionAuthenticationStrategy raises an exception. If not set, an unauthorized (401) error code will be returned to the client. Note that this attribute doesn't apply if the error occurs during a form-based login, where the URL for authentication failure will take precedence.
attribute session-authentication-error-url {xsd:token}?
@@ -553,7 +553,7 @@ remember-me =
## Sets up remember-me authentication. If used with the "key" attribute (or no attributes) the cookie-only implementation will be used. Specifying "token-repository-ref" or "remember-me-data-source-ref" will use the more secure, persisten token approach.
element remember-me {remember-me.attlist}
remember-me.attlist &=
## The "key" used to identify cookies from a specific token-based remember-me application. You should set this to a unique value for your application. If unset, it will default to a random value generated by SecureRandom.
## The "key" used to identify cookies from a specific token-based remember-me application. You should set this to a unique value for your application.
attribute key {xsd:token}?
remember-me.attlist &=
@@ -593,7 +593,7 @@ anonymous =
## Adds support for automatically granting all anonymous web requests a particular principal identity and a corresponding granted authority.
element anonymous {anonymous.attlist}
anonymous.attlist &=
## The key shared between the provider and filter. This generally does not need to be set. If unset, it will default to a random value generated by SecureRandom.
## The key shared between the provider and filter. This generally does not need to be set. If unset, it will default to "doesNotMatter".
attribute key {xsd:token}?
anonymous.attlist &=
## The username that should be assigned to the anonymous request. This allows the principal to be identified, which may be important for logging and auditing. if unset, defaults to "anonymousUser".
@@ -739,4 +739,4 @@ position =
## The explicit position at which the custom-filter should be placed in the chain. Use if you are replacing a standard filter.
attribute position {named-security-filter}
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "CONCURRENT_SESSION_FILTER" | "SECURITY_CONTEXT_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" |"BASIC_AUTH_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "SESSION_MANAGEMENT_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "SECURITY_CONTEXT_FILTER" | "CONCURRENT_SESSION_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" | "LOGIN_PAGE_FILTER" | "DIGEST_AUTH_FILTER" |"BASIC_AUTH_FILTER" | "REQUEST_CACHE_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "JAAS_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "SESSION_MANAGEMENT_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
@@ -868,7 +868,7 @@
<xs:documentation>Container element for HTTP security configuration. Multiple elements can now be defined,
each with a specific pattern to which the enclosed security configuration applies. A
pattern can also be configured to bypass Spring Security's filters completely by setting
the "secured" attribute to "false".
the "security" attribute to "none".
</xs:documentation>
</xs:annotation>
<xs:complexType>
@@ -1695,7 +1695,7 @@
<xs:attribute name="session-authentication-error-url" type="xs:token">
<xs:annotation>
<xs:documentation>Defines the URL of the error page which should be shown when the
SessionAuthenticationStrategy raises an exception. If not set, an unauthorized (402) error
SessionAuthenticationStrategy raises an exception. If not set, an unauthorized (401) error
code will be returned to the client. Note that this attribute doesn't apply if the error
occurs during a form-based login, where the URL for authentication failure will take
precedence.
@@ -1748,8 +1748,7 @@
<xs:attribute name="key" type="xs:token">
<xs:annotation>
<xs:documentation>The "key" used to identify cookies from a specific token-based remember-me application.
You should set this to a unique value for your application. If unset, it will default to a
random value generated by SecureRandom.
You should set this to a unique value for your application.
</xs:documentation>
</xs:annotation>
</xs:attribute>
@@ -1832,7 +1831,7 @@
<xs:attribute name="key" type="xs:token">
<xs:annotation>
<xs:documentation>The key shared between the provider and filter. This generally does not need to be set. If
unset, it will default to a random value generated by SecureRandom.
unset, it will default to "doesNotMatter".
</xs:documentation>
</xs:annotation>
</xs:attribute>
@@ -2293,20 +2292,24 @@
<xs:restriction base="xs:token">
<xs:enumeration value="FIRST"/>
<xs:enumeration value="CHANNEL_FILTER"/>
<xs:enumeration value="CONCURRENT_SESSION_FILTER"/>
<xs:enumeration value="SECURITY_CONTEXT_FILTER"/>
<xs:enumeration value="CONCURRENT_SESSION_FILTER"/>
<xs:enumeration value="LOGOUT_FILTER"/>
<xs:enumeration value="X509_FILTER"/>
<xs:enumeration value="PRE_AUTH_FILTER"/>
<xs:enumeration value="CAS_FILTER"/>
<xs:enumeration value="FORM_LOGIN_FILTER"/>
<xs:enumeration value="OPENID_FILTER"/>
<xs:enumeration value="LOGIN_PAGE_FILTER"/>
<xs:enumeration value="DIGEST_AUTH_FILTER"/>
<xs:enumeration value="BASIC_AUTH_FILTER"/>
<xs:enumeration value="REQUEST_CACHE_FILTER"/>
<xs:enumeration value="SERVLET_API_SUPPORT_FILTER"/>
<xs:enumeration value="JAAS_API_SUPPORT_FILTER"/>
<xs:enumeration value="REMEMBER_ME_FILTER"/>
<xs:enumeration value="ANONYMOUS_FILTER"/>
<xs:enumeration value="EXCEPTION_TRANSLATION_FILTER"/>
<xs:enumeration value="SESSION_MANAGEMENT_FILTER"/>
<xs:enumeration value="EXCEPTION_TRANSLATION_FILTER"/>
<xs:enumeration value="FILTER_SECURITY_INTERCEPTOR"/>
<xs:enumeration value="SWITCH_USER_FILTER"/>
<xs:enumeration value="LAST"/>
@@ -280,7 +280,7 @@ http-firewall =
element http-firewall {ref}
http =
## Container element for HTTP security configuration. Multiple elements can now be defined, each with a specific pattern to which the enclosed security configuration applies. A pattern can also be configured to bypass Spring Security's filters completely by setting the "secured" attribute to "false".
## Container element for HTTP security configuration. Multiple elements can now be defined, each with a specific pattern to which the enclosed security configuration applies. A pattern can also be configured to bypass Spring Security's filters completely by setting the "security" attribute to "none".
element http {http.attlist, (intercept-url* & access-denied-handler? & form-login? & openid-login? & x509? & jee? & http-basic? & logout? & session-management & remember-me? & anonymous? & port-mappings & custom-filter* & request-cache? & expression-handler? & headers? & csrf?) }
http.attlist &=
## The request URL pattern which will be mapped to the filter chain created by this <http> element. If omitted, the filter chain will match all requests.
@@ -357,7 +357,7 @@ intercept-url.attlist &=
attribute access {xsd:token}?
intercept-url.attlist &=
## The HTTP Method for which the access configuration attributes should apply. If not specified, the attributes will apply to any method.
attribute method {"GET" | "DELETE" | "HEAD" | "OPTIONS" | "POST" | "PUT" | "TRACE"}?
attribute method {"GET" | "DELETE" | "HEAD" | "OPTIONS" | "POST" | "PUT" | "PATCH" | "TRACE"}?
intercept-url.attlist &=
## The filter list for the path. Currently can be set to "none" to remove a path from having any filters applied. The full filter stack (consisting of all filters created by the namespace configuration, and any added using 'custom-filter'), will be applied to any other paths.
@@ -524,7 +524,7 @@ session-management.attlist &=
## Allows injection of the SessionAuthenticationStrategy instance used by the SessionManagementFilter
attribute session-authentication-strategy-ref {xsd:token}?
session-management.attlist &=
## Defines the URL of the error page which should be shown when the SessionAuthenticationStrategy raises an exception. If not set, an unauthorized (402) error code will be returned to the client. Note that this attribute doesn't apply if the error occurs during a form-based login, where the URL for authentication failure will take precedence.
## Defines the URL of the error page which should be shown when the SessionAuthenticationStrategy raises an exception. If not set, an unauthorized (401) error code will be returned to the client. Note that this attribute doesn't apply if the error occurs during a form-based login, where the URL for authentication failure will take precedence.
attribute session-authentication-error-url {xsd:token}?
@@ -572,7 +572,7 @@ remember-me.attlist &=
remember-me.attlist &=
## The period (in seconds) for which the remember-me cookie should be valid.
attribute token-validity-seconds {xsd:integer}?
attribute token-validity-seconds {xsd:string}?
remember-me.attlist &=
## Reference to an AuthenticationSuccessHandler bean which should be used to handle a successful remember-me authentication.
@@ -746,7 +746,7 @@ hsts-options.attlist &=
attribute request-matcher-ref { xsd:token }?
cache-control =
## Adds Cache-Control no-cache, no-store, must-revalidate and Pragma no-cache every URL
## Adds Cache-Control no-cache, no-store, must-revalidate, Pragma no-cache, and Expires 0 for every request
element cache-control {empty}
frame-options =
@@ -818,4 +818,4 @@ position =
## The explicit position at which the custom-filter should be placed in the chain. Use if you are replacing a standard filter.
attribute position {named-security-filter}
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "CONCURRENT_SESSION_FILTER" | "HEADERS_FILTER" | "CSRF_FILTER" | "SECURITY_CONTEXT_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" |"BASIC_AUTH_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "SESSION_MANAGEMENT_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
named-security-filter = "FIRST" | "CHANNEL_FILTER" | "SECURITY_CONTEXT_FILTER" | "CONCURRENT_SESSION_FILTER" | "WEB_ASYNC_MANAGER_FILTER" | "HEADERS_FILTER" | "CSRF_FILTER" | "LOGOUT_FILTER" | "X509_FILTER" | "PRE_AUTH_FILTER" | "CAS_FILTER" | "FORM_LOGIN_FILTER" | "OPENID_FILTER" | "LOGIN_PAGE_FILTER" | "DIGEST_AUTH_FILTER" | "BASIC_AUTH_FILTER" | "REQUEST_CACHE_FILTER" | "SERVLET_API_SUPPORT_FILTER" | "JAAS_API_SUPPORT_FILTER" | "REMEMBER_ME_FILTER" | "ANONYMOUS_FILTER" | "SESSION_MANAGEMENT_FILTER" | "EXCEPTION_TRANSLATION_FILTER" | "FILTER_SECURITY_INTERCEPTOR" | "SWITCH_USER_FILTER" | "LAST"
@@ -868,7 +868,7 @@
<xs:documentation>Container element for HTTP security configuration. Multiple elements can now be defined,
each with a specific pattern to which the enclosed security configuration applies. A
pattern can also be configured to bypass Spring Security's filters completely by setting
the "secured" attribute to "false".
the "security" attribute to "none".
</xs:documentation>
</xs:annotation>
<xs:complexType>
@@ -1248,6 +1248,7 @@
<xs:enumeration value="OPTIONS"/>
<xs:enumeration value="POST"/>
<xs:enumeration value="PUT"/>
<xs:enumeration value="PATCH"/>
<xs:enumeration value="TRACE"/>
</xs:restriction>
</xs:simpleType>
@@ -1702,7 +1703,7 @@
<xs:attribute name="session-authentication-error-url" type="xs:token">
<xs:annotation>
<xs:documentation>Defines the URL of the error page which should be shown when the
SessionAuthenticationStrategy raises an exception. If not set, an unauthorized (402) error
SessionAuthenticationStrategy raises an exception. If not set, an unauthorized (401) error
code will be returned to the client. Note that this attribute doesn't apply if the error
occurs during a form-based login, where the URL for authentication failure will take
precedence.
@@ -1795,7 +1796,7 @@
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="token-validity-seconds" type="xs:integer">
<xs:attribute name="token-validity-seconds" type="xs:string">
<xs:annotation>
<xs:documentation>The period (in seconds) for which the remember-me cookie should be valid.
</xs:documentation>
@@ -2314,7 +2315,8 @@
</xs:attributeGroup>
<xs:element name="cache-control">
<xs:annotation>
<xs:documentation>Adds Cache-Control no-cache, no-store, must-revalidate and Pragma no-cache every URL
<xs:documentation>Adds Cache-Control no-cache, no-store, must-revalidate, Pragma no-cache, and Expires 0 for
every request
</xs:documentation>
</xs:annotation>
<xs:complexType/>
@@ -2504,22 +2506,27 @@
<xs:restriction base="xs:token">
<xs:enumeration value="FIRST"/>
<xs:enumeration value="CHANNEL_FILTER"/>
<xs:enumeration value="SECURITY_CONTEXT_FILTER"/>
<xs:enumeration value="CONCURRENT_SESSION_FILTER"/>
<xs:enumeration value="WEB_ASYNC_MANAGER_FILTER"/>
<xs:enumeration value="HEADERS_FILTER"/>
<xs:enumeration value="CSRF_FILTER"/>
<xs:enumeration value="SECURITY_CONTEXT_FILTER"/>
<xs:enumeration value="LOGOUT_FILTER"/>
<xs:enumeration value="X509_FILTER"/>
<xs:enumeration value="PRE_AUTH_FILTER"/>
<xs:enumeration value="CAS_FILTER"/>
<xs:enumeration value="FORM_LOGIN_FILTER"/>
<xs:enumeration value="OPENID_FILTER"/>
<xs:enumeration value="LOGIN_PAGE_FILTER"/>
<xs:enumeration value="DIGEST_AUTH_FILTER"/>
<xs:enumeration value="BASIC_AUTH_FILTER"/>
<xs:enumeration value="REQUEST_CACHE_FILTER"/>
<xs:enumeration value="SERVLET_API_SUPPORT_FILTER"/>
<xs:enumeration value="JAAS_API_SUPPORT_FILTER"/>
<xs:enumeration value="REMEMBER_ME_FILTER"/>
<xs:enumeration value="ANONYMOUS_FILTER"/>
<xs:enumeration value="EXCEPTION_TRANSLATION_FILTER"/>
<xs:enumeration value="SESSION_MANAGEMENT_FILTER"/>
<xs:enumeration value="EXCEPTION_TRANSLATION_FILTER"/>
<xs:enumeration value="FILTER_SECURITY_INTERCEPTOR"/>
<xs:enumeration value="SWITCH_USER_FILTER"/>
<xs:enumeration value="LAST"/>
@@ -42,6 +42,7 @@ abstract class AbstractXmlConfigTests extends Specification {
def mockBean(Class clazz, String id = clazz.simpleName) {
xml.'b:bean'(id: id, 'class': Mockito.class.name, 'factory-method':'mock') {
'b:constructor-arg'(value : clazz.name)
'b:constructor-arg'(value : id)
}
}
@@ -20,6 +20,7 @@ import javax.servlet.Filter
import org.springframework.beans.factory.NoSuchBeanDefinitionException
import org.springframework.context.ConfigurableApplicationContext
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Configuration;
import org.springframework.mock.web.MockFilterChain
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.mock.web.MockHttpServletResponse
@@ -27,6 +28,9 @@ import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessor;
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
import org.springframework.security.core.Authentication
import org.springframework.security.core.authority.AuthorityUtils
import org.springframework.security.core.context.SecurityContextHolder
@@ -36,6 +40,7 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
import org.springframework.security.web.context.HttpRequestResponseHolder
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
import org.springframework.security.web.csrf.CsrfToken
import org.springframework.security.web.csrf.DefaultCsrfToken;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository
import spock.lang.AutoCleanup
@@ -48,13 +53,17 @@ import spock.lang.Specification
abstract class BaseSpringSpec extends Specification {
@AutoCleanup
ConfigurableApplicationContext context
@AutoCleanup
ConfigurableApplicationContext oppContext
MockHttpServletRequest request
MockHttpServletResponse response
MockFilterChain chain
CsrfToken csrfToken
AuthenticationManagerBuilder authenticationBldr
def setup() {
authenticationBldr = createAuthenticationManagerBuilder()
setupWeb(null)
}
@@ -68,14 +77,12 @@ abstract class BaseSpringSpec extends Specification {
setupCsrf()
}
def setupCsrf(csrfTokenValue="BaseSpringSpec_CSRFTOKEN") {
csrfToken = new CsrfToken("X-CSRF-TOKEN","_csrf",csrfTokenValue)
new HttpSessionCsrfTokenRepository().saveToken(csrfToken, request,response)
request.setParameter(csrfToken.parameterName, csrfToken.token)
def setupCsrf(csrfTokenValue="BaseSpringSpec_CSRFTOKEN",req=request,resp=response) {
csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN","_csrf",csrfTokenValue)
new HttpSessionCsrfTokenRepository().saveToken(csrfToken, req, resp)
req.setParameter(csrfToken.parameterName, csrfToken.token)
}
AuthenticationManagerBuilder authenticationBldr = new AuthenticationManagerBuilder(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR).inMemoryAuthentication().and()
def cleanup() {
SecurityContextHolder.clearContext()
}
@@ -148,4 +155,14 @@ abstract class BaseSpringSpec extends Specification {
repo.loadContext(requestResponseHolder)
repo.saveContext(new SecurityContextImpl(authentication:auth), requestResponseHolder.request, requestResponseHolder.response)
}
}
def createAuthenticationManagerBuilder() {
oppContext = new AnnotationConfigApplicationContext(ObjectPostProcessorConfiguration, AuthenticationConfiguration)
AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(objectPostProcessor)
auth.inMemoryAuthentication().and()
}
def getObjectPostProcessor() {
oppContext.getBean(ObjectPostProcessor)
}
}
@@ -38,7 +38,7 @@ class AuthenticationManagerBuilderTests extends BaseSpringSpec {
setup:
ObjectPostProcessor opp = Mock()
AuthenticationProvider provider = Mock()
AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR).objectPostProcessor(opp)
AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder(objectPostProcessor).objectPostProcessor(opp)
when: "Adding an AuthenticationProvider"
builder.authenticationProvider(provider)
builder.build()
@@ -47,11 +47,11 @@ class AuthenticationManagerBuilderTests extends BaseSpringSpec {
}
// https://github.com/SpringSource/spring-security-javaconfig/issues/132
def "#132 Custom AuthenticationEventPublisher with Web registerAuthentication"() {
def "#132 Custom AuthenticationEventPublisher with Web configure(AuthenticationManagerBuilder)"() {
setup:
AuthenticationEventPublisher aep = Mock()
when:
AuthenticationManager am = new AuthenticationManagerBuilder(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR)
AuthenticationManager am = new AuthenticationManagerBuilder(objectPostProcessor)
.authenticationEventPublisher(aep)
.inMemoryAuthentication()
.and()
@@ -78,7 +78,7 @@ class AuthenticationManagerBuilderTests extends BaseSpringSpec {
@EnableWebSecurity
@Configuration
static class MultiAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
@@ -35,8 +35,7 @@ import org.springframework.security.core.userdetails.UserDetailsService;
@Configuration
class BaseAuthenticationConfig {
@Autowired
protected void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
@@ -47,7 +47,7 @@ class NamespaceAuthenticationManagerTests extends BaseSpringSpec {
@EnableWebSecurity
@Configuration
static class EraseCredentialsTrueDefaultConfig extends WebSecurityConfigurerAdapter {
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
@@ -74,7 +74,7 @@ class NamespaceAuthenticationManagerTests extends BaseSpringSpec {
@EnableWebSecurity
@Configuration
static class EraseCredentialsFalseConfig extends WebSecurityConfigurerAdapter {
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.eraseCredentials(false)
.inMemoryAuthentication()
@@ -42,7 +42,7 @@ class NamespaceAuthenticationProviderTests extends BaseSpringSpec {
@Configuration
static class AuthenticationProviderRefConfig extends WebSecurityConfigurerAdapter {
static DaoAuthenticationProvider expected = new DaoAuthenticationProvider()
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(expected)
}
@@ -67,7 +67,7 @@ class NamespaceAuthenticationProviderTests extends BaseSpringSpec {
@Configuration
static class UserServiceRefConfig extends WebSecurityConfigurerAdapter {
static InMemoryUserDetailsManager expected = new InMemoryUserDetailsManager([] as Collection)
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(expected)
}
@@ -54,7 +54,7 @@ class NamespaceJdbcUserServiceTests extends BaseSpringSpec {
@Autowired
private DataSource dataSource;
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource) // jdbc-user-service@data-source-ref
@@ -84,7 +84,7 @@ class NamespaceJdbcUserServiceTests extends BaseSpringSpec {
@Autowired
private DataSource dataSource;
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource)
@@ -132,7 +132,7 @@ class NamespaceJdbcUserServiceTests extends BaseSpringSpec {
@Autowired
private DataSource dataSource;
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
// jdbc-user-service@dataSource
@@ -54,8 +54,7 @@ class NamespacePasswordEncoderTests extends BaseSpringSpec {
@Configuration
static class PasswordEncoderWithInMemoryConfig extends WebSecurityConfigurerAdapter {
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder()
auth
@@ -76,8 +75,7 @@ class NamespacePasswordEncoderTests extends BaseSpringSpec {
@Configuration
static class PasswordEncoderWithJdbcConfig extends WebSecurityConfigurerAdapter {
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder()
auth
@@ -106,8 +104,7 @@ class NamespacePasswordEncoderTests extends BaseSpringSpec {
@Configuration
static class PasswordEncoderWithUserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder()
User user = new User("user",encoder.encode("password"), AuthorityUtils.createAuthorityList("ROLE_USER"))
@@ -37,8 +37,7 @@ public class PasswordEncoderConfigurerConfigs {
@EnableWebSecurity
@Configuration
static class PasswordEncoderConfig extends WebSecurityConfigurerAdapter {
protected void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = passwordEncoder();
auth
.inMemoryAuthentication()
@@ -66,8 +65,7 @@ public class PasswordEncoderConfigurerConfigs {
@EnableWebSecurity
@Configuration
static class PasswordEncoderNoAuthManagerLoadsConfig extends WebSecurityConfigurerAdapter {
protected void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = passwordEncoder();
auth
.inMemoryAuthentication()
@@ -0,0 +1,25 @@
/*
* 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.configuration;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class AroundMethodInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
return String.valueOf(methodInvocation.proceed());
}
}
@@ -15,25 +15,23 @@
*/
package org.springframework.security.config.annotation.configuration
import javax.servlet.ServletConfig
import javax.servlet.ServletContext
import org.springframework.beans.factory.BeanClassLoaderAware
import org.springframework.beans.factory.BeanFactoryAware
import org.springframework.beans.factory.BeanNameAware
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.DisposableBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.config.AutowireCapableBeanFactory
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.ApplicationContextAware
import org.springframework.context.ApplicationEventPublisherAware
import org.springframework.context.EnvironmentAware
import org.springframework.context.MessageSourceAware
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.support.ClassPathXmlApplicationContext
import org.springframework.mock.web.MockServletConfig
import org.springframework.mock.web.MockServletContext
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessor;
import org.springframework.security.config.annotation.ObjectPostProcessor
import org.springframework.web.context.ServletConfigAware
import org.springframework.web.context.ServletContextAware
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext
@@ -117,4 +115,27 @@ class AutowireBeanFactoryObjectPostProcessorTests extends BaseSpringSpec {
return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
}
}
def "SEC-2382: AutowireBeanFactoryObjectPostProcessor works with BeanNameAutoProxyCreator"() {
when:
// must load with XML for BeanPostProcessors to work
context = new ClassPathXmlApplicationContext("AutowireBeanFactoryObjectPostProcessorTests-aopconfig.xml", getClass());
then:
noExceptionThrown()
and: "make sure autoproxying was actually enabled"
context.getBean(MyAdvisedBean).doStuff() == "null"
}
@Configuration
static class WithBanNameAutoProxyCreatorConfig {
@Bean
public ObjectPostProcessor objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
return new AutowireBeanFactoryObjectPostProcessor(beanFactory)
}
@Autowired
public void configure(ObjectPostProcessor<Object> p) {
p.postProcess(new Object())
}
}
}
@@ -0,0 +1,23 @@
/*
* 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.configuration;
public class MyAdvisedBean {
public Object doStuff() {
return null;
}
}
@@ -18,24 +18,27 @@ package org.springframework.security.config.annotation.method.configuration
import static org.fest.assertions.Assertions.assertThat
import static org.junit.Assert.fail
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInterceptor
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionManager
import org.springframework.context.ApplicationListener
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.access.AccessDeniedException
import org.springframework.security.access.ConfigAttribute
import org.springframework.security.access.PermissionEvaluator
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.AuthenticationTrustResolver
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher
import org.springframework.security.authentication.TestingAuthenticationToken
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
import org.springframework.security.config.annotation.web.WebSecurityConfigurerAdapterTests.InMemoryAuthWithWebSecurityConfigurerAdapter
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.core.Authentication
import org.springframework.security.core.authority.AuthorityUtils
import org.springframework.security.core.context.SecurityContextHolder
/**
*
@@ -67,8 +70,7 @@ public class GlobalMethodSecurityConfigurationTests extends BaseSpringSpec {
static AuthenticationSuccessEvent EVENT
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@@ -82,4 +84,221 @@ public class GlobalMethodSecurityConfigurationTests extends BaseSpringSpec {
AuthenticationManager getAuthenticationManager() {
context.getBean(MethodInterceptor).authenticationManager
}
def "AuthenticationTrustResolver autowires"() {
setup:
CustomTrustResolverConfig.TR = Mock(AuthenticationTrustResolver)
when:
loadConfig(CustomTrustResolverConfig)
def preAdviceVoter = context.getBean(MethodInterceptor).accessDecisionManager.decisionVoters.find { it instanceof PreInvocationAuthorizationAdviceVoter}
then:
preAdviceVoter.preAdvice.expressionHandler.trustResolver == CustomTrustResolverConfig.TR
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class CustomTrustResolverConfig extends GlobalMethodSecurityConfiguration {
static AuthenticationTrustResolver TR
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Bean
public AuthenticationTrustResolver tr() {
return TR
}
}
def "SEC-2301: DefaultWebSecurityExpressionHandler has BeanResolver set"() {
setup:
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
loadConfig(ExpressionHandlerHasBeanResolverSetConfig)
def service = context.getBean(ServiceImpl)
when: "service with bean reference on PreAuthorize invoked"
service.message()
then: "properly throws AccessDeniedException"
thrown(AccessDeniedException)
when: "service with bean reference on PreAuthorize invoked"
context.getBean(CustomAuthzService).grantAccess = true
service.message()
then: "grants access too"
noExceptionThrown()
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
static class ExpressionHandlerHasBeanResolverSetConfig extends GlobalMethodSecurityConfiguration {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Bean
public ServiceImpl service() {
return new ServiceImpl()
}
@Bean
public CustomAuthzService authz() {
return new CustomAuthzService()
}
}
static class ServiceImpl {
@PreAuthorize("@authz.authorize()")
public String message() {
null
}
}
static class CustomAuthzService {
boolean grantAccess
public boolean authorize() {
grantAccess
}
}
def "Method Security supports annotations on interface parameter names"() {
setup:
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
loadConfig(MethodSecurityServiceConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when: "service with annotated argument"
service.postAnnotation('deny')
then: "properly throws AccessDeniedException"
thrown(AccessDeniedException)
when: "service with annotated argument"
service.postAnnotation('grant')
then: "properly throws AccessDeniedException"
noExceptionThrown()
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class MethodSecurityServiceConfig extends GlobalMethodSecurityConfiguration {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Bean
public MethodSecurityService service() {
new MethodSecurityServiceImpl()
}
}
def "GlobalMethodSecurityConfiguration autowires PermissionEvaluator"() {
setup:
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
PermissionEvaluator evaluator = Mock()
AutowirePermissionEvaluatorConfig.PE = evaluator
loadConfig(AutowirePermissionEvaluatorConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.hasPermission("something")
then:
1 * evaluator.hasPermission(_, "something", "read") >> true
when:
service.hasPermission("something")
then:
1 * evaluator.hasPermission(_, "something", "read") >> false
thrown(AccessDeniedException)
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class AutowirePermissionEvaluatorConfig extends GlobalMethodSecurityConfiguration {
static PermissionEvaluator PE
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Bean
public PermissionEvaluator pe() {
PE
}
@Bean
public MethodSecurityService service() {
new MethodSecurityServiceImpl()
}
}
def "GlobalMethodSecurityConfiguration does not failw with multiple PermissionEvaluator"() {
when:
loadConfig(MultiPermissionEvaluatorConfig)
then:
noExceptionThrown()
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class MultiPermissionEvaluatorConfig extends GlobalMethodSecurityConfiguration {
static PermissionEvaluator PE
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Bean
public PermissionEvaluator pe() {
PE
}
@Bean
public PermissionEvaluator pe2() {
PE
}
@Bean
public MethodSecurityService service() {
new MethodSecurityServiceImpl()
}
}
def "SEC-2425: EnableGlobalMethodSecurity works on superclass"() {
setup:
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
loadConfig(ParentConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
}
static class ChildConfig extends ParentConfig {}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class ParentConfig {
@Autowired
protected void configurGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Bean
public MethodSecurityService service() {
new MethodSecurityServiceImpl()
}
}
}
@@ -16,8 +16,10 @@
package org.springframework.security.config.annotation.method.configuration;
import javax.annotation.security.DenyAll
import javax.annotation.security.PermitAll;
import org.springframework.security.access.annotation.Secured
import org.springframework.security.access.method.P
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.security.core.Authentication
@@ -34,9 +36,15 @@ public interface MethodSecurityService {
@Secured("ROLE_ADMIN")
public String secured();
@Secured("ROLE_USER")
public String securedUser();
@DenyAll
public String jsr250();
@PermitAll
public String jsr250PermitAll();
@Secured(["ROLE_USER","RUN_AS_SUPER"])
public Authentication runAs();
@@ -48,4 +56,7 @@ public interface MethodSecurityService {
@PostAuthorize("hasPermission(#object,'read')")
public String postHasPermission(String object);
@PostAuthorize("#o?.contains('grant')")
public String postAnnotation(@P("o") String object);
}
@@ -35,11 +35,21 @@ public class MethodSecurityServiceImpl implements MethodSecurityService {
return null;
}
@Override
public String securedUser() {
return null;
}
@Override
public String jsr250() {
return null;
}
@Override
public String jsr250PermitAll() {
return null;
}
@Override
public Authentication runAs() {
return SecurityContextHolder.getContext().getAuthentication();
@@ -59,4 +69,9 @@ public class MethodSecurityServiceImpl implements MethodSecurityService {
public String postHasPermission(String object) {
return null;
}
@Override
public String postAnnotation(String object) {
return null;
}
}
@@ -77,7 +77,7 @@ public class NamespaceGlobalMethodSecurityExpressionHandlerTests extends BaseSpr
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class CustomAccessDecisionManagerConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler expressionHandler() {
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler()
expressionHandler.permissionEvaluator = new PermissionEvaluator() {
boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
@@ -134,6 +134,10 @@ public class NamespaceGlobalMethodSecurityTests extends BaseSpringSpec {
service.jsr250()
then: "access is denied"
thrown(AccessDeniedException)
when: "@PermitAll method invoked"
String jsr250PermitAll = service.jsr250PermitAll()
then: "access is allowed"
jsr250PermitAll == null
}
@EnableGlobalMethodSecurity(jsr250Enabled = true)
@@ -345,6 +349,9 @@ public class NamespaceGlobalMethodSecurityTests extends BaseSpringSpec {
service.secured()
then:
thrown(AccessDeniedException)
and: "service with ROLE_USER allowed"
service.securedUser() == null
and:
service.preAuthorize() == null
service.jsr250() == null
}
@@ -67,7 +67,7 @@ public class SampleEnableGlobalMethodSecurityTests extends BaseSpringSpec {
}
@Autowired
public void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
@@ -97,15 +97,14 @@ public class SampleEnableGlobalMethodSecurityTests extends BaseSpringSpec {
}
@Override
protected MethodSecurityExpressionHandler expressionHandler() {
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator());
return expressionHandler;
}
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
@@ -16,6 +16,7 @@
package org.springframework.security.config.annotation.web
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityConfigurer
import org.springframework.security.config.annotation.SecurityConfigurerAdapter
@@ -27,9 +28,13 @@ import spock.lang.Specification
* @author Rob Winch
*
*/
class AbstractConfiguredSecurityBuilderTests extends Specification {
class AbstractConfiguredSecurityBuilderTests extends BaseSpringSpec {
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder()
ConcreteAbstractConfiguredBuilder builder
def setup() {
builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor)
}
def "Null ObjectPostProcessor rejected"() {
when:
@@ -86,7 +91,7 @@ class AbstractConfiguredSecurityBuilderTests extends Specification {
def "getConfigurer with multi fails"() {
setup:
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR, true)
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
builder.apply(new DelegateConfigurer())
builder.apply(new DelegateConfigurer())
when:
@@ -97,7 +102,7 @@ class AbstractConfiguredSecurityBuilderTests extends Specification {
def "removeConfigurer with multi fails"() {
setup:
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR, true)
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
builder.apply(new DelegateConfigurer())
builder.apply(new DelegateConfigurer())
when:
@@ -110,7 +115,7 @@ class AbstractConfiguredSecurityBuilderTests extends Specification {
setup:
DelegateConfigurer c1 = new DelegateConfigurer()
DelegateConfigurer c2 = new DelegateConfigurer()
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR, true)
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
builder.apply(c1)
builder.apply(c2)
when:
@@ -126,7 +131,7 @@ class AbstractConfiguredSecurityBuilderTests extends Specification {
setup:
DelegateConfigurer c1 = new DelegateConfigurer()
DelegateConfigurer c2 = new DelegateConfigurer()
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR, true)
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
builder.apply(c1)
builder.apply(c2)
when:
@@ -150,10 +155,7 @@ class AbstractConfiguredSecurityBuilderTests extends Specification {
private static class ConcreteConfigurer extends SecurityConfigurerAdapter<Object, ConcreteAbstractConfiguredBuilder> { }
private static class ConcreteAbstractConfiguredBuilder extends AbstractConfiguredSecurityBuilder<Object, ConcreteAbstractConfiguredBuilder> {
public ConcreteAbstractConfiguredBuilder() {
}
private class ConcreteAbstractConfiguredBuilder extends AbstractConfiguredSecurityBuilder<Object, ConcreteAbstractConfiguredBuilder> {
public ConcreteAbstractConfiguredBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
super(objectPostProcessor);
@@ -15,11 +15,11 @@
*/
package org.springframework.security.config.annotation.web;
import static org.springframework.security.config.annotation.web.AbstractRequestMatcherConfigurer.RequestMatchers.*
import static org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.RequestMatchers.*
import org.springframework.http.HttpMethod;
import org.springframework.security.web.util.AntPathRequestMatcher;
import org.springframework.security.web.util.RegexRequestMatcher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import spock.lang.Specification;
@@ -91,7 +91,7 @@ public class SampleWebSecurityConfigurerAdapterTests extends BaseSpringSpec {
@EnableWebSecurity
public static class HelloWorldWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) {
protected void configure(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
@@ -179,7 +179,7 @@ public class SampleWebSecurityConfigurerAdapterTests extends BaseSpringSpec {
}
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) {
protected void configure(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
@@ -276,7 +276,7 @@ public class SampleWebSecurityConfigurerAdapterTests extends BaseSpringSpec {
@EnableWebSecurity
public static class SampleMultiHttpSecurityConfig {
@Autowired
public void registerAuthentication(AuthenticationManagerBuilder auth) {
protected void configure(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
@@ -27,8 +27,12 @@ import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationListener
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.Ordered
import org.springframework.core.annotation.AnnotationAwareOrderComparator
import org.springframework.core.annotation.Order
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.authentication.AuthenticationTrustResolver
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.authentication.event.AuthenticationSuccessEvent
@@ -41,7 +45,7 @@ import org.springframework.security.core.Authentication
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.core.userdetails.UsernameNotFoundException
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter
import org.springframework.web.accept.ContentNegotiationStrategy
import org.springframework.web.accept.HeaderContentNegotiationStrategy
import org.springframework.web.filter.OncePerRequestFilter
@@ -77,10 +81,10 @@ class WebSecurityConfigurerAdapterTests extends BaseSpringSpec {
responseHeaders == ['X-Content-Type-Options':'nosniff',
'X-Frame-Options':'DENY',
'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
'Cache-Control': 'no-cache,no-store,max-age=0,must-revalidate',
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
'Pragma':'no-cache',
'X-XSS-Protection' : '1; mode=block',
'X-CSRF-TOKEN' : csrfToken.token]
'Expires' : '0',
'X-XSS-Protection' : '1; mode=block']
}
@EnableWebSecurity
@@ -88,8 +92,7 @@ class WebSecurityConfigurerAdapterTests extends BaseSpringSpec {
static class HeadersArePopulatedByDefaultConfig extends WebSecurityConfigurerAdapter {
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
@@ -113,8 +116,7 @@ class WebSecurityConfigurerAdapterTests extends BaseSpringSpec {
static class WebAsyncPopulatedByDefaultConfig extends WebSecurityConfigurerAdapter {
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
@@ -126,7 +128,7 @@ class WebSecurityConfigurerAdapterTests extends BaseSpringSpec {
}
}
def "AuthenticationEventPublisher is registered for Web registerAuthentication"() {
def "AuthenticationEventPublisher is registered for Web configure(AuthenticationManagerBuilder auth)"() {
when:
loadConfig(InMemoryAuthWithWebSecurityConfigurerAdapter)
then:
@@ -151,8 +153,7 @@ class WebSecurityConfigurerAdapterTests extends BaseSpringSpec {
}
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
@@ -235,14 +236,26 @@ class WebSecurityConfigurerAdapterTests extends BaseSpringSpec {
}
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
}
def "SEC-2274: WebSecurityConfigurer adds ApplicationContext as a shared object"() {
when:
loadConfig(ApplicationContextSharedObjectConfig)
then:
context.getBean(ApplicationContextSharedObjectConfig).http.getSharedObject(ApplicationContext) == context
}
@Configuration
@EnableWebSecurity
static class ApplicationContextSharedObjectConfig extends WebSecurityConfigurerAdapter {
}
static class MyFilter extends OncePerRequestFilter {
private UserDetailsService userDetailsService
public MyFilter(UserDetailsService uds) {
@@ -253,4 +266,38 @@ class WebSecurityConfigurerAdapterTests extends BaseSpringSpec {
chain.doFilter(request,response)
}
}
def "AuthenticationTrustResolver populated as defaultObject"() {
setup:
CustomTrustResolverConfig.TR = Mock(AuthenticationTrustResolver)
when:
loadConfig(CustomTrustResolverConfig)
then:
context.getBean(CustomTrustResolverConfig).http.getSharedObject(AuthenticationTrustResolver) == CustomTrustResolverConfig.TR
}
@Configuration
@EnableWebSecurity
static class CustomTrustResolverConfig extends WebSecurityConfigurerAdapter {
static AuthenticationTrustResolver TR
@Bean
public AuthenticationTrustResolver tr() {
return TR
}
}
def "WebSecurityConfigurerAdapter has Ordered between 0 and lowest priority"() {
when:
def lowestConfig = new LowestPriorityWebSecurityConfig()
def defaultConfig = new DefaultOrderWebSecurityConfig()
def compare = new AnnotationAwareOrderComparator()
then: "the default ordering is between 0 and lowest priority (Boot adapters)"
compare.compare(lowestConfig, defaultConfig) > 0
}
class DefaultOrderWebSecurityConfig extends WebSecurityConfigurerAdapter {}
@Order(Ordered.LOWEST_PRECEDENCE)
class LowestPriorityWebSecurityConfig extends WebSecurityConfigurerAdapter {}
}
@@ -61,8 +61,7 @@ public class WebSecurityConfigurerAdapterTestsConfigs {
}
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth)
throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication().and()
.jdbcAuthentication()
@@ -0,0 +1,34 @@
/*
* 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.builders;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.BaseWebConfig;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.UrlAuthorizationConfigurer;
@Configuration
@EnableWebSecurity
public class DisableUseExpressionsConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
// This config is also on UrlAuthorizationConfigurer javadoc
http
.apply(new UrlAuthorizationConfigurer<HttpSecurity>()).getRegistry()
.antMatchers("/users**","/sessions/**").hasRole("USER")
.antMatchers("/signup").hasRole("ANONYMOUS")
.anyRequest().hasRole("USER");
}
}
@@ -50,8 +50,8 @@ import org.springframework.security.web.savedrequest.NullRequestCache
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter
import org.springframework.security.web.session.SessionManagementFilter
import org.springframework.security.web.util.RegexRequestMatcher
import org.springframework.security.web.util.RequestMatcher
import org.springframework.security.web.util.matcher.RegexRequestMatcher
import org.springframework.security.web.util.matcher.RequestMatcher
/**
* Tests to verify that all the functionality of <http> attributes is present
@@ -331,16 +331,21 @@ public class NamespaceHttpTests extends BaseSpringSpec {
// http@pattern is not available (instead see the tests http@request-matcher-ref ant or http@request-matcher-ref regex)
def "http@realm"() {
when:
setup:
loadConfig(RealmConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
findFilter(BasicAuthenticationFilter).authenticationEntryPoint.realmName == "RealmConfig"
response.getHeader("WWW-Authenticate") == 'Basic realm="RealmConfig"'
}
@Configuration
static class RealmConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic().realmName("RealmConfig")
}
}
@@ -496,16 +501,4 @@ public class NamespaceHttpTests extends BaseSpringSpec {
findFilter(FilterSecurityInterceptor).securityMetadataSource.class == DefaultFilterInvocationSecurityMetadataSource
findFilter(FilterSecurityInterceptor).accessDecisionManager.decisionVoters.collect { it.class } == [RoleVoter, AuthenticatedVoter]
}
@Configuration
@EnableWebSecurity
static class DisableUseExpressionsConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.apply(new UrlAuthorizationConfigurer())
.antMatchers("/users**","/sessions/**").hasRole("USER")
.antMatchers("/signup").hasRole("ANONYMOUS")
.anyRequest().hasRole("USER")
}
}
}
@@ -32,8 +32,7 @@ public abstract class BaseWebConfig extends WebSecurityConfigurerAdapter {
BaseWebConfig() {
}
protected void registerAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()

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