1
0
mirror of synced 2026-07-11 05:40:02 +00:00

Compare commits

...

112 Commits

Author SHA1 Message Date
Spring Buildmaster afcad4f0d4 Release version 3.2.3.RELEASE 2014-03-25 12:04:52 -07:00
Rob Winch 32c767a30d SEC-2533: Global AuthenticationManagerBuilder disables clearing child credentials 2014-03-25 13:00:42 -05:00
Rob Winch a11746a8d1 SEC-2498: RequestCache allows POST when CSRF is disabled 2014-03-25 10:44:34 -05:00
Rob Winch a18265a163 SEC-2531: AuthenticationConfiguration#lazyBean should use BeanClassLoader 2014-03-24 14:54:02 -05:00
Rob Winch d7a2c0a98c SEC-2177: Polish 2014-03-18 15:49:20 -05:00
Maciej Zasada 9057fbe0ed SEC-2177: Striping off all leading schemes
Striping off all leading schemes in the DefaultRedirectStrategy, so it
will be less vulnerable to open redirect phishing attacks. More info can
be found at SEC-2177 JIRA issue.
2014-03-18 15:49:20 -05:00
Julien Dubois 537d8f974f SEC-2519: RememberMeAuthenticationException supports root cause
Added a constructor which keeps the root cause of the exception, and
added some documentation
2014-03-11 16:13:03 -05:00
Alexander Kjäll 783af4012b SEC-2518: UserDetailsService javadoc repeats "insensitive"
Typo in javadoc, "case insensitive" was repeated twice.
2014-03-11 15:38:28 -05:00
Spring Buildmaster 5f5b8052d8 Next development version 2014-03-10 15:24:45 -07:00
Rob Winch 7dbb8e777e SEC-2500: Prevent anonymous bind for ActiveDirectoryLdapAuthenticator 2014-03-10 14:21:32 -05:00
Rob Winch bb563967cc SEC-2507: WebExpressionVoter.supports support subclasses of FilterInvocation 2014-03-10 14:21:07 -05:00
Rob Winch 974105ed19 SEC-2515: Detect object cycle for AuthenticationManager configuration 2014-03-10 14:04:10 -05:00
Rob Winch 2cad2f401b SEC-2325: Polish CSRF Tag support
- Rename csrfField to csrfInput
- Make AbstractCsrfTag package scope
- rename FormFieldTag to CsrfInputTag
- rename MetaTagsTag to CsrfMetaTagsTag
- removed whitespace from tag output so output is
  minimized & improving browser performance
- Update @since
- changed test names to be more meaningful
2014-03-07 15:25:57 -06:00
beamerblvd 3048e2c6e7 SEC-2325 Added JSP tags for CSRF meta tags and form fields 2014-03-07 13:18:46 -06:00
beamerblvd 561f284718 SEC-2335 Added ACL schema files for MySQL, SQL Server, Oracle 2014-03-07 13:10:03 -06:00
John Tims afc6a6ee0d SEC-2514: Fix typo in hellomvc.asc
packags -> packages
2014-03-07 10:26:31 -06:00
John Tims fa05e9c590 SEC-2513: Add link to SpringSource CLA form 2014-03-07 10:22:36 -06:00
Manimaran Selvan 818be86d46 SEC-2512: Fix typo in reference`
udates -> updates
2014-03-06 22:21:22 -06:00
Rob Winch 60704eb50e SEC-2511: Remove double ALLOW-FROM in X-Frame-Options header 2014-03-06 22:00:09 -06:00
getvictor f02b77794f SEC-2511: Remove double ALLOW-FROM from X-Frame-Options header.
The interface documentation for getAllowFromValue states: Gets the value for ALLOW-FROM excluding the ALLOW-FROM.
2014-03-06 21:59:46 -06:00
Rob Winch 1172d44397 SEC-2499: Allow MethodSecurityExpressionHandler in parent context
Previously a NoSuchBeanDefintionException was thrown when the
MethodSecurityExpressionHandler was defined in the parent context. This
happened due to trying to work around ordering issues related to SEC-2136

This commit resolves this by not marking the
MethodSecurityExpressionHandler bean as lazy unless it exists.
2014-03-06 20:51:24 -06:00
Rob Winch 49738e4588 SEC-2508: Passivity test for SEC-2357 2014-03-06 15:13:34 -06:00
Rob Winch 3b13c1fdf4 SEC-2495: CSRF disables logout on GET 2014-02-20 09:33:30 -06:00
Spring Buildmaster 8f6450ede1 Next development version 2014-02-19 10:52:05 -06:00
Rob Winch f2cde4ffa3 SEC-2486: Update tests to Spring LDAP 2.0.1.RELEASE 2014-02-19 09:32:37 -06:00
Rob Winch 9810768186 SEC-2485: Update test to Spring 4.0.2.RELEASE 2014-02-19 09:31:46 -06:00
Rob Winch 7f99a2dfbb SEC-2487: Update to Spring 3.2.8.RELEASE 2014-02-19 09:30:40 -06:00
Rob Winch 85305050c0 SEC-2455: Fix XML default login generation 2014-02-18 13:52:05 -06:00
Rob Winch 8a3a7961cb SEC-2492: ExpressionUrlAuthorizationConfigurer private interceptUrl to void 2014-02-15 14:41:26 -06:00
Rob Winch fc8e4868ce SEC-2468: Fix tests 2014-02-15 14:25:46 -06:00
Rob Winch 65367e6547 SEC-2468: JdbcUserDetailsManager#createNewAuthentication uses null credentials 2014-02-14 16:53:26 -06:00
Rob Winch bf2df220ca SEC-2490: LdapAuthenticationProviderConfigurer allows custom LdapAuthoritiesPopulator 2014-02-13 16:37:33 -06:00
Rob Winch 152f41f61e SEC-2392: KeyBasedPersistenceTokenService uses bytes instead of bits
The method setPseudoRandomNumberBits actually sets the number of bytes. This
commit deprecates setPseudoRandomNumberBits and adds
setPseudoRandomNumberBytes. The default value is still 256 to remain passive
but will be updated in 4.x.
2014-02-13 15:36:47 -06:00
Rob Winch 7a3da28987 SEC-2479: Search parent context for AuthenticationManager 2014-02-12 08:11:26 -06:00
Rob Winch e17adad878 SEC-2469: Support Spring LDAP 2.0.1+ 2014-02-12 08:11:26 -06:00
Luke Taylor 058b9debef Minor slapd config changes 2014-02-11 14:23:54 +00:00
Rob Winch 6c35c33abe SEC-2447: Fix AuthenticationManagerBuilder ordering issues 2014-02-09 21:17:51 -06:00
Rob Winch c42e13c966 loginProcessing test 2014-02-07 17:01:11 -06:00
Rob Winch 6b42a2eae1 SEC-2461: Multi WebSecurityConfiguration does not create null springSecurityFilterChain 2014-02-07 17:01:11 -06:00
Rob Winch ec8b48150d SEC-2474: Update poms 2014-02-07 17:01:11 -06:00
Rob Winch 4eff50b48b SEC-2474: Update tests against Spring 4.0.1 2014-01-30 09:44:26 -06:00
Rob Winch 087b56da96 SEC-2473: Update to Spring 3.2.7 2014-01-30 09:44:26 -06:00
Rob Winch 8d8475deb1 SEC-2455: form-login@login-processing-url & logout@logout-url use matchers
Remove the deprecation warnings of using setFilterProcessingUrl by invoking
the matcher methods instead.
2014-01-29 15:35:18 -06:00
Rob Winch b5f5665ea6 SEC-2463: CSRF documentation includes EnableWebMvcSecurity 2014-01-29 09:28:51 -06:00
Rob Winch 3b05fd6fed SEC-2466: Add link to MultipartFilter in CSRF multipart section 2014-01-28 22:04:35 -06:00
Rob Winch 4c84805ac9 SEC-2466: CSRF MutipartFilter doc now uses <url-pattern> 2014-01-28 16:51:05 -06:00
james a99c6db327 SEC-2467: Fix Small errors in itest-web's jsps 2014-01-28 16:03:59 -06:00
Rob Winch 1f833b0d6b Add ExpressionUrlAuthorizationCOnfigurer tests
- Demo custom expression root
- Demo @Bean in expression example
2014-01-23 11:21:21 -06:00
Spring Buildmaster add3aae6ef Next development version 2013-12-16 11:27:25 -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
397 changed files with 7080 additions and 83777 deletions
+1
View File
@@ -19,3 +19,4 @@ build/
*.iws
.gradle/
atlassian-ide-plugin.xml
/samples
+1 -1
View File
@@ -16,7 +16,7 @@ Is there already an issue that addresses your concern? Do a bit of searching in
If you're considering anything more than correcting a typo or fixing a minor bug , please discuss it on the [Spring Security forums](http://forum.springsource.org/forumdisplay.php?33-Security) before submitting a pull request. We're happy to provide guidance but please spend an hour or two researching the subject on your own including searching the forums for prior discussions.
# Sign the Contributor License Agreement
If you have not previously done so, please fill out and submit the SpringSource CLA form. You'll receive a token when this process is complete. Keep track of this, you may be asked for it later!
If you have not previously done so, please fill out and submit the [SpringSource CLA form](https://support.springsource.com/spring_committer_signup). You'll receive a token when this process is complete. Keep track of this, you may be asked for it later!
* For **Project** select _Spring Security_
* For **Project Lead** enter _Rob Winch_
+18 -24
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.CI-SNAPSHOT</version>
<version>3.2.3.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.CI-SNAPSHOT</version>
<version>3.2.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -88,13 +82,13 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -132,7 +126,7 @@
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.10</version>
<version>2.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -150,19 +144,19 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.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() {
+2 -2
View File
@@ -5,12 +5,12 @@
-- drop table acl_class;
-- drop table acl_sid;
create table acl_sid(
id bigint generated by default as identity(start with 100) not null primary key,
principal boolean not null,
sid varchar_ignorecase(100) not null,
constraint unique_uk_1 unique(sid,principal));
constraint unique_uk_1 unique(sid,principal)
);
create table acl_class(
id bigint generated by default as identity(start with 100) not null primary key,
@@ -0,0 +1,46 @@
-- ACL Schema SQL for MySQL 5.5+ / MariaDB equivalent
-- drop table acl_entry;
-- drop table acl_object_identity;
-- drop table acl_class;
-- drop table acl_sid;
CREATE TABLE acl_sid (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
principal BOOLEAN NOT NULL,
sid VARCHAR(100) NOT NULL,
UNIQUE KEY unique_acl_sid (sid, principal)
) ENGINE=InnoDB;
CREATE TABLE acl_class (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
class VARCHAR(100) NOT NULL,
UNIQUE KEY uk_acl_class (class)
) ENGINE=InnoDB;
CREATE TABLE acl_object_identity (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
object_id_class BIGINT UNSIGNED NOT NULL,
object_id_identity BIGINT NOT NULL,
parent_object BIGINT UNSIGNED,
owner_sid BIGINT UNSIGNED,
entries_inheriting BOOLEAN NOT NULL,
UNIQUE KEY uk_acl_object_identity (object_id_class, object_id_identity),
CONSTRAINT fk_acl_object_identity_parent FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id),
CONSTRAINT fk_acl_object_identity_class FOREIGN KEY (object_id_class) REFERENCES acl_class (id),
CONSTRAINT fk_acl_object_identity_owner FOREIGN KEY (owner_sid) REFERENCES acl_sid (id)
) ENGINE=InnoDB;
CREATE TABLE acl_entry (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
acl_object_identity BIGINT UNSIGNED NOT NULL,
ace_order INTEGER NOT NULL,
sid BIGINT UNSIGNED NOT NULL,
mask INTEGER UNSIGNED NOT NULL,
granting BOOLEAN NOT NULL,
audit_success BOOLEAN NOT NULL,
audit_failure BOOLEAN NOT NULL,
UNIQUE KEY unique_acl_entry (acl_object_identity, ace_order),
CONSTRAINT fk_acl_entry_object FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity (id),
CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id)
) ENGINE=InnoDB;
@@ -0,0 +1,82 @@
-- ACL Schema SQL for Oracle Database 10g+
-- drop trigger acl_sid_id_trigger;
-- drop trigger acl_class_id_trigger;
-- drop trigger acl_object_identity_id_trigger;
-- drop trigger acl_entry_id_trigger;
-- drop sequence acl_sid_sequence;
-- drop sequence acl_class_sequence;
-- drop sequence acl_object_identity_sequence;
-- drop sequence acl_entry_sequence;
-- drop table acl_entry;
-- drop table acl_object_identity;
-- drop table acl_class;
-- drop table acl_sid;
CREATE TABLE acl_sid (
id NUMBER(38) NOT NULL PRIMARY KEY,
principal NUMBER(1) NOT NULL CHECK (principal in (0, 1)),
sid NVARCHAR2(100) NOT NULL,
CONSTRAINT unique_acl_sid UNIQUE (sid, principal)
);
CREATE SEQUENCE acl_sid_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE OR REPLACE TRIGGER acl_sid_id_trigger
BEFORE INSERT ON acl_sid
FOR EACH ROW
BEGIN
SELECT acl_sid_sequence.nextval INTO :new.id FROM dual;
END;
CREATE TABLE acl_class (
id NUMBER(38) NOT NULL PRIMARY KEY,
class NVARCHAR2(100) NOT NULL,
CONSTRAINT uk_acl_class UNIQUE (class)
);
CREATE SEQUENCE acl_class_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE OR REPLACE TRIGGER acl_class_id_trigger
BEFORE INSERT ON acl_class
FOR EACH ROW
BEGIN
SELECT acl_class_sequence.nextval INTO :new.id FROM dual;
END;
CREATE TABLE acl_object_identity (
id NUMBER(38) NOT NULL PRIMARY KEY,
object_id_class NUMBER(38) NOT NULL,
object_id_identity NUMBER(38) NOT NULL,
parent_object NUMBER(38),
owner_sid NUMBER(38),
entries_inheriting NUMBER(1) NOT NULL CHECK (entries_inheriting in (0, 1)),
CONSTRAINT uk_acl_object_identity UNIQUE (object_id_class, object_id_identity),
CONSTRAINT fk_acl_object_identity_parent FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id),
CONSTRAINT fk_acl_object_identity_class FOREIGN KEY (object_id_class) REFERENCES acl_class (id),
CONSTRAINT fk_acl_object_identity_owner FOREIGN KEY (owner_sid) REFERENCES acl_sid (id)
);
CREATE SEQUENCE acl_object_identity_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE OR REPLACE TRIGGER acl_object_identity_id_trigger
BEFORE INSERT ON acl_object_identity
FOR EACH ROW
BEGIN
SELECT acl_object_identity_sequence.nextval INTO :new.id FROM dual;
END;
CREATE TABLE acl_entry (
id NUMBER(38) NOT NULL PRIMARY KEY,
acl_object_identity NUMBER(38) NOT NULL,
ace_order INTEGER NOT NULL,
sid NUMBER(38) NOT NULL,
mask INTEGER NOT NULL,
granting NUMBER(1) NOT NULL CHECK (granting in (0, 1)),
audit_success NUMBER(1) NOT NULL CHECK (audit_success in (0, 1)),
audit_failure NUMBER(1) NOT NULL CHECK (audit_failure in (0, 1)),
CONSTRAINT unique_acl_entry UNIQUE (acl_object_identity, ace_order),
CONSTRAINT fk_acl_entry_object FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity (id),
CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id)
);
CREATE SEQUENCE acl_entry_sequence START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE OR REPLACE TRIGGER acl_entry_id_trigger
BEFORE INSERT ON acl_entry
FOR EACH ROW
BEGIN
SELECT acl_entry_sequence.nextval INTO :new.id FROM dual;
END;
@@ -0,0 +1,46 @@
-- ACL Schema SQL for Microsoft SQL Server 2008+
-- drop table acl_entry;
-- drop table acl_object_identity;
-- drop table acl_class;
-- drop table acl_sid;
CREATE TABLE acl_sid (
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
principal BIT NOT NULL,
sid VARCHAR(100) NOT NULL,
CONSTRAINT unique_acl_sid UNIQUE (sid, principal)
);
CREATE TABLE acl_class (
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
class VARCHAR(100) NOT NULL,
CONSTRAINT uk_acl_class UNIQUE (class)
);
CREATE TABLE acl_object_identity (
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
object_id_class BIGINT NOT NULL,
object_id_identity BIGINT NOT NULL,
parent_object BIGINT,
owner_sid BIGINT,
entries_inheriting BIT NOT NULL,
CONSTRAINT uk_acl_object_identity UNIQUE (object_id_class, object_id_identity),
CONSTRAINT fk_acl_object_identity_parent FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id),
CONSTRAINT fk_acl_object_identity_class FOREIGN KEY (object_id_class) REFERENCES acl_class (id),
CONSTRAINT fk_acl_object_identity_owner FOREIGN KEY (owner_sid) REFERENCES acl_sid (id)
);
CREATE TABLE acl_entry (
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
acl_object_identity BIGINT NOT NULL,
ace_order INTEGER NOT NULL,
sid BIGINT NOT NULL,
mask INTEGER NOT NULL,
granting BIT NOT NULL,
audit_success BIT NOT NULL,
audit_failure BIT NOT NULL,
CONSTRAINT unique_acl_entry UNIQUE (acl_object_identity, ace_order),
CONSTRAINT fk_acl_entry_object FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity (id),
CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id)
);
@@ -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));
}
}
@@ -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
+14 -20
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.CI-SNAPSHOT</version>
<version>3.2.3.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.CI-SNAPSHOT</version>
<version>3.2.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -132,13 +126,13 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.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
}
+16 -7
View File
@@ -5,11 +5,12 @@ buildscript {
maven { url "http://repo.springsource.org/plugins-release" }
}
dependencies {
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.3")
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('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')
}
}
@@ -24,12 +25,17 @@ allprojects {
ext.releaseBuild = version.endsWith('RELEASE')
ext.snapshotBuild = version.endsWith('SNAPSHOT')
ext.springVersion = '3.2.8.RELEASE'
ext.spring4Version = '4.0.2.RELEASE'
ext.springLdapVersion = '1.3.2.RELEASE'
ext.springLdap2Version = '2.0.1.RELEASE'
group = 'org.springframework.security'
repositories {
maven { url "http://repo.springsource.org/libs-snapshot" }
maven { url "http://repo.springsource.org/plugins-release" }
mavenCentral()
maven { url "https://repo.spring.io/libs-snapshot" }
maven { url "https://repo.spring.io/plugins-release" }
maven { url "http://repo.terracotta.org/maven2/" }
}
@@ -51,7 +57,7 @@ sonarRunner {
}
// Set up different subproject lists for individual configuration
ext.javaProjects = subprojects.findAll { project -> project.name != 'docs' && 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
@@ -76,7 +82,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
@@ -106,7 +112,7 @@ configure(coreModuleProjects) {
configurations.spring4TestRuntime {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
if (details.requested.group == 'org.springframework') {
details.useVersion '4.0.0.RC1'
details.useVersion spring4Version
}
if (details.requested.name == 'ehcache') {
details.useVersion '2.6.5'
@@ -114,6 +120,9 @@ configure(coreModuleProjects) {
if (details.requested.name == 'ehcache-terracotta') {
details.useVersion '2.1.1'
}
if (details.requested.group == 'org.springframework.ldap') {
details.useVersion springLdap2Version
}
}
}
@@ -185,5 +194,5 @@ artifacts {
}
task wrapper(type: Wrapper) {
gradleVersion = '1.8'
gradleVersion = '1.10-rc-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
+15 -21
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.CI-SNAPSHOT</version>
<version>3.2.3.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.CI-SNAPSHOT</version>
<version>3.2.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -94,7 +88,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -150,7 +144,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
+7 -7
View File
@@ -35,6 +35,7 @@ dependencies {
"org.springframework:spring-orm:$springVersion",
"org.springframework:spring-tx:$springVersion",
"org.spockframework:spock-core:$spockVersion",
"org.spockframework:spock-spring:$spockVersion",
"org.slf4j:jcl-over-slf4j:$slf4jVersion",
"org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final",
"org.hibernate:hibernate-entitymanager:4.1.0.Final",
@@ -46,13 +47,16 @@ dependencies {
"org.apache.directory.server:apacheds-server-jndi:$apacheDsVersion",
'org.apache.directory.shared:shared-ldap:0.9.15',
'ldapsdk:ldapsdk:4.1',
powerMockDependencies
powerMockDependencies,
"org.springframework.data:spring-data-jpa:1.2.0.RELEASE",
"org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.0.Final",
"org.hibernate:hibernate-entitymanager:3.6.10.Final",
"org.hsqldb:hsqldb:2.2.8"
testCompile('org.openid4java:openid4java-nodeps:0.9.6') {
exclude group: 'com.google.code.guice', module: 'guice'
}
testRuntime "hsqldb:hsqldb:$hsqlVersion",
testRuntime "org.hsqldb:hsqldb:$hsqlVersion",
"cglib:cglib-nodep:2.2"
}
@@ -60,10 +64,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
+60 -36
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.CI-SNAPSHOT</version>
<version>3.2.3.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.CI-SNAPSHOT</version>
<version>3.2.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -108,49 +102,49 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.3.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-openid</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.3.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.3.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
@@ -172,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>
@@ -244,6 +232,12 @@
<version>1.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.0.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
@@ -256,6 +250,24 @@
<version>4.1.0.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.6.10.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.2.8</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
@@ -322,6 +334,18 @@
<version>0.7-groovy-2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>0.7-groovy-2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.2.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap-core</artifactId>
@@ -331,25 +355,25 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -26,6 +26,7 @@ import org.springframework.security.config.annotation.authentication.builders.Au
import org.springframework.security.config.annotation.authentication.ldap.NamespaceLdapAuthenticationProviderTestsConfigs.LdapAuthenticationProviderConfig;
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
import org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator;
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
import org.springframework.security.ldap.userdetails.PersonContextMapper;
import org.springframework.test.util.ReflectionTestUtils;
@@ -57,6 +58,17 @@ class NamespaceLdapAuthenticationProviderTests extends BaseSpringSpec {
provider.authenticator.userSearch.searchFilter == "(uid={0})"
}
def "SEC-2490: ldap-authentication-provider custom LdapAuthoritiesPopulator"() {
setup:
LdapAuthoritiesPopulator LAP = Mock()
CustomAuthoritiesPopulatorConfig.LAP = LAP
when:
loadConfig(CustomAuthoritiesPopulatorConfig)
LdapAuthenticationProvider provider = findAuthenticationProvider(LdapAuthenticationProvider)
then:
provider.authoritiesPopulator == LAP
}
def "ldap-authentication-provider password compare"() {
when:
loadConfig(PasswordCompareLdapConfig)
@@ -20,6 +20,7 @@ import org.springframework.security.authentication.encoding.PlaintextPasswordEnc
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
import org.springframework.security.ldap.userdetails.PersonContextMapper;
/**
@@ -65,6 +66,18 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
}
}
@Configuration
@EnableWebSecurity
static class CustomAuthoritiesPopulatorConfig extends WebSecurityConfigurerAdapter {
static LdapAuthoritiesPopulator LAP;
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.userSearchFilter("(uid={0})")
.ldapAuthoritiesPopulator(LAP);
}
}
@Configuration
@EnableWebSecurity
static class PasswordCompareLdapConfig extends WebSecurityConfigurerAdapter {
@@ -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) {}
}
}
}
@@ -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;
}
@@ -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;
@@ -25,6 +27,7 @@ import org.springframework.security.authentication.ProviderManager;
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.SecurityConfigurer;
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.ldap.LdapAuthenticationProviderConfigurer;
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
@@ -45,6 +48,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>();
@@ -74,6 +78,9 @@ public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuil
*/
public AuthenticationManagerBuilder parentAuthenticationManager(
AuthenticationManager authenticationManager) {
if(authenticationManager instanceof ProviderManager) {
eraseCredentials(((ProviderManager) authenticationManager).isEraseCredentialsAfterAuthentication());
}
this.parentAuthenticationManager = authenticationManager;
return this;
}
@@ -218,6 +225,10 @@ public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuil
@Override
protected ProviderManager performBuild() throws Exception {
if(!isConfigured()) {
logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
return null;
}
ProviderManager providerManager = new ProviderManager(authenticationProviders, parentAuthenticationManager);
if(eraseCredentials != null) {
providerManager.setEraseCredentialsAfterAuthentication(eraseCredentials);
@@ -229,6 +240,26 @@ public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuil
return providerManager;
}
/**
* Determines if the {@link AuthenticationManagerBuilder} is configured to
* build a non null {@link AuthenticationManager}. This means that either a
* non-null parent is specified or at least one
* {@link AuthenticationProvider} has been specified.
*
* <p>
* When using {@link SecurityConfigurer} instances, the
* {@link AuthenticationManagerBuilder} will not be configured until the
* {@link SecurityConfigurer#configure(SecurityBuilder)} methods. This means
* a {@link SecurityConfigurer} that is last could check this method and
* provide a default configuration in the
* {@link SecurityConfigurer#configure(SecurityBuilder)} method.
*
* @return
*/
public boolean isConfigured() {
return !authenticationProviders.isEmpty() || parentAuthenticationManager != null;
}
/**
* Gets the default {@link UserDetailsService} for the
* {@link AuthenticationManagerBuilder}. The result may be null in some
@@ -15,10 +15,26 @@
*/
package org.springframework.security.config.annotation.authentication.configuration;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.aop.target.LazyInitTargetSource;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
import org.springframework.util.Assert;
/**
* Exports the authentication {@link Configuration}
@@ -29,9 +45,100 @@ import org.springframework.security.config.annotation.authentication.builders.Au
*/
@Configuration
public class AuthenticationConfiguration {
private ApplicationContext applicationContext;
private AuthenticationManager authenticationManager;
private boolean authenticationManagerInitialized;
private List<GlobalAuthenticationConfigurerAdapter> globalAuthConfigures = Collections.emptyList();
private ObjectPostProcessor<Object> objectPostProcessor;
@Bean
public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
return new AuthenticationManagerBuilder(objectPostProcessor);
}
}
@Bean
public GlobalAuthenticationConfigurerAdapter enableGlobalAuthenticationAutowiredConfigurer(ApplicationContext context) {
return new EnableGlobalAuthenticationAutowiredConfigurer(context);
}
public AuthenticationManager getAuthenticationManager() throws Exception {
if(authenticationManagerInitialized) {
return authenticationManager;
}
AuthenticationManagerBuilder authBuilder = authenticationManagerBuilder(objectPostProcessor);
for(GlobalAuthenticationConfigurerAdapter config : globalAuthConfigures) {
authBuilder.apply(config);
}
authenticationManager = authBuilder.build();
if(authenticationManager == null) {
authenticationManager = getAuthenticationMangerBean();
}
this.authenticationManagerInitialized = true;
return authenticationManager;
}
@Autowired(required = false)
public void setGlobalAuthenticationConfigurers(List<GlobalAuthenticationConfigurerAdapter> configurers) throws Exception {
Collections.sort(configurers, AnnotationAwareOrderComparator.INSTANCE);
this.globalAuthConfigures = configurers;
}
@Autowired
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Autowired
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
this.objectPostProcessor = objectPostProcessor;
}
@SuppressWarnings("unchecked")
private <T> T lazyBean(Class<T> interfaceName) {
LazyInitTargetSource lazyTargetSource = new LazyInitTargetSource();
String[] beanNamesForType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, interfaceName);
if(beanNamesForType.length == 0) {
return null;
}
Assert.isTrue(beanNamesForType.length == 1 , "Expecting to only find a single bean for type " + interfaceName + ", but found " + Arrays.asList(beanNamesForType));
lazyTargetSource.setTargetBeanName(beanNamesForType[0]);
lazyTargetSource.setBeanFactory(applicationContext);
ProxyFactoryBean proxyFactory = new ProxyFactoryBean();
proxyFactory = objectPostProcessor.postProcess(proxyFactory);
proxyFactory.setTargetSource(lazyTargetSource);
proxyFactory.setInterfaces(new Class[] { interfaceName, LazyBean.class });
return (T) proxyFactory.getObject();
}
private AuthenticationManager getAuthenticationMangerBean() {
return lazyBean(AuthenticationManager.class);
}
private interface LazyBean {}
private static class EnableGlobalAuthenticationAutowiredConfigurer extends GlobalAuthenticationConfigurerAdapter {
private final ApplicationContext context;
private static final Log logger = LogFactory.getLog(EnableGlobalAuthenticationAutowiredConfigurer.class);
public EnableGlobalAuthenticationAutowiredConfigurer(ApplicationContext context) {
this.context = context;
}
@Override
public void init(AuthenticationManagerBuilder auth) {
Map<String, Object> beansWithAnnotation = context.getBeansWithAnnotation(EnableGlobalAuthentication.class);
if(logger.isDebugEnabled()) {
logger.debug("Eagerly initializing " + beansWithAnnotation);
}
}
}
}
@@ -0,0 +1,91 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication.configuration;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
/**
* The {@link EnableGlobalAuthentication} annotation signals that the annotated
* class can be used to configure a global instance of
* {@link AuthenticationManagerBuilder}. For example:
*
* <pre class="code">
* &#064;Configuration
* &#064;EnableGlobalAuthentication
* public class MyGlobalAuthenticationConfiguration {
*
* &#064;Autowired
* public void configureGlobal(AuthenticationManagerBuilder auth) {
* auth
* .inMemoryAuthentication()
* .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;);
* }
* }
* </pre>
*
* Annotations that are annotated with {@link EnableGlobalAuthentication} also
* signal that the annotated class can be used to configure a global instance of
* {@link AuthenticationManagerBuilder}. For example:
*
* <pre class="code">
* &#064;Configuration
* &#064;EnableWebSecurity
* public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
*
* &#064;Autowired
* public void configureGlobal(AuthenticationManagerBuilder auth) {
* auth
* .inMemoryAuthentication()
* .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;);
* }
*
* // Possibly overridden methods ...
* }
* </pre>
*
* The following annotations are annotated with {@link EnableGlobalAuthentication}
*
* <ul>
* <li> {@link EnableWebSecurity} </li>
* <li> {@link EnableWebMvcSecurity} </li>
* <li> {@link EnableGlobalMethodSecurity} </li>
* </ul>
*
* Configuring {@link AuthenticationManagerBuilder} in a class without the {@link EnableGlobalAuthentication} annotation has
* unpredictable results.
*
* @see EnableWebMvcSecurity
* @see EnableWebSecurity
* @see EnableGlobalMethodSecurity
*
* @author Rob Winch
*
*/
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value={java.lang.annotation.ElementType.TYPE})
@Documented
@Import(AuthenticationConfiguration.class)
public @interface EnableGlobalAuthentication {}
@@ -0,0 +1,39 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication.configurers;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
/**
* A {@link SecurityConfigurer} that can be exposed as a bean to configure the
* global {@link AuthenticationManagerBuilder}. Beans of this type are
* automatically used by {@link AuthenticationConfiguration} to configure the
* global {@link AuthenticationManagerBuilder}.
*
* @since 3.2.1
* @author Rob Winch
*/
@Order(100)
public abstract class GlobalAuthenticationConfigurerAdapter implements SecurityConfigurer<AuthenticationManager, AuthenticationManagerBuilder> {
public void init(AuthenticationManagerBuilder auth) throws Exception {}
public void configure(AuthenticationManagerBuilder auth) throws Exception {}
}
@@ -36,6 +36,7 @@ import org.springframework.security.ldap.search.LdapUserSearch;
import org.springframework.security.ldap.server.ApacheDSContainer;
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
import org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper;
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper;
import org.springframework.security.ldap.userdetails.PersonContextMapper;
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper;
@@ -61,15 +62,13 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
private UserDetailsContextMapper userDetailsContextMapper;
private PasswordEncoder passwordEncoder;
private String passwordAttribute;
private LdapAuthoritiesPopulator ldapAuthoritiesPopulator;
private LdapAuthenticationProvider build() throws Exception {
BaseLdapPathContextSource contextSource = getContextSource();
LdapAuthenticator ldapAuthenticator = createLdapAuthenticator(contextSource);
DefaultLdapAuthoritiesPopulator authoritiesPopulator = new DefaultLdapAuthoritiesPopulator(
contextSource, groupSearchBase);
authoritiesPopulator.setGroupRoleAttribute(groupRoleAttribute);
authoritiesPopulator.setGroupSearchFilter(groupSearchFilter);
LdapAuthoritiesPopulator authoritiesPopulator = getLdapAuthoritiesPopulator();
LdapAuthenticationProvider ldapAuthenticationProvider = new LdapAuthenticationProvider(
ldapAuthenticator, authoritiesPopulator);
@@ -83,6 +82,17 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
return ldapAuthenticationProvider;
}
/**
* Specifies the {@link LdapAuthoritiesPopulator}.
*
* @param ldapAuthoritiesPopulator the {@link LdapAuthoritiesPopulator} the default is {@link DefaultLdapAuthoritiesPopulator}
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*/
public LdapAuthenticationProviderConfigurer<B> ldapAuthoritiesPopulator(LdapAuthoritiesPopulator ldapAuthoritiesPopulator) {
this.ldapAuthoritiesPopulator = ldapAuthoritiesPopulator;
return this;
}
/**
* Adds an {@link ObjectPostProcessor} for this class.
*
@@ -94,6 +104,25 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
return this;
}
/**
* Gets the {@link LdapAuthoritiesPopulator} and defaults to {@link DefaultLdapAuthoritiesPopulator}
*
* @return the {@link LdapAuthoritiesPopulator}
*/
private LdapAuthoritiesPopulator getLdapAuthoritiesPopulator() {
if(ldapAuthoritiesPopulator != null) {
return ldapAuthoritiesPopulator;
}
DefaultLdapAuthoritiesPopulator defaultAuthoritiesPopulator = new DefaultLdapAuthoritiesPopulator(
contextSource, groupSearchBase);
defaultAuthoritiesPopulator.setGroupRoleAttribute(groupRoleAttribute);
defaultAuthoritiesPopulator.setGroupSearchFilter(groupSearchFilter);
this.ldapAuthoritiesPopulator = defaultAuthoritiesPopulator;
return defaultAuthoritiesPopulator;
}
/**
* Creates the {@link LdapAuthenticator} to use
*
@@ -23,7 +23,7 @@ import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Import;
import org.springframework.core.Ordered;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
/**
@@ -44,7 +44,8 @@ import org.springframework.security.config.annotation.configuration.ObjectPostPr
@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value={java.lang.annotation.ElementType.TYPE})
@Documented
@Import({GlobalMethodSecuritySelector.class,ObjectPostProcessorConfiguration.class,AuthenticationConfiguration.class})
@Import({GlobalMethodSecuritySelector.class,ObjectPostProcessorConfiguration.class})
@EnableGlobalAuthentication
public @interface EnableGlobalMethodSecurity {
/**
@@ -16,19 +16,14 @@
package org.springframework.security.config.annotation.method.configuration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.aopalliance.intercept.MethodInterceptor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.aop.target.LazyInitTargetSource;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
@@ -67,6 +62,7 @@ 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;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.util.Assert;
/**
@@ -81,7 +77,6 @@ import org.springframework.util.Assert;
@Configuration
public class GlobalMethodSecurityConfiguration implements ImportAware {
private static final Log logger = LogFactory.getLog(GlobalMethodSecurityConfiguration.class);
private ApplicationContext context;
private ObjectPostProcessor<Object> objectPostProcessor = new ObjectPostProcessor<Object>() {
public <T> T postProcess(T object) {
throw new IllegalStateException(ObjectPostProcessor.class.getName()+ " is a required bean. Ensure you have used @"+EnableGlobalMethodSecurity.class.getName());
@@ -93,6 +88,7 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
private boolean disableAuthenticationRegistry;
private AnnotationAttributes enableMethodSecurity;
private MethodSecurityExpressionHandler expressionHandler;
private AuthenticationConfiguration authenticationConfiguration;
/**
* Creates the default MethodInterceptor which is a MethodSecurityInterceptor using the following methods to
@@ -248,19 +244,11 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
auth = new AuthenticationManagerBuilder(objectPostProcessor);
auth.authenticationEventPublisher(eventPublisher);
configure(auth);
if(!disableAuthenticationRegistry) {
if(disableAuthenticationRegistry) {
authenticationManager = getAuthenticationConfiguration().getAuthenticationManager();
} else {
authenticationManager = auth.build();
}
if(authenticationManager == null) {
try {
authenticationManager = context.getBean(AuthenticationManagerBuilder.class).getOrBuild();
} catch(NoSuchBeanDefinitionException e) {
logger.debug("Could not obtain the AuthenticationManagerBuilder. This is ok for now, we will try using an AuthenticationManager directly",e);
}
}
if(authenticationManager == null) {
authenticationManager = lazyBean(AuthenticationManager.class);
}
}
return authenticationManager;
}
@@ -351,11 +339,6 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
this.defaultMethodExpressionHandler.setTrustResolver(trustResolver);
}
@Autowired
public void setApplicationContext(ApplicationContext context) {
this.context = context;
}
@Autowired(required=false)
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
this.objectPostProcessor = objectPostProcessor;
@@ -370,17 +353,14 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
this.defaultMethodExpressionHandler.setPermissionEvaluator(permissionEvaluators.get(0));
}
@SuppressWarnings("unchecked")
private <T> T lazyBean(Class<T> interfaceName) {
LazyInitTargetSource lazyTargetSource = new LazyInitTargetSource();
String[] beanNamesForType = context.getBeanNamesForType(interfaceName);
Assert.isTrue(beanNamesForType.length == 1 , "Expecting to only find a single bean for type " + interfaceName + ", but found " + Arrays.asList(beanNamesForType));
lazyTargetSource.setTargetBeanName(beanNamesForType[0]);
lazyTargetSource.setBeanFactory(context);
ProxyFactoryBean proxyFactory = new ProxyFactoryBean();
proxyFactory.setTargetSource(lazyTargetSource);
proxyFactory.setInterfaces(new Class[] { interfaceName });
return (T) proxyFactory.getObject();
@Autowired(required = false)
public void setAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {
this.authenticationConfiguration = authenticationConfiguration;
}
private AuthenticationConfiguration getAuthenticationConfiguration() {
Assert.notNull(authenticationConfiguration, "authenticationConfiguration cannot be null");
return authenticationConfiguration;
}
private boolean prePostEnabled() {
@@ -414,5 +394,4 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
}
return this.enableMethodSecurity;
}
}
}
@@ -280,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) {
@@ -0,0 +1,58 @@
/*
* 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 java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.Filter;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.util.Assert;
/**
* A class used to get all the {@link WebSecurityConfigurer} instances from the
* current {@link ApplicationContext} but ignoring the parent.
*
* @author Rob Winch
*
*/
final class AutowiredWebSecurityConfigurersIgnoreParents {
private final ConfigurableListableBeanFactory beanFactory;
public AutowiredWebSecurityConfigurersIgnoreParents(ConfigurableListableBeanFactory beanFactory) {
Assert.notNull(beanFactory,"beanFactory cannot be null");
this.beanFactory = beanFactory;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public List<SecurityConfigurer<Filter, WebSecurity>> getWebSecurityConfigurers() {
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList<SecurityConfigurer<Filter, WebSecurity>>();
Map<String, WebSecurityConfigurer> beansOfType = beanFactory.getBeansOfType(WebSecurityConfigurer.class);
for(Entry<String,WebSecurityConfigurer> entry : beansOfType.entrySet()) {
webSecurityConfigurers.add(entry.getValue());
}
return webSecurityConfigurers;
}
}
@@ -20,7 +20,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
@@ -77,7 +77,8 @@ 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})
@EnableGlobalAuthentication
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 WebMvcSecurityConfiguration} when the DispatcherServlet is present on the
* classpath.
*
* @author Rob Winch
* @since 3.2
*/
class SpringWebMvcImportSelector implements ImportSelector {
/* (non-Javadoc)
* @see org.springframework.context.annotation.ImportSelector#selectImports(org.springframework.core.type.AnnotationMetadata)
*/
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
boolean webmvcPresent = ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", getClass().getClassLoader());
return webmvcPresent ? new String[] {"org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration"} : new String[] {};
}
}
@@ -23,6 +23,8 @@ import javax.servlet.Filter;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
@@ -110,7 +112,7 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
*/
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers) throws Exception {
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers) throws Exception {
webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
if(debugEnabled != null) {
webSecurity.debug(debugEnabled);
@@ -132,6 +134,10 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
this.webSecurityConfigurers = webSecurityConfigurers;
}
@Bean
public AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents(ConfigurableListableBeanFactory beanFactory) {
return new AutowiredWebSecurityConfigurersIgnoreParents(beanFactory);
}
/**
* A custom verision of the Spring provided AnnotationAwareOrderComparator
@@ -16,20 +16,23 @@
package org.springframework.security.config.annotation.web.configuration;
import java.lang.reflect.Field;
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.FatalBeanException;
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.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
@@ -42,6 +45,8 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.accept.ContentNegotiationStrategy;
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
@@ -53,6 +58,7 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
*
* @author Rob Winch
*/
@Order(100)
public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer<WebSecurity> {
private final Log logger = LogFactory.getLog(WebSecurityConfigurerAdapter.class);
@@ -66,9 +72,10 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
}
};
private AuthenticationConfiguration authenticationConfiguration;
private AuthenticationManagerBuilder authenticationBuilder;
private AuthenticationManagerBuilder parentAuthenticationBuilder;
private boolean disableAuthenticationRegistration;
private AuthenticationManagerBuilder localConfigureAuthenticationBldr;
private boolean disableLocalConfigureAuthenticationBldr;
private boolean authenticationManagerInitialized;
private AuthenticationManager authenticationManager;
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
@@ -144,7 +151,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
* @throws Exception
*/
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
this.disableAuthenticationRegistration = true;
this.disableLocalConfigureAuthenticationBldr = true;
}
/**
@@ -159,11 +166,11 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
}
DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
parentAuthenticationBuilder.authenticationEventPublisher(eventPublisher);
localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
AuthenticationManager authenticationManager = authenticationManager();
authenticationBuilder.parentAuthenticationManager(authenticationManager);
http = new HttpSecurity(objectPostProcessor,authenticationBuilder, parentAuthenticationBuilder.getSharedObjects());
http = new HttpSecurity(objectPostProcessor,authenticationBuilder, localConfigureAuthenticationBldr.getSharedObjects());
http.setSharedObject(UserDetailsService.class, userDetailsService());
http.setSharedObject(ApplicationContext.class, context);
http.setSharedObject(ContentNegotiationStrategy.class, contentNegotiationStrategy);
@@ -217,22 +224,11 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
*/
protected AuthenticationManager authenticationManager() throws Exception {
if(!authenticationManagerInitialized) {
configure(parentAuthenticationBuilder);
if(disableAuthenticationRegistration) {
try {
authenticationManager = context.getBean(AuthenticationManagerBuilder.class).getOrBuild();
} catch(NoSuchBeanDefinitionException e) {
logger.debug("Could not obtain the AuthenticationManagerBuilder. This is ok for now, we will try using an AuthenticationManager directly",e);
}
if(authenticationManager == null) {
try {
authenticationManager = context.getBean(AuthenticationManager.class);
} catch(NoSuchBeanDefinitionException e) {
logger.debug("The AuthenticationManager was not found. This is ok for now as it may not be required.",e);
}
}
configure(localConfigureAuthenticationBldr);
if(disableLocalConfigureAuthenticationBldr) {
authenticationManager = authenticationConfiguration.getAuthenticationManager();
} else {
authenticationManager = parentAuthenticationBuilder.build();
authenticationManager = localConfigureAuthenticationBldr.build();
}
authenticationManagerInitialized = true;
}
@@ -260,7 +256,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
*/
public UserDetailsService userDetailsServiceBean() throws Exception {
AuthenticationManagerBuilder globalAuthBuilder = context.getBean(AuthenticationManagerBuilder.class);
return new UserDetailsServiceDelegator(Arrays.asList(parentAuthenticationBuilder, globalAuthBuilder));
return new UserDetailsServiceDelegator(Arrays.asList(localConfigureAuthenticationBldr, globalAuthBuilder));
}
/**
@@ -273,7 +269,7 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
*/
protected UserDetailsService userDetailsService() {
AuthenticationManagerBuilder globalAuthBuilder = context.getBean(AuthenticationManagerBuilder.class);
return new UserDetailsServiceDelegator(Arrays.asList(parentAuthenticationBuilder, globalAuthBuilder));
return new UserDetailsServiceDelegator(Arrays.asList(localConfigureAuthenticationBldr, globalAuthBuilder));
}
public void init(final WebSecurity web) throws Exception {
@@ -339,12 +335,12 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
this.contentNegotiationStrategy = contentNegotiationStrategy;
}
@Autowired(required=false)
@Autowired
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
this.objectPostProcessor = objectPostProcessor;
authenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor);
parentAuthenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor) {
localConfigureAuthenticationBldr = new AuthenticationManagerBuilder(objectPostProcessor) {
@Override
public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {
authenticationBuilder.eraseCredentials(eraseCredentials);
@@ -354,6 +350,10 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
};
}
@Autowired
public void setAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {
this.authenticationConfiguration = authenticationConfiguration;
}
/**
* Delays the use of the {@link UserDetailsService} from the
@@ -414,8 +414,12 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
private AuthenticationManager delegate;
private final Object delegateMonitor = new Object();
AuthenticationManagerDelegator(AuthenticationManagerBuilder authentication) {
this.delegateBuilder = authentication;
AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder) {
Assert.notNull(delegateBuilder,"delegateBuilder cannot be null");
Field parentAuthMgrField = ReflectionUtils.findField(AuthenticationManagerBuilder.class, "parentAuthenticationManager");
ReflectionUtils.makeAccessible(parentAuthMgrField);
validateBeanCycle(ReflectionUtils.getField(parentAuthMgrField, delegateBuilder));
this.delegateBuilder = delegateBuilder;
}
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
@@ -432,5 +436,18 @@ public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigu
return delegate.authenticate(authentication);
}
private static void validateBeanCycle(Object auth) {
if(auth != null) {
String lazyBeanClassName = AuthenticationConfiguration.class.getName() + "$LazyBean";
Class<?>[] interfaces = auth.getClass().getInterfaces();
for(Class<?> i : interfaces) {
String className = i.getName();
if(className.equals(lazyBeanClassName)) {
throw new FatalBeanException("A dependency cycle was detected when trying to resolve the AuthenticationManager. Please ensure you have configured authentication.");
}
}
}
}
}
}
@@ -15,14 +15,22 @@
*/
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.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);
}
}
@@ -132,13 +132,11 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
*
* @param requestMatchers the {@link RequestMatcher} instances to register to the {@link ConfigAttribute} instances
* @param configAttributes the {@link ConfigAttribute} to be mapped by the {@link RequestMatcher} instances
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customization.
*/
private ExpressionUrlAuthorizationConfigurer<H> interceptUrl(Iterable<? extends RequestMatcher> requestMatchers, Collection<ConfigAttribute> configAttributes) {
private void interceptUrl(Iterable<? extends RequestMatcher> requestMatchers, Collection<ConfigAttribute> configAttributes) {
for(RequestMatcher requestMatcher : requestMatchers) {
REGISTRY.addMapping(new AbstractConfigAttributeRequestMatcherRegistry.UrlMapping(requestMatcher, configAttributes));
}
return null;
}
@Override
@@ -15,7 +15,9 @@
*/
package org.springframework.security.config.annotation.web.configurers;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.http.MediaType;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
@@ -114,12 +116,13 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>> exte
return defaultCache;
}
@SuppressWarnings("unchecked")
private RequestMatcher createDefaultSavedRequestMatcher(H http) {
ContentNegotiationStrategy contentNegotiationStrategy = http.getSharedObject(ContentNegotiationStrategy.class);
if(contentNegotiationStrategy == null) {
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
}
RequestMatcher getRequests = new AntPathRequestMatcher("/**", "GET");
RequestMatcher notFavIcon = new NegatedRequestMatcher(new AntPathRequestMatcher("/**/favicon.ico"));
MediaTypeRequestMatcher jsonRequest = new MediaTypeRequestMatcher(contentNegotiationStrategy, MediaType.APPLICATION_JSON);
@@ -127,6 +130,18 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>> exte
RequestMatcher notJson = new NegatedRequestMatcher(jsonRequest);
RequestMatcher notXRequestedWith = new NegatedRequestMatcher(new RequestHeaderRequestMatcher("X-Requested-With","XMLHttpRequest"));
return new AndRequestMatcher(getRequests, notFavIcon, notJson, notXRequestedWith);
boolean isCsrfEnabled = http.getConfigurer(CsrfConfigurer.class) != null;
List<RequestMatcher> matchers = new ArrayList<RequestMatcher>();
if(isCsrfEnabled) {
RequestMatcher getRequests = new AntPathRequestMatcher("/**", "GET");
matchers.add(0, getRequests);
}
matchers.add(notFavIcon);
matchers.add(notJson);
matchers.add(notXRequestedWith);
return new AndRequestMatcher(matchers);
}
}
@@ -42,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;
@@ -66,6 +67,7 @@ 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>
@@ -83,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;
@@ -365,6 +368,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
}
}
http.setSharedObject(SessionAuthenticationStrategy.class, getSessionAuthenticationStrategy());
http.setSharedObject(InvalidSessionStrategy.class, getInvalidSessionStrategy());
}
@Override
@@ -375,7 +379,7 @@ 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) {
@@ -391,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}
@@ -27,6 +27,7 @@ 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.matcher.RequestMatcher;
@@ -48,10 +49,10 @@ import org.springframework.util.Assert;
* <pre>
* protected void configure(HttpSecurity http) throws Exception {
* http
* .apply(new UrlAuthorizationConfigurer()).getRegistry()
* .antMatchers("/users**","/sessions/**").hasRole("USER")
* .antMatchers("/signup").hasRole("ANONYMOUS")
* .anyRequest().hasRole("USER")
* .apply(new UrlAuthorizationConfigurer<HttpSecurity>()).getRegistry()
* .antMatchers("/users**","/sessions/**").hasRole("USER")
* .antMatchers("/signup").hasRole("ANONYMOUS")
* .anyRequest().hasRole("USER");
* }
* </pre>
*
@@ -0,0 +1,39 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.servlet.configuration;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
/**
* 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)
@EnableGlobalAuthentication
public @interface EnableWebMvcSecurity {
}
@@ -13,12 +13,13 @@
* 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;
@@ -38,7 +39,8 @@ import org.springframework.web.servlet.support.RequestDataValueProcessor;
* @since 3.2
*/
@Configuration
class WebMvcSecurityConfiguration extends WebMvcConfigurerAdapter {
@EnableWebSecurity
public class WebMvcSecurityConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addArgumentResolvers(
@@ -48,6 +50,6 @@ class WebMvcSecurityConfiguration extends WebMvcConfigurerAdapter {
@Bean
public RequestDataValueProcessor requestDataValueProcessor() {
return CsrfRequestDataValueProcessor.create();
return new CsrfRequestDataValueProcessor();
}
}
}
@@ -128,6 +128,9 @@ final class AuthenticationConfigBuilder {
private final BeanReference portResolver;
private final BeanMetadataElement csrfLogoutHandler;
private String loginProcessingUrl;
private String openidLoginProcessingUrl;
public AuthenticationConfigBuilder(Element element, ParserContext pc, SessionCreationPolicy sessionPolicy,
BeanReference requestCache, BeanReference authenticationManager, BeanReference sessionStrategy, BeanReference portMapper, BeanReference portResolver, BeanMetadataElement csrfLogoutHandler) {
this.httpElt = element;
@@ -197,6 +200,7 @@ final class AuthenticationConfigBuilder {
parser.parse(formLoginElt, pc);
formFilter = parser.getFilterBean();
formEntryPoint = parser.getEntryPointBean();
loginProcessingUrl = parser.getLoginProcessingUrl();
}
if (formFilter != null) {
@@ -221,6 +225,7 @@ final class AuthenticationConfigBuilder {
parser.parse(openIDLoginElt, pc);
openIDFilter = parser.getFilterBean();
openIDEntryPoint = parser.getEntryPointBean();
openidLoginProcessingUrl = parser.getLoginProcessingUrl();
List<Element> attrExElts = DomUtils.getChildElementsByTagName(openIDLoginElt, Elements.OPENID_ATTRIBUTE_EXCHANGE);
@@ -473,10 +478,12 @@ final class AuthenticationConfigBuilder {
if (formFilterId != null) {
loginPageFilter.addConstructorArgReference(formFilterId);
loginPageFilter.addPropertyValue("authenticationUrl", loginProcessingUrl);
}
if (openIDFilterId != null) {
loginPageFilter.addConstructorArgReference(openIDFilterId);
loginPageFilter.addPropertyValue("openIDauthenticationUrl", openidLoginProcessingUrl);
}
loginPageGenerationFilter = loginPageFilter.getBeanDefinition();
@@ -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,12 +53,12 @@ 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());
if(webmvcPresent) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(CsrfRequestDataValueProcessor.class);
beanDefinition.setFactoryMethodName("create");
BeanComponentDefinition componentDefinition =
new BeanComponentDefinition(beanDefinition, REQUEST_DATA_VALUE_PROCESSOR);
pc.registerBeanComponent(componentDefinition);
@@ -58,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() {
@@ -66,6 +66,7 @@ public class FormLoginBeanDefinitionParser {
private RootBeanDefinition filterBean;
private RootBeanDefinition entryPointBean;
private String loginPage;
private String loginProcessingUrl;
FormLoginBeanDefinitionParser(String defaultLoginProcessingUrl, String filterClassName,
BeanReference requestCache, BeanReference sessionStrategy, boolean allowSessionCreation, BeanReference portMapper, BeanReference portResolver) {
@@ -148,7 +149,12 @@ public class FormLoginBeanDefinitionParser {
loginUrl = defaultLoginProcessingUrl;
}
filterBuilder.addPropertyValue("filterProcessesUrl", loginUrl);
this.loginProcessingUrl = loginUrl;
BeanDefinitionBuilder matcherBuilder = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.web.authentication.logout.LogoutFilter$FilterProcessUrlRequestMatcher");
matcherBuilder.addConstructorArgValue(loginUrl);
filterBuilder.addPropertyValue("requiresAuthenticationRequestMatcher", matcherBuilder.getBeanDefinition());
if (StringUtils.hasText(successHandlerRef)) {
filterBuilder.addPropertyReference("authenticationSuccessHandler", successHandlerRef);
@@ -201,4 +207,8 @@ public class FormLoginBeanDefinitionParser {
String getLoginPage() {
return loginPage;
}
String getLoginProcessingUrl() {
return loginProcessingUrl;
}
}
@@ -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() {
@@ -46,10 +46,12 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
final String rememberMeServices;
private ManagedList<BeanMetadataElement> logoutHandlers = new ManagedList<BeanMetadataElement>();
private boolean csrfEnabled;
public LogoutBeanDefinitionParser(String rememberMeServices, BeanMetadataElement csrfLogoutHandler) {
this.rememberMeServices = rememberMeServices;
if(csrfLogoutHandler != null) {
this.csrfEnabled = csrfLogoutHandler != null;
if(this.csrfEnabled) {
logoutHandlers.add(csrfLogoutHandler);
}
}
@@ -78,7 +80,9 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
if (!StringUtils.hasText(logoutUrl)) {
logoutUrl = DEF_LOGOUT_URL;
}
builder.addPropertyValue("filterProcessesUrl", logoutUrl);
builder.addPropertyValue("logoutRequestMatcher", getLogoutRequestMatcher(logoutUrl));
if (StringUtils.hasText(successHandlerRef)) {
if (StringUtils.hasText(logoutSuccessUrl)) {
@@ -114,6 +118,19 @@ class LogoutBeanDefinitionParser implements BeanDefinitionParser {
return builder.getBeanDefinition();
}
private BeanDefinition getLogoutRequestMatcher(String logoutUrl) {
if(this.csrfEnabled) {
BeanDefinitionBuilder matcherBuilder = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.web.util.matcher.AntPathRequestMatcher");
matcherBuilder.addConstructorArgValue(logoutUrl);
matcherBuilder.addConstructorArgValue("POST");
return matcherBuilder.getBeanDefinition();
} else {
BeanDefinitionBuilder matcherBuilder = BeanDefinitionBuilder.rootBeanDefinition("org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter$FilterProcessUrlRequestMatcher");
matcherBuilder.addConstructorArgValue(logoutUrl);
return matcherBuilder.getBeanDefinition();
}
}
ManagedList<BeanMetadataElement> getLogoutHandlers() {
return logoutHandlers;
}
@@ -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) {}
}
}
}
}
@@ -452,6 +452,9 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
}
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
if(!registry.containsBeanDefinition(beanName)) {
return;
}
BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
beanDefinition.setLazyInit(true);
}
@@ -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.
@@ -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>
@@ -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.
@@ -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.
@@ -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>
@@ -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>
@@ -87,4 +87,37 @@ class AuthenticationManagerBuilderTests extends BaseSpringSpec {
.withUser("admin").password("password").roles("USER","ADMIN")
}
}
def "isConfigured with AuthenticationProvider"() {
setup:
ObjectPostProcessor opp = Mock()
AuthenticationProvider provider = Mock()
AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(opp)
when:
auth
.authenticationProvider(provider)
then:
auth.isConfigured()
}
def "isConfigured with parent"() {
setup:
ObjectPostProcessor opp = Mock()
AuthenticationManager parent = Mock()
AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(opp)
when:
auth
.parentAuthenticationManager(parent)
then:
auth.isConfigured()
}
def "isConfigured not configured"() {
setup:
ObjectPostProcessor opp = Mock()
when:
AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(opp)
then:
auth.isConfigured() == false
}
}
@@ -15,6 +15,7 @@
*/
package org.springframework.security.config.annotation.authentication
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.authentication.AuthenticationManager
@@ -89,4 +90,25 @@ class NamespaceAuthenticationManagerTests extends BaseSpringSpec {
return super.authenticationManagerBean();
}
}
def "SEC-2533: global authentication-manager@erase-credentials=false"() {
when:
loadConfig(GlobalEraseCredentialsFalseConfig)
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
then:
auth.credentials == "password"
auth.principal.password == "password"
}
@EnableWebSecurity
@Configuration
static class GlobalEraseCredentialsFalseConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.eraseCredentials(false)
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
}
}
@@ -0,0 +1,328 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication.configuration;
import org.springframework.aop.framework.ProxyFactoryBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.ApplicationContext
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Import
import org.springframework.core.Ordered
import org.springframework.core.annotation.Order
import org.springframework.security.access.annotation.Secured
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.TestingAuthenticationToken
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.ObjectPostProcessor
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity
import org.springframework.security.core.AuthenticationException
import org.springframework.security.core.authority.AuthorityUtils
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.userdetails.User
import org.springframework.security.provisioning.InMemoryUserDetailsManager
class AuthenticationConfigurationTests extends BaseSpringSpec {
def "Ordering Autowired on EnableGlobalMethodSecurity"() {
setup:
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "password","ROLE_USER"))
when:
loadConfig(GlobalMethodSecurityAutowiredConfigAndServicesConfig)
then:
context.getBean(Service).run()
}
@Configuration
@Import([GlobalMethodSecurityAutowiredConfig,ServicesConfig])
static class GlobalMethodSecurityAutowiredConfigAndServicesConfig {}
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
static class GlobalMethodSecurityAutowiredConfig {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
}
}
def "Ordering Autowired on EnableWebSecurity"() {
setup:
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "password","ROLE_USER"))
when:
loadConfig(GlobalMethodSecurityConfigAndServicesConfig)
then:
context.getBean(Service).run()
}
@Configuration
@Import([GlobalMethodSecurityConfig,WebSecurityConfig,ServicesConfig])
static class GlobalMethodSecurityConfigAndServicesConfig {}
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
static class GlobalMethodSecurityConfig {}
@Configuration
@EnableWebSecurity
static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
}
}
//
def "Ordering Autowired on EnableWebMvcSecurity"() {
setup:
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "password","ROLE_USER"))
when:
loadConfig(GlobalMethodSecurityMvcSecurityAndServicesConfig)
then:
context.getBean(Service).run()
}
@Configuration
@Import([GlobalMethodSecurityConfig,WebMvcSecurityConfig,ServicesConfig])
static class GlobalMethodSecurityMvcSecurityAndServicesConfig {}
@Configuration
@EnableWebMvcSecurity
static class WebMvcSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
}
}
//
def "no authentication getAuthenticationManager falls back to null"() {
when:
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration)
then:
context.getBean(AuthenticationConfiguration).authenticationManager == null
}
def "QuiesentGlobalAuthenticationConfiguererAdapter falls back to null"() {
when:
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration,QuiesentGlobalAuthenticationConfiguererAdapter)
then:
context.getBean(AuthenticationConfiguration).authenticationManager == null
}
@Configuration
static class QuiesentGlobalAuthenticationConfiguererAdapter extends GlobalAuthenticationConfigurerAdapter {}
//
def "GlobalAuthenticationConfiguererAdapterImpl configures authentication successfully"() {
setup:
def token = new UsernamePasswordAuthenticationToken("user", "password")
when:
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration,GlobalAuthenticationConfiguererAdapterImpl)
then:
context.getBean(AuthenticationConfiguration).authenticationManager.authenticate(token)?.name == "user"
}
@Configuration
static class GlobalAuthenticationConfiguererAdapterImpl extends GlobalAuthenticationConfigurerAdapter {
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
}
}
//
def "AuthenticationManagerBean configures authentication successfully"() {
setup:
def token = new UsernamePasswordAuthenticationToken("user", "password")
def auth = new UsernamePasswordAuthenticationToken("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER"))
AuthenticationManagerBeanConfig.AM = Mock(AuthenticationManager)
1 * AuthenticationManagerBeanConfig.AM.authenticate(token) >> auth
when:
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration,AuthenticationManagerBeanConfig)
then:
context.getBean(AuthenticationConfiguration).authenticationManager.authenticate(token).name == auth.name
}
@Configuration
static class AuthenticationManagerBeanConfig {
static AuthenticationManager AM
@Bean
public AuthenticationManager authenticationManager() {
AM
}
}
//
@Configuration
static class ServicesConfig {
@Bean
public Service service() {
return new ServiceImpl()
}
}
static interface Service {
public void run();
}
static class ServiceImpl implements Service {
@Secured("ROLE_USER")
public void run() {}
}
//
def "GlobalAuthenticationConfigurerAdapter are ordered"() {
setup:
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration)
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
config.setGlobalAuthenticationConfigurers([new LowestOrderGlobalAuthenticationConfigurerAdapter(), new HighestOrderGlobalAuthenticationConfigurerAdapter(), new DefaultOrderGlobalAuthenticationConfigurerAdapter()])
when:
config.getAuthenticationManager()
then:
DefaultOrderGlobalAuthenticationConfigurerAdapter.inits == [HighestOrderGlobalAuthenticationConfigurerAdapter,DefaultOrderGlobalAuthenticationConfigurerAdapter,LowestOrderGlobalAuthenticationConfigurerAdapter]
DefaultOrderGlobalAuthenticationConfigurerAdapter.configs == [HighestOrderGlobalAuthenticationConfigurerAdapter,DefaultOrderGlobalAuthenticationConfigurerAdapter,LowestOrderGlobalAuthenticationConfigurerAdapter]
}
static class DefaultOrderGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
static List inits = []
static List configs = []
public void init(AuthenticationManagerBuilder auth) throws Exception {
inits.add(getClass())
}
public void configure(AuthenticationManagerBuilder auth) throws Exception {
configs.add(getClass())
}
}
@Order(Ordered.LOWEST_PRECEDENCE)
static class LowestOrderGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {}
@Order(Ordered.HIGHEST_PRECEDENCE)
static class HighestOrderGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {}
//
def "Spring Boot not triggered when already configured"() {
setup:
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration)
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
config.setGlobalAuthenticationConfigurers([new ConfiguresInMemoryConfigurerAdapter(), new BootGlobalAuthenticationConfigurerAdapter()])
AuthenticationManager authenticationManager = config.authenticationManager
when:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
then:
noExceptionThrown()
when:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("boot","password"))
then:
thrown(AuthenticationException)
}
def "Spring Boot is triggered when not already configured"() {
setup:
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration)
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
config.setGlobalAuthenticationConfigurers([new BootGlobalAuthenticationConfigurerAdapter()])
AuthenticationManager authenticationManager = config.authenticationManager
when:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("boot","password"))
then:
noExceptionThrown()
}
static class ConfiguresInMemoryConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
}
@Order(Ordered.LOWEST_PRECEDENCE)
static class BootGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.apply(new DefaultBootGlobalAuthenticationConfigurerAdapter())
}
}
static class DefaultBootGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
if(auth.isConfigured()) {
return;
}
User user = new User("boot","password", AuthorityUtils.createAuthorityList("ROLE_USER"))
List<User> users = Arrays.asList(user);
InMemoryUserDetailsManager inMemory = new InMemoryUserDetailsManager(users);
DaoAuthenticationProvider provider = new DaoAuthenticationProvider()
provider.userDetailsService = inMemory
auth.authenticationProvider(provider)
}
}
def "SEC-2531: AuthenticationConfiguration#lazyBean should use BeanClassLoader on ProxyFactoryBean"() {
setup:
ObjectPostProcessor opp = Mock()
Sec2531Config. opp = opp
loadConfig(Sec2531Config)
when:
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
config.getAuthenticationManager()
then:
1 * opp.postProcess(_ as ProxyFactoryBean) >> { args ->
args[0]
}
}
@Configuration
@Import(AuthenticationConfiguration)
static class Sec2531Config {
static ObjectPostProcessor opp
@Bean
public ObjectPostProcessor objectPostProcessor() {
opp
}
@Bean
public AuthenticationManager manager() {
null
}
}
}
@@ -0,0 +1,68 @@
/*
* 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.issue50;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.security.config.annotation.issue50.domain.User;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* @author Rob Winch
*
*/
@Configuration
@EnableJpaRepositories("org.springframework.security.config.annotation.issue50.repo")
@EnableTransactionManagement
public class ApplicationConfig {
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabase(Database.HSQL);
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setShowSql(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan(User.class.getPackage().getName());
factory.setDataSource(dataSource());
return factory;
}
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory().getObject());
return txManager;
}
}
@@ -0,0 +1,100 @@
/*
* 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.issue50;
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.security.access.AccessDeniedException
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.BadCredentialsException
import org.springframework.security.authentication.TestingAuthenticationToken
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.config.annotation.issue50.domain.User
import org.springframework.security.config.annotation.issue50.repo.UserRepository
import org.springframework.security.core.Authentication
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.userdetails.UsernameNotFoundException
import org.springframework.security.web.FilterChainProxy
import org.springframework.test.context.ContextConfiguration
import org.springframework.transaction.annotation.Transactional
import spock.lang.Specification
/**
* @author Rob Winch
*
*/
@ContextConfiguration(classes=[ApplicationConfig,SecurityConfig])
@Transactional
class Issue50Tests extends Specification {
@Autowired
private FilterChainProxy springSecurityFilterChain
@Autowired
private AuthenticationManager authenticationManager
@Autowired
private UserRepository userRepo
def setup() {
SecurityContextHolder.context.authentication = new TestingAuthenticationToken("test",null,"ROLE_ADMIN")
}
def cleanup() {
SecurityContextHolder.clearContext()
}
// https://github.com/SpringSource/spring-security-javaconfig/issues/50
def "#50 - GlobalMethodSecurityConfiguration should load AuthenticationManager lazily"() {
when:
"Configuration Loads"
then: "GlobalMethodSecurityConfiguration loads AuthenticationManager lazily"
noExceptionThrown()
}
def "AuthenticationManager will not authenticate missing user"() {
when:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("test", "password"))
then:
thrown(UsernameNotFoundException)
}
def "AuthenticationManager will not authenticate with invalid password"() {
when:
User user = new User(username:"test",password:"password")
userRepo.save(user)
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.username , "invalid"))
then:
thrown(BadCredentialsException)
}
def "AuthenticationManager can be used to authenticate a user"() {
when:
User user = new User(username:"test",password:"password")
userRepo.save(user)
Authentication result = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.username , user.password))
then:
result.principal == user.username
}
def "Global Method Security is enabled and works"() {
setup:
SecurityContextHolder.context.authentication = new TestingAuthenticationToken("test",null,"ROLE_USER")
when:
User user = new User(username:"denied",password:"password")
userRepo.save(user)
Authentication result = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.username , user.password))
then:
thrown(AccessDeniedException)
}
}
@@ -0,0 +1,90 @@
/*
* 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.issue50;
import org.spockframework.util.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.issue50.domain.User;
import org.springframework.security.config.annotation.issue50.repo.UserRepository;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
/**
* @author Rob Winch
*
*/
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserRepository myUserRepository;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(authenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/*").permitAll();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
@Bean
public AuthenticationProvider authenticationProvider() {
Assert.notNull(myUserRepository);
return new AuthenticationProvider() {
public boolean supports(Class<?> authentication) {
return true;
}
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
Object principal = authentication.getPrincipal();
String username = String.valueOf(principal);
User user = myUserRepository.findByUsername(username);
if(user == null) {
throw new UsernameNotFoundException("No user for principal "+principal);
}
if(!authentication.getCredentials().equals(user.getPassword())) {
throw new BadCredentialsException("Invalid password");
}
return new TestingAuthenticationToken(principal, null, "ROLE_USER");
}
};
}
}
@@ -0,0 +1,62 @@
/*
* 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.issue50.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
/**
* @author Rob Winch
*
*/
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String username;
private String password;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
@@ -0,0 +1,30 @@
/*
* 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.issue50.repo;
import org.springframework.data.repository.CrudRepository;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.config.annotation.issue50.domain.User;
/**
* @author Rob Winch
*
*/
public interface UserRepository extends CrudRepository<User, String> {
@PreAuthorize("hasRole('ROLE_ADMIN')")
User findByUsername(String username);
}
@@ -19,8 +19,10 @@ import static org.fest.assertions.Assertions.assertThat
import static org.junit.Assert.fail
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.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.access.AccessDeniedException
@@ -270,4 +272,71 @@ public class GlobalMethodSecurityConfigurationTests extends BaseSpringSpec {
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()
}
}
def "SEC-2479: Support AuthenticationManager in parent"() {
setup:
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
loadConfig(Sec2479ParentConfig)
def child = new AnnotationConfigApplicationContext()
child.register(Sec2479ChildConfig)
child.parent = context
child.refresh()
MethodSecurityService service = child.getBean(MethodSecurityService)
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
cleanup:
child?.close()
}
@Configuration
static class Sec2479ParentConfig {
static AuthenticationManager AM
@Bean
public AuthenticationManager am() {
AM
}
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class Sec2479ChildConfig {
@Bean
public MethodSecurityService service() {
new MethodSecurityServiceImpl()
}
}
}
@@ -27,6 +27,9 @@ 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
@@ -283,4 +286,18 @@ class WebSecurityConfigurerAdapterTests extends BaseSpringSpec {
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 {}
}
@@ -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");
}
}
@@ -501,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()).getRegistry()
.antMatchers("/users**","/sessions/**").hasRole("USER")
.antMatchers("/signup").hasRole("ANONYMOUS")
.anyRequest().hasRole("USER")
}
}
}
@@ -0,0 +1,72 @@
/*
* 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.beans.FatalBeanException;
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
public class Sec2515Tests extends BaseSpringSpec {
def "SEC-2515: Prevent StackOverflow with bean graph cycle"() {
when:
loadConfig(StackOverflowSecurityConfig)
then:
thrown(FatalBeanException)
}
@EnableWebSecurity
@Configuration
static class StackOverflowSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
@Bean
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
def "SEC-2515: @Bean still works when configure(AuthenticationManagerBuilder) used"() {
when:
loadConfig(SecurityConfig)
then:
noExceptionThrown();
}
@EnableWebSecurity
@Configuration
static class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
@Bean
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication()
}
}
}
@@ -17,31 +17,28 @@ package org.springframework.security.config.annotation.web.configuration;
import static org.junit.Assert.*
import java.util.List;
import org.springframework.beans.factory.BeanCreationException
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.annotation.Order
import org.springframework.expression.ExpressionParser;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.expression.ExpressionParser
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.security.access.expression.SecurityExpressionHandler
import org.springframework.security.authentication.AuthenticationManager
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.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.builders.WebSecurity
import org.springframework.security.web.FilterChainProxy
import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.access.expression.WebSecurityExpressionHandler;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler
import org.springframework.security.web.access.expression.WebSecurityExpressionHandler
import org.springframework.security.web.util.matcher.AnyRequestMatcher
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.test.util.ReflectionTestUtils
/**
* @author Rob Winch
@@ -313,4 +310,36 @@ class WebSecurityConfigurationTests extends BaseSpringSpec {
}
}
}
def "SEC-2461: Multiple WebSecurityConfiguration instances cause null springSecurityFilterChain"() {
setup:
def parent = loadConfig(ParentConfig)
def child = new AnnotationConfigApplicationContext()
child.register(ChildConfig)
child.parent = parent
when:
child.refresh()
then: "springSecurityFilterChain can be found in parent and child"
parent.getBean("springSecurityFilterChain")
child.getBean("springSecurityFilterChain")
and: "springSecurityFilterChain is defined in both parent and child (don't search parent)"
parent.containsBeanDefinition("springSecurityFilterChain")
child.containsBeanDefinition("springSecurityFilterChain")
cleanup:
child?.close()
// parent.close() is in superclass
}
@EnableWebSecurity
@Configuration
static class ParentConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.inMemoryAuthentication()
}
}
@EnableWebSecurity
@Configuration
static class ChildConfig extends WebSecurityConfigurerAdapter { }
}
@@ -0,0 +1,38 @@
/*
* 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.sec2377;
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.web.configuration.sec2377.a.*
import org.springframework.security.config.annotation.web.configuration.sec2377.b.*
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext
public class Sec2377Tests extends BaseSpringSpec {
def "SEC-2377: Error reporting with multiple EnableWebSecurity from other packages"() {
when:
AnnotationConfigWebApplicationContext parent = new AnnotationConfigWebApplicationContext()
parent.register(Sec2377AConfig)
parent.refresh()
AnnotationConfigWebApplicationContext child = new AnnotationConfigWebApplicationContext()
child.register(Sec2377BConfig)
child.parent = parent
child.refresh()
then:
noExceptionThrown();
}
}
@@ -0,0 +1,26 @@
/*
* 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.sec2377.a;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableWebSecurity
@Configuration
public class Sec2377AConfig extends WebSecurityConfigurerAdapter {
}
@@ -0,0 +1,26 @@
/*
* 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.sec2377.b;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableWebSecurity
@Configuration
public class Sec2377BConfig extends WebSecurityConfigurerAdapter {
}
@@ -0,0 +1,51 @@
/*
* 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.configurers;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.event.AuthorizedEvent;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
@Configuration
@EnableWebSecurity
public class AuthorizedRequestsWithPostProcessorConfig extends WebSecurityConfigurerAdapter {
static ApplicationListener<AuthorizedEvent> AL;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().permitAll()
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
public <O extends FilterSecurityInterceptor> O postProcess(
O fsi) {
fsi.setPublishAuthorizationSuccess(true);
return fsi;
}
});
}
@Bean
public ApplicationListener<AuthorizedEvent> applicationListener() {
return AL;
}
}
@@ -18,19 +18,21 @@ package org.springframework.security.config.annotation.web.configurers
import javax.servlet.http.HttpServletResponse
import org.springframework.context.annotation.Configuration
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.web.access.AccessDeniedHandler
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.web.servlet.support.RequestDataValueProcessor;
import org.springframework.security.web.csrf.CsrfFilter
import org.springframework.security.web.csrf.CsrfTokenRepository
import org.springframework.security.web.util.matcher.RequestMatcher
import org.springframework.web.servlet.support.RequestDataValueProcessor
import spock.lang.Unroll;
import spock.lang.Unroll
/**
*
@@ -69,7 +71,7 @@ class CsrfConfigurerTests extends BaseSpringSpec {
}
@Configuration
@EnableWebSecurity
@EnableWebMvcSecurity
static class CsrfAppliedDefaultConfig extends WebSecurityConfigurerAdapter {
@Override
@@ -100,6 +102,80 @@ class CsrfConfigurerTests extends BaseSpringSpec {
}
}
def "SEC-2498: Disable CSRF enables RequestCache for any method"() {
setup:
loadConfig(DisableCsrfEnablesRequestCacheConfig)
request.requestURI = '/tosave'
request.method = "POST"
clearCsrfToken()
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.redirectedUrl
when:
super.setupWeb(request.session)
request.method = "POST"
request.servletPath = '/login'
request.parameters['username'] = ['user'] as String[]
request.parameters['password'] = ['password'] as String[]
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.redirectedUrl == 'http://localhost/tosave'
}
@Configuration
@EnableWebSecurity
static class DisableCsrfEnablesRequestCacheConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().and()
.csrf().disable()
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
}
def "SEC-2422: csrf expire CSRF token and session-management invalid-session-url"() {
setup:
loadConfig(InvalidSessionUrlConfig)
request.session.clearAttributes()
request.setParameter("_csrf","abc")
request.method = "POST"
when: "No existing expected CsrfToken (session times out) and a POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to the session timeout page page"
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "/error/sessionError"
when: "Existing expected CsrfToken and a POST (invalid token provided)"
response = new MockHttpServletResponse()
request = new MockHttpServletRequest(session: request.session, method:'POST')
springSecurityFilterChain.doFilter(request,response,chain)
then: "Access Denied occurs"
response.status == HttpServletResponse.SC_FORBIDDEN
}
@Configuration
@EnableWebSecurity
static class InvalidSessionUrlConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().and()
.sessionManagement()
.invalidSessionUrl("/error/sessionError")
}
}
def "csrf requireCsrfProtectionMatcher"() {
setup:
RequireCsrfProtectionMatcherConfig.matcher = Mock(RequestMatcher)
@@ -158,7 +234,7 @@ class CsrfConfigurerTests extends BaseSpringSpec {
def "csrf clears on login"() {
setup:
CsrfTokenRepositoryConfig.repo = Mock(CsrfTokenRepository)
1 * CsrfTokenRepositoryConfig.repo.loadToken(_) >> csrfToken
(1.._) * CsrfTokenRepositoryConfig.repo.loadToken(_) >> csrfToken
loadConfig(CsrfTokenRepositoryConfig)
request.method = "POST"
request.getSession()
@@ -169,7 +245,7 @@ class CsrfConfigurerTests extends BaseSpringSpec {
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.redirectedUrl == "/"
1 * CsrfTokenRepositoryConfig.repo.saveToken(null, _, _)
(1.._) * CsrfTokenRepositoryConfig.repo.saveToken(null, _, _)
}
@Configuration
@@ -282,7 +358,7 @@ class CsrfConfigurerTests extends BaseSpringSpec {
when: "CSRF passes and our session times out"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to the login page"
1 * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "http://localhost/login"
when: "authenticate successfully"
@@ -293,7 +369,7 @@ class CsrfConfigurerTests extends BaseSpringSpec {
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default success because we don't want csrf attempts made prior to authentication to pass"
1 * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "/"
}
@@ -308,7 +384,7 @@ class CsrfConfigurerTests extends BaseSpringSpec {
when: "CSRF passes and our session times out"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to the login page"
1 * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "http://localhost/login"
when: "authenticate successfully"
@@ -319,7 +395,7 @@ class CsrfConfigurerTests extends BaseSpringSpec {
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to original URL since it was a GET"
1 * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "http://localhost/some-url"
}
@@ -18,16 +18,23 @@ package org.springframework.security.config.annotation.web.configurers;
import java.util.Arrays;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.access.expression.SecurityExpressionOperations;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.access.expression.WebExpressionVoter;
import org.springframework.security.web.access.expression.WebSecurityExpressionRoot;
/**
*
@@ -60,4 +67,90 @@ public class ExpressionUrlAuthorizationConfigurerConfigs {
.formLogin();
}
}
@EnableWebSecurity
@Configuration
static class UseBeansInExpressions extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasRole("USER")
.antMatchers("/allow/**").access("@permission.check(authentication,'user')")
.anyRequest().access("@permission.check(authentication,'admin')");
}
@Bean
public Checker permission() {
return new Checker();
}
static class Checker {
public boolean check(Authentication authentication, String customArg) {
return authentication.getName().contains(customArg);
}
}
}
@EnableWebSecurity
@Configuration
static class CustomExpressionRootConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.expressionHandler(expressionHandler())
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasRole("USER")
.antMatchers("/allow/**").access("check('user')")
.anyRequest().access("check('admin')");
}
@Bean
public CustomExpressionHandler expressionHandler() {
return new CustomExpressionHandler();
}
static class CustomExpressionHandler extends DefaultWebSecurityExpressionHandler {
@Override
protected SecurityExpressionOperations createSecurityExpressionRoot(
Authentication authentication, FilterInvocation fi) {
WebSecurityExpressionRoot root = new CustomExpressionRoot(authentication, fi);
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(new AuthenticationTrustResolverImpl());
root.setRoleHierarchy(getRoleHierarchy());
return root;
}
}
static class CustomExpressionRoot extends WebSecurityExpressionRoot {
public CustomExpressionRoot(Authentication a, FilterInvocation fi) {
super(a, fi);
}
public boolean check(String customArg) {
Authentication auth = this.getAuthentication();
return auth.getName().contains(customArg);
}
}
}
}
@@ -20,7 +20,9 @@ import static org.springframework.security.config.annotation.web.configurers.Exp
import javax.servlet.http.HttpServletResponse
import org.springframework.beans.factory.BeanCreationException
import org.springframework.context.ApplicationListener
import org.springframework.context.annotation.Configuration
import org.springframework.security.access.event.AuthorizedEvent
import org.springframework.security.access.vote.AffirmativeBased
import org.springframework.security.authentication.RememberMeAuthenticationToken
import org.springframework.security.config.annotation.BaseSpringSpec
@@ -29,6 +31,7 @@ import org.springframework.security.config.annotation.authentication.builders.Au
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurerConfigs.CustomExpressionRootConfig;
import org.springframework.security.core.authority.AuthorityUtils
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor
@@ -462,4 +465,79 @@ public class ExpressionUrlAuthorizationConfigurerTests extends BaseSpringSpec {
then:
noExceptionThrown()
}
def "AuthorizedRequests withPostProcessor"() {
setup:
ApplicationListener al = Mock()
AuthorizedRequestsWithPostProcessorConfig.AL = al
loadConfig(AuthorizedRequestsWithPostProcessorConfig)
when:
springSecurityFilterChain.doFilter(request, response, chain)
then:
1 * al.onApplicationEvent(_ as AuthorizedEvent)
}
def "Use @permission.check in access"() {
setup:
loadConfig(UseBeansInExpressions)
when: "invoke standard expression that denies access"
login()
request.servletPath = "/admin/1"
springSecurityFilterChain.doFilter(request, response, chain)
then: "standard expression works - get forbidden"
response.status == HttpServletResponse.SC_FORBIDDEN
when: "invoke standard expression that allows access"
super.setup()
login()
request.servletPath = "/user/1"
springSecurityFilterChain.doFilter(request, response, chain)
then: "standard expression works - get ok"
response.status == HttpServletResponse.SC_OK
when: "invoke custom bean as expression that allows access"
super.setup()
login()
request.servletPath = "/allow/1"
springSecurityFilterChain.doFilter(request, response, chain)
then: "custom bean expression allows access"
response.status == HttpServletResponse.SC_OK
when: "invoke custom bean as expression that denies access"
super.setup()
login()
request.servletPath = "/deny/1"
springSecurityFilterChain.doFilter(request, response, chain)
then: "custom bean expression denies access"
response.status == HttpServletResponse.SC_FORBIDDEN
}
def "Use custom expressionroot in access"() {
setup:
loadConfig(CustomExpressionRootConfig)
when: "invoke standard expression that denies access"
login()
request.servletPath = "/admin/1"
springSecurityFilterChain.doFilter(request, response, chain)
then: "standard expression works - get forbidden"
response.status == HttpServletResponse.SC_FORBIDDEN
when: "invoke standard expression that allows access"
super.setup()
login()
request.servletPath = "/user/1"
springSecurityFilterChain.doFilter(request, response, chain)
then: "standard expression works - get ok"
response.status == HttpServletResponse.SC_OK
when: "invoke custom bean as expression that allows access"
super.setup()
login()
request.servletPath = "/allow/1"
springSecurityFilterChain.doFilter(request, response, chain)
then: "custom bean expression allows access"
response.status == HttpServletResponse.SC_OK
when: "invoke custom bean as expression that denies access"
super.setup()
login()
request.servletPath = "/deny/1"
springSecurityFilterChain.doFilter(request, response, chain)
then: "custom bean expression denies access"
response.status == HttpServletResponse.SC_FORBIDDEN
}
}
@@ -186,6 +186,45 @@ class FormLoginConfigurerTests extends BaseSpringSpec {
}
}
def "FormLogin loginProcessingUrl"() {
setup:
loadConfig(FormLoginLoginProcessingUrlConfig)
request.servletPath = "/loginCheck"
request.method = "POST"
request.parameters.username = ["user"] as String[]
request.parameters.password = ["password"] as String[]
when:
springSecurityFilterChain.doFilter(request, response, new MockFilterChain())
then:
response.redirectedUrl == "/"
}
@Configuration
@EnableWebSecurity
static class FormLoginLoginProcessingUrlConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/loginCheck")
.loginPage("/login")
//.failureUrl("/loginFailure")
.defaultSuccessUrl("/", true)
.passwordParameter("password")
.usernameParameter("username")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/login")
.logoutUrl("/logout")
.deleteCookies("JSESSIONID")
}
}
def "FormLogin uses PortMapper"() {
when: "load formLogin() with permitAll"
FormLoginUsesPortMapperConfig.PORT_MAPPER = Mock(PortMapper)
@@ -19,6 +19,7 @@ import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@@ -36,11 +37,13 @@ import org.springframework.stereotype.Component
class Issue55Tests extends BaseSpringSpec {
def "WebSecurityConfigurerAdapter defaults to @Autowired"() {
setup:
TestingAuthenticationToken token = new TestingAuthenticationToken("test", "this")
when:
loadConfig(WebSecurityConfigurerAdapterDefaultsAuthManagerConfig)
loadConfig(WebSecurityConfigurerAdapterDefaultsAuthManagerConfig)
then:
context.getBean(FilterChainProxy)
findFilter(FilterSecurityInterceptor).authenticationManager.parent.class == CustomAuthenticationManager
context.getBean(FilterChainProxy)
findFilter(FilterSecurityInterceptor).authenticationManager.authenticate(token) == CustomAuthenticationManager.RESULT
}
@Configuration
@@ -66,12 +69,14 @@ class Issue55Tests extends BaseSpringSpec {
}
def "multi http WebSecurityConfigurerAdapter defaults to @Autowired"() {
setup:
TestingAuthenticationToken token = new TestingAuthenticationToken("test", "this")
when:
loadConfig(MultiWebSecurityConfigurerAdapterDefaultsAuthManagerConfig)
loadConfig(MultiWebSecurityConfigurerAdapterDefaultsAuthManagerConfig)
then:
context.getBean(FilterChainProxy)
findFilter(FilterSecurityInterceptor).authenticationManager.parent.class == CustomAuthenticationManager
findFilter(FilterSecurityInterceptor,1).authenticationManager.parent.class == CustomAuthenticationManager
context.getBean(FilterChainProxy)
findFilter(FilterSecurityInterceptor).authenticationManager.authenticate(token) == CustomAuthenticationManager.RESULT
findFilter(FilterSecurityInterceptor,1).authenticationManager.authenticate(token) == CustomAuthenticationManager.RESULT
}
@Configuration
@@ -107,8 +112,9 @@ class Issue55Tests extends BaseSpringSpec {
}
static class CustomAuthenticationManager implements AuthenticationManager {
static Authentication RESULT = new TestingAuthenticationToken("test", "this","ROLE_USER")
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
return null;
return RESULT;
}
}
}
@@ -12,27 +12,29 @@
*/
package org.springframework.security.config.http
import static org.mockito.Mockito.*
import static org.mockito.Matchers.*
import static org.mockito.Mockito.*
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import org.spockframework.compiler.model.WhenBlock;
import org.springframework.mock.web.MockFilterChain
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurerTests.CsrfTokenRepositoryConfig;
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurerTests.RequireCsrfProtectionMatcherConfig
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.access.AccessDeniedException
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.Authentication
import org.springframework.security.core.authority.AuthorityUtils
import org.springframework.security.core.context.SecurityContextImpl
import org.springframework.security.web.access.AccessDeniedHandler
import org.springframework.security.web.context.HttpRequestResponseHolder
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
import org.springframework.security.web.csrf.CsrfFilter
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.DefaultCsrfToken;
import org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor
import org.springframework.security.web.csrf.CsrfToken
import org.springframework.security.web.csrf.CsrfTokenRepository
import org.springframework.security.web.csrf.DefaultCsrfToken
import org.springframework.security.web.util.matcher.RequestMatcher
import org.springframework.web.servlet.support.RequestDataValueProcessor;
import org.springframework.web.servlet.support.RequestDataValueProcessor
import spock.lang.Unroll
@@ -174,6 +176,28 @@ class CsrfConfigTests extends AbstractHttpConfigTests {
response.redirectedUrl == "http://localhost/some-url"
}
def "SEC-2422: csrf expire CSRF token and session-management invalid-session-url"() {
setup:
httpAutoConfig {
'csrf'()
'session-management'('invalid-session-url': '/error/sessionError')
}
createAppContext()
request.setParameter("_csrf","abc")
request.method = "POST"
when: "No existing expected CsrfToken (session times out) and a POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to the session timeout page page"
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "/error/sessionError"
when: "Existing expected CsrfToken and a POST (invalid token provided)"
response = new MockHttpServletResponse()
request = new MockHttpServletRequest(session: request.session, method:'POST')
springSecurityFilterChain.doFilter(request,response,chain)
then: "Access Denied occurs"
response.status == HttpServletResponse.SC_FORBIDDEN
}
def "csrf requireCsrfProtectionMatcher"() {
setup:
httpAutoConfig {
@@ -181,6 +205,7 @@ class CsrfConfigTests extends AbstractHttpConfigTests {
}
mockBean(RequestMatcher,'matcher')
createAppContext()
request.method = 'POST'
RequestMatcher matcher = appContext.getBean("matcher",RequestMatcher)
when:
when(matcher.matches(any(HttpServletRequest))).thenReturn(false)
@@ -235,7 +260,7 @@ class CsrfConfigTests extends AbstractHttpConfigTests {
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
verify(repo).saveToken(eq(null),any(HttpServletRequest), any(HttpServletResponse))
verify(repo, atLeastOnce()).saveToken(eq(null),any(HttpServletRequest), any(HttpServletResponse))
}
def "csrf clears on logout"() {
@@ -250,10 +275,43 @@ class CsrfConfigTests extends AbstractHttpConfigTests {
when(repo.loadToken(any(HttpServletRequest))).thenReturn(token)
request.setParameter(token.parameterName,token.token)
request.method = "POST"
request.requestURI = "/j_spring_security_logout"
request.servletPath = "/j_spring_security_logout"
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
verify(repo).saveToken(eq(null),any(HttpServletRequest), any(HttpServletResponse))
}
def "SEC-2495: csrf disables logout on GET"() {
setup:
httpAutoConfig {
'csrf'()
}
createAppContext()
login()
request.method = "GET"
request.requestURI = "/j_spring_security_logout"
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
getAuthentication(request) != null
}
def login(String username="user", String role="ROLE_USER") {
login(new UsernamePasswordAuthenticationToken(username, null, AuthorityUtils.createAuthorityList(role)))
}
def login(Authentication auth) {
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository()
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
repo.loadContext(requestResponseHolder)
repo.saveContext(new SecurityContextImpl(authentication:auth), requestResponseHolder.request, requestResponseHolder.response)
}
def getAuthentication(HttpServletRequest request) {
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository()
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response)
repo.loadContext(requestResponseHolder)?.authentication
}
}
@@ -0,0 +1,109 @@
package org.springframework.security.config.http
import org.springframework.mock.web.MockFilterChain
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.mock.web.MockHttpServletResponse
/**
*
* @author Luke Taylor
*/
class FormLoginBeanDefinitionParserTests extends AbstractHttpConfigTests {
def 'form-login default login page'() {
setup:
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/spring_security_login')
MockHttpServletResponse response = new MockHttpServletResponse()
MockFilterChain chain = new MockFilterChain()
httpAutoConfig {
}
createAppContext()
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.j_username.focus();'>
<h3>Login with Username and Password</h3><form name='f' action='/j_spring_security_check' method='POST'>
<table>
<tr><td>User:</td><td><input type='text' name='j_username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='j_password'/></td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
</table>
</form></body></html>"""
}
def 'form-login default login page custom attributes'() {
setup:
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/spring_security_login')
MockHttpServletResponse response = new MockHttpServletResponse()
MockFilterChain chain = new MockFilterChain()
httpAutoConfig {
'form-login'('login-processing-url':'/login_custom','username-parameter':'custom_user','password-parameter':'custom_password')
}
createAppContext()
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.custom_user.focus();'>
<h3>Login with Username and Password</h3><form name='f' action='/login_custom' method='POST'>
<table>
<tr><td>User:</td><td><input type='text' name='custom_user' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='custom_password'/></td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
</table>
</form></body></html>"""
}
def 'openid-login default login page'() {
setup:
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/spring_security_login')
MockHttpServletResponse response = new MockHttpServletResponse()
MockFilterChain chain = new MockFilterChain()
httpAutoConfig {
'openid-login'()
}
createAppContext()
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.j_username.focus();'>
<h3>Login with Username and Password</h3><form name='f' action='/j_spring_security_check' method='POST'>
<table>
<tr><td>User:</td><td><input type='text' name='j_username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='j_password'/></td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
</table>
</form><h3>Login with OpenID Identity</h3><form name='oidf' action='/j_spring_openid_security_check' method='POST'>
<table>
<tr><td>Identity:</td><td><input type='text' size='30' name='openid_identifier'/></td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
</table>
</form></body></html>"""
}
def 'openid-login default login page custom attributes'() {
setup:
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET',requestURI:'/spring_security_login')
MockHttpServletResponse response = new MockHttpServletResponse()
MockFilterChain chain = new MockFilterChain()
httpAutoConfig {
'openid-login'('login-processing-url':'/login_custom')
}
createAppContext()
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.j_username.focus();'>
<h3>Login with Username and Password</h3><form name='f' action='/j_spring_security_check' method='POST'>
<table>
<tr><td>User:</td><td><input type='text' name='j_username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='j_password'/></td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
</table>
</form><h3>Login with OpenID Identity</h3><form name='oidf' action='/login_custom' method='POST'>
<table>
<tr><td>Identity:</td><td><input type='text' size='30' name='openid_identifier'/></td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
</table>
</form></body></html>"""
}
}
@@ -6,6 +6,8 @@ import org.springframework.security.web.access.ExceptionTranslationFilter
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.ReflectionUtils;
/**
*
@@ -102,4 +104,18 @@ class FormLoginConfigTests extends AbstractHttpConfigTests {
apf.usernameParameter == 'xname';
apf.passwordParameter == 'xpass'
}
def 'SEC-2455: http@login-processing-url'() {
when:
xml.http {
'form-login'('login-processing-url':'/authenticate')
}
createAppContext()
def apf = getFilter(UsernamePasswordAuthenticationFilter);
then:
apf.filterProcessesUrl == null // SEC-2455 setFilterProcessesUrl was not invoked
FieldUtils.getFieldValue(apf,'requiresAuthenticationRequestMatcher.filterProcessesUrl') == '/authenticate'
}
}
@@ -17,7 +17,10 @@ package org.springframework.security.config.http;
import java.security.Principal
import javax.servlet.Filter
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.BeansException
import org.springframework.beans.factory.BeanCreationException
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
@@ -98,4 +101,27 @@ class InterceptUrlConfigTests extends AbstractHttpConfigTests {
attrsPost.size() == 1
attrsPost.contains(new SecurityConfig("ROLE_USER"))
}
def "SEC-2355: intercept-url support patch"() {
setup:
MockHttpServletRequest request = new MockHttpServletRequest(method:'GET')
MockHttpServletResponse response = new MockHttpServletResponse()
MockFilterChain chain = new MockFilterChain()
xml.http() {
'http-basic'()
'intercept-url'(pattern: '/**', 'method':'PATCH',access: 'ROLE_ADMIN')
}
createAppContext()
when: 'Method other than PATCH is used'
springSecurityFilterChain.doFilter(request,response,chain)
then: 'The response is OK'
response.status == HttpServletResponse.SC_OK
when: 'Method of PATCH is used'
request = new MockHttpServletRequest(method:'PATCH')
response = new MockHttpServletResponse()
chain = new MockFilterChain()
springSecurityFilterChain.doFilter(request, response, chain)
then: 'The response is unauthorized'
response.status == HttpServletResponse.SC_UNAUTHORIZED
}
}
@@ -0,0 +1,25 @@
package org.springframework.security.config.http
import org.springframework.security.util.FieldUtils
import org.springframework.security.web.authentication.logout.LogoutFilter
/**
*
* @author Rob Winch
*/
class LogoutConfigTests extends AbstractHttpConfigTests {
def 'SEC-2455: logout@logout-url'() {
when:
httpAutoConfig {
'logout'('logout-url':'/logout')
}
createAppContext()
def lf = getFilter(LogoutFilter);
then:
lf.filterProcessesUrl == null // SEC-2455 setFilterProcessesUrl was not invoked
FieldUtils.getFieldValue(lf,'logoutRequestMatcher.filterProcessesUrl') == '/logout'
}
}
@@ -17,6 +17,10 @@ package org.springframework.security.config.http
import static org.springframework.security.config.ConfigTestUtils.AUTH_PROVIDER_XML
import javax.sql.DataSource
import org.springframework.beans.FatalBeanException
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException
import org.springframework.security.TestDataSource
import org.springframework.security.authentication.ProviderManager
@@ -26,7 +30,7 @@ import org.springframework.security.util.FieldUtils
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler
import org.springframework.security.web.authentication.logout.LogoutFilter
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices
import org.springframework.security.web.authentication.rememberme.InMemoryTokenRepositoryImpl
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl
import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices
@@ -154,6 +158,32 @@ class RememberMeConfigTests extends AbstractHttpConfigTests {
rememberMeServices().tokenValiditySeconds == -1
}
def 'remember-me@token-validity-seconds denies for persistent implementation'() {
setup:
httpAutoConfig () {
'remember-me'('key': 'ourkey', 'token-validity-seconds':'-1', 'dataSource' : 'dataSource')
}
mockBean(DataSource)
when:
createAppContext(AUTH_PROVIDER_XML)
then:
thrown(FatalBeanException)
}
def 'SEC-2165: remember-me@token-validity-seconds allows property placeholders'() {
when:
httpAutoConfig () {
'remember-me'('key': 'ourkey', 'token-validity-seconds':'${security.rememberme.ttl}')
}
xml.'b:bean'(class: PropertyPlaceholderConfigurer.name) {
'b:property'(name:'properties', value:'security.rememberme.ttl=30')
}
createAppContext(AUTH_PROVIDER_XML)
then:
rememberMeServices().tokenValiditySeconds == 30
}
def rememberMeSecureCookieAttributeIsSetCorrectly() {
httpAutoConfig () {
'remember-me'('key': 'ourkey', 'use-secure-cookie':'true')
@@ -34,7 +34,7 @@ public class DataSourcePopulator implements InitializingBean {
public void afterPropertiesSet() throws Exception {
Assert.notNull(template, "dataSource required");
template.execute("CREATE TABLE USERS(USERNAME VARCHAR_IGNORECASE(50) NOT NULL PRIMARY KEY,PASSWORD VARCHAR_IGNORECASE(50) NOT NULL,ENABLED BOOLEAN NOT NULL);");
template.execute("CREATE TABLE USERS(USERNAME VARCHAR_IGNORECASE(50) NOT NULL PRIMARY KEY,PASSWORD VARCHAR_IGNORECASE(500) NOT NULL,ENABLED BOOLEAN NOT NULL);");
template.execute("CREATE TABLE AUTHORITIES(USERNAME VARCHAR_IGNORECASE(50) NOT NULL,AUTHORITY VARCHAR_IGNORECASE(50) NOT NULL,CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY(USERNAME) REFERENCES USERS(USERNAME));");
template.execute("CREATE UNIQUE INDEX IX_AUTH_USERNAME ON AUTHORITIES(USERNAME,AUTHORITY);");
@@ -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;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:org/springframework/security/config/sec-2508.xml" )
public class Sec2508Tests {
@Autowired
private AuthenticationEntryPoint ep;
@Test
public void loads() {}
}
@@ -16,30 +16,21 @@
package org.springframework.security.config.annotation.web.configurers;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.util.ClassUtils;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
/**
* @author Rob Winch
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassUtils.class})
public class CsrfConfigurerNoWebMvcTests {
ConfigurableApplicationContext context;
@@ -52,24 +43,30 @@ public class CsrfConfigurerNoWebMvcTests {
@Test
public void missingDispatcherServletPreventsCsrfRequestDataValueProcessor() {
spy(ClassUtils.class);
when(ClassUtils.isPresent(eq("org.springframework.web.servlet.DispatcherServlet"), any(ClassLoader.class))).thenReturn(false);
loadContext(CsrfDefaultsConfig.class);
loadContext(EnableWebConfig.class);
assertThat(context.containsBeanDefinition("requestDataValueProcessor")).isFalse();
}
@Test
public void findDispatcherServletPreventsCsrfRequestDataValueProcessor() {
loadContext(CsrfDefaultsConfig.class);
loadContext(EnableWebMvcConfig.class);
assertThat(context.containsBeanDefinition("requestDataValueProcessor")).isTrue();
}
@EnableWebSecurity
@Configuration
static class CsrfDefaultsConfig extends WebSecurityConfigurerAdapter {
static class EnableWebConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
}
}
@EnableWebMvcSecurity
@Configuration
static class EnableWebMvcConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
@@ -0,0 +1,50 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.method.sec2499;
import org.junit.After;
import org.junit.Test;
import org.springframework.context.support.GenericXmlApplicationContext;
/**
*
* @author Rob Winch
*
*/
public class Sec2499Tests {
private GenericXmlApplicationContext parent;
private GenericXmlApplicationContext child;
@After
public void cleanup() {
if(parent != null) {
parent.close();
}
if(child != null) {
child.close();
}
}
@Test
public void methodExpressionHandlerInParentContextLoads() {
parent = new GenericXmlApplicationContext("org/springframework/security/config/method/sec2499/parent.xml");
child = new GenericXmlApplicationContext();
child.load("org/springframework/security/config/method/sec2499/child.xml");
child.setParent(parent);
child.refresh();
}
}
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<global-method-security pre-post-annotations="enabled">
<expression-handler ref="expressionHandler"/>
</global-method-security>
</b:beans>
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="expressionHandler"
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler"/>
</beans>
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint">
<constructor-arg>
<map>
<entry>
<key>
<bean class="org.springframework.security.web.util.AntPathRequestMatcher">
<constructor-arg value="/**"/>
</bean>
</key>
<bean class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/>
</entry>
</map>
</constructor-arg>
<property name="defaultEntryPoint">
<bean class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/>
</property>
</bean>
</beans>
+1 -1
View File
@@ -30,7 +30,7 @@ dependencies {
"org.slf4j:jcl-over-slf4j:$slf4jVersion",
powerMockDependencies
testRuntime "hsqldb:hsqldb:$hsqlVersion",
testRuntime "org.hsqldb:hsqldb:$hsqlVersion",
"cglib:cglib-nodep:$cglibVersion"
}
+22 -28
View File
@@ -4,13 +4,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.2.0.CI-SNAPSHOT</version>
<version>3.2.3.RELEASE</version>
<name>spring-security-core</name>
<description>spring-security-core</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</groupId>
<artifactId>spring-aop</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -88,7 +82,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -122,14 +116,14 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
@@ -151,12 +145,6 @@
<version>3.2</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>
@@ -169,6 +157,12 @@
<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>
@@ -220,7 +214,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.4.RELEASE</version>
<version>3.2.8.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -12,30 +12,91 @@ import org.springframework.security.core.Authentication;
*/
public interface SecurityExpressionOperations {
/**
* Gets the {@link Authentication} used for evaluating the expressions
* @return the {@link Authentication} for evaluating the expressions
*/
Authentication getAuthentication();
/**
* Determines if the {@link #getAuthentication()} has a particular authority within {@link Authentication#getAuthorities()}. This is a synonym for {@link #hasAuthority(String)}.
* @param authority the authority to test (i.e. "ROLE_USER")
* @return true if the authority is found, else false
*/
boolean hasAuthority(String authority);
/**
* Determines if the {@link #getAuthentication()} has any of the specified authorities within {@link Authentication#getAuthorities()}. This is a synonym for {@link #hasAnyRole(String...)}.
* @param authorities the authorities to test (i.e. "ROLE_USER", "ROLE_ADMIN")
* @return true if any of the authorities is found, else false
*/
boolean hasAnyAuthority(String... authorities);
/**
* Determines if the {@link #getAuthentication()} has a particular authority within {@link Authentication#getAuthorities()}. This is a synonym for {@link #hasAuthority(String)}.
* @param authority the authority to test (i.e. "ROLE_USER")
* @return true if the authority is found, else false
*/
boolean hasRole(String role);
/**
* Determines if the {@link #getAuthentication()} has any of the specified authorities within {@link Authentication#getAuthorities()}. This is a synonym for {@link #hasAnyAuthority(String...)}.
* @param authorities the authorities to test (i.e. "ROLE_USER", "ROLE_ADMIN")
* @return true if any of the authorities is found, else false
*/
boolean hasAnyRole(String... roles);
/**
* Always grants access.
* @return true
*/
boolean permitAll();
/**
* Always denies access
* @return false
*/
boolean denyAll();
/**
* Determines if the {@link #getAuthentication()} is anonymous
* @return true if the user is anonymous, else false
*/
boolean isAnonymous();
/**
* Determines ifthe {@link #getAuthentication()} is authenticated
* @return true if the {@link #getAuthentication()} is authenticated, else false
*/
boolean isAuthenticated();
/**
* Determines if the {@link #getAuthentication()} was authenticated using remember me
* @return true if the {@link #getAuthentication()} authenticated using remember me, else false
*/
boolean isRememberMe();
/**
* Determines if the {@link #getAuthentication()} authenticated without the use of remember me
* @return true if the {@link #getAuthentication()} authenticated without the use of remember me, else false
*/
boolean isFullyAuthenticated();
/**
* Determines if the {@link #getAuthentication()} has permission to access the target given the permission
* @param target the target domain object to check permission on
* @param permission the permission to check on the domain object (i.e. "read", "write", etc).
* @return true if permission is granted to the {@link #getAuthentication()}, else false
*/
boolean hasPermission(Object target, Object permission);
/**
* Determines if the {@link #getAuthentication()} has permission to access the domain object with a given id, type, and permission.
* @param targetId the identifier of the domain object to determine access
* @param targetType the type (i.e. com.example.domain.Message)
* @param permission the perission to check on the domain object (i.e. "read", "write", etc)
* @return true if permission is granted to the {@link #getAuthentication()}, else false
*/
boolean hasPermission(Object targetId, String targetType, Object permission);
}
@@ -5,7 +5,6 @@ import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.springframework.context.ApplicationContext;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.authentication.AuthenticationTrustResolver;
@@ -38,11 +37,15 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
public final String delete = "delete";
public final String admin = "administration";
public SecurityExpressionRoot(Authentication a) {
if (a == null) {
/**
* Creates a new instance
* @param authentication the {@link Authentication} to use. Cannot be null.
*/
public SecurityExpressionRoot(Authentication authentication) {
if (authentication == null) {
throw new IllegalArgumentException("Authentication object cannot be null");
}
this.authentication = a;
this.authentication = authentication;
}
public final boolean hasAuthority(String authority) {
@@ -97,6 +100,10 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
return !trustResolver.isAnonymous(authentication) && !trustResolver.isRememberMe(authentication);
}
/**
* Convenience method to access {@link Authentication#getPrincipal()} from {@link #getAuthentication()}
* @return
*/
public Object getPrincipal() {
return authentication.getPrincipal();
}
@@ -17,7 +17,7 @@ package org.springframework.security.authentication;
* Thrown if an authentication request could not be processed due to a system problem that occurred internally. It
* differs from {@link AuthenticationServiceException} in that it would not be thrown if an external system has an
* internal error or failure. This ensures that we can handle errors that are within our control distinctly from errors
* of other systems. The advantage to this distinction is that the unrusted external system should not be able to fill
* of other systems. The advantage to this distinction is that the untrusted external system should not be able to fill
* up logs and cause excessive IO. However, an internal system should report errors.
* </p>
* <p>
@@ -163,6 +163,9 @@ public class ProviderManager implements AuthenticationManager, MessageSourceAwar
prepareException(e, authentication);
// SEC-546: Avoid polling additional providers if auth failure is due to invalid account status
throw e;
} catch (InternalAuthenticationServiceException e) {
prepareException(e, authentication);
throw e;
} catch (AuthenticationException e) {
lastException = e;
}

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