1
0
mirror of synced 2026-09-05 08:49:54 +00:00

Compare commits

...

109 Commits

Author SHA1 Message Date
Spring Buildmaster 19f88e9179 Release version 4.0.3.RELEASE 2015-10-30 12:35:23 -07:00
Rob Winch cf9b6bc0de SEC-2848: LogoutConfigurer allows setting clearAuthentication 2015-10-30 13:54:30 -05:00
Rob Winch fc67550ff2 SEC-3135: antMatchers(<method>,new String[0]) now passive 2015-10-30 10:09:03 -05:00
Rob Winch af2a431f23 SEC-3120: Remove .and() from httpStrictTransportSecurity() doc 2015-10-30 09:10:57 -05:00
Rob Winch 8d9b06afb4 SEC-3082: make SavedRequest parameters case sensitive 2015-10-29 16:46:33 -05:00
Rob Winch 0ecdd0e856 SEC-3120: Reference hsts() -> httpStrictTransportSecurity() 2015-10-29 15:10:16 -05:00
Rob Winch edd2751ff1 SEC-3128: RoleVoter supports null Authentication 2015-10-29 14:03:47 -05:00
Rob Winch 8663ac4173 SEC-3135: antMatchers now allows method and no pattern
Previously, antMatchers(POST).authenticated() was not allowed. Instead
users had to use antMatchers(POST, "/**").authenticated().

Now we default the patterns to be "/**" if it is null or empty.
2015-10-29 12:48:56 -05:00
Rob Winch 72213b5c69 SEC-2190: Fix Javadoc 2015-10-29 11:42:03 -05:00
Rob Winch 2bbe70501b SEC-2190: Support WebApplicationContext in ServletContext attribute 2015-10-28 15:26:16 -05:00
Rob Winch da606d50c0 SEC-3108: DigestAuthenticationFilter should use SecurityContextHolder.createEmptyContext() 2015-10-27 13:57:18 -05:00
Rob Winch d648a56e16 SEC-2521: Improve StandardPasswordEncoder performance 2015-10-27 11:21:05 -05:00
Rob Winch 9c39a0e83e SEC-3109: Fix web tests 2015-10-26 21:31:40 -05:00
Rob Winch c8692b6d0b SEC-3109: DelegatingSecurityContextExecutor fails with same Thread
Previously DelegatingSecurityContextRunnable and DelegatingSecurityContextCallable
would not setup the SecurityContext if it was on the same thread as it was created.
This was intended to fix SEC-3031 but simply caused more problems.

This commit changes the strategy to keep track of the previous SecurityContext
and restore it (or clear it out if it was originally empty).
2015-10-26 17:17:31 -05:00
Rob Winch 45bbabd485 SEC-3057: Include all *.txt & *.jar in dist zip 2015-10-26 14:04:48 -05:00
Rob Winch 43fbeab106 SEC-3133: Correct test doc username parameter 2015-10-26 13:00:27 -05:00
Rob Winch b719e0fbcc SEC-3132: securityBuilder cannot be null
If a custom SecurityConfiguererAdapter applies another
SecurityConfigurerAdapter it caused an error securityBuilder cannot be null.

This commit fixes this.
2015-10-23 10:28:27 -05:00
Rob Winch 09bf290583 SEC-3129: Update Spring 2015-10-22 10:04:52 -05:00
Rob Winch 9a6f026dff SEC-3052: Doc DEFAULT_MATCHER->DEFAULT_CSRF_MATCHER 2015-10-21 16:22:53 -05:00
Rob Winch 269127c2c6 SEC-2941: Default RequestPostProcessor overrides
Previously a default RequestPostProcessor overrode additional
RequestPostProcessor instances added to the request. This was due to
SPR-12945. Now that SPR-12945 is fixed, this commit adds a test to
ensure this stays fixed.
2015-10-21 16:09:15 -05:00
Rob Winch 7074daac0e SEC-3063: rm ConditionalOnMissingBean for @Primary
ConditionalOnMissingBean can only work in a Spring Boot environment. This
means this approach is flawed.

Instead users that wish to override requestDataValueProcessor can use
@Primary.
2015-10-21 15:41:32 -05:00
Rob Winch 69446ab80f SEC-3070: Logout invalidate-session=false and Spring Session doesn't
work
2015-10-20 15:13:01 -05:00
izeye 48bc0ad5f9 SEC-3124: Fix broken Javadoc related to < and > 2015-10-13 13:33:51 -05:00
Rob Winch db9584104c Add Gitter to README 2015-08-11 11:49:46 -05:00
Rob Winch b0701ea770 SEC-3068: Update Tutorial to use POST /logout 2015-08-10 09:53:07 -05:00
Rob Winch 8cc9108601 Merge pull request #209 from raindev/patch-1
Remove unused imports from SecureRandomBytesKeyGenerator
2015-08-06 08:54:09 -05:00
Rob Winch 41c9431fcc Test that form log in requires CSRF 2015-08-03 12:24:37 -05:00
Rob Winch 453e6332da Fix indentation of CsrfConfigTests 2015-08-03 12:03:05 -05:00
Rob Winch 969f3a7d1b Update pom.xml to latest snapshots 2015-08-03 09:46:01 -05:00
Rob Winch 4c19768e54 Update to jacoco 0.7.5.201505241946 2015-08-03 09:45:42 -05:00
Thomas Darimont ad1d858e2b SEC-3056 - Fix JavaDoc errors.
Fixed JavaDoc errors accross multiple modules in order to make javadoc happy with Java 8.
2015-08-03 08:02:24 -05:00
Rob Winch 7317c090cc SEC-2963: Disable appengineRun if contains functional tests 2015-07-29 09:57:57 -05:00
Rob Winch 485fbdc1ee SEC-2963: Select Available Port for appengine 2015-07-28 22:47:21 -05:00
Spring Buildmaster 22aa91c8e1 Next development version 2015-07-22 22:08:15 -07:00
Rob Winch ea873fb1b8 SEC-2963: Disable appengineFunctionalTest 2015-07-22 21:27:28 -05:00
Rob Winch 117f892c91 SEC-3031: DelegatingSecurityContext(Runnable|Callable) only modify SecurityContext on new Thread
Modifying the SecurityContext on the same Thread can cause issues. For example, with a
RejectedExecutionHandler the SecurityContext may be cleared out on the original Thread.

This change modifies both the DelegatingSecurityContextRunnable and DelegatingSecurityContextCallable to,
by default, only modify the SecurityContext if they are invoked on a new Thread. The behavior can be changed
by setting the property enableOnOrigionalThread to true.
2015-07-22 16:07:21 -05:00
Rob Winch 113b61e3a0 SEC-2957: Polish 2015-07-22 13:57:28 -05:00
Rob Winch dab4cf18b8 SEC-3032: Correct documented logout-success-url default 2015-07-22 13:48:07 -05:00
Rob Winch be27ede0e9 SEC-2957: Add missing provided dependencies to samples 2015-07-22 13:33:52 -05:00
Rob Winch e8c9f75f9c Update pom.xml to latest versions 2015-07-22 12:51:04 -05:00
Rob Winch bc53945d89 Remove unused import in WithSecurityContextTestExecutionListenerTests 2015-07-22 12:44:34 -05:00
Rob Winch 432123daa2 SEC-2964: Fix CsrfTokenArgumentResolver Javadoc 2015-07-22 11:32:36 -05:00
Rob Winch 92ae45a04d SEC-3051: Add AbstractPreAuthenticatedProcessingFilter#principalChanged 2015-07-22 08:41:33 -05:00
Rob Winch a50d297f3a SEC-2953: Add index-docinfo.xml
This removes the "please define title in your docbook file"
2015-07-21 11:48:44 -05:00
Rob Winch 54dabb6433 SEC-2993: OpenID Sample now uses me.yahoo.com 2015-07-21 10:44:54 -05:00
Rob Winch cd4a7e95cc SEC-2991: Add CSRF Token to OpenID XML Sample 2015-07-21 10:42:24 -05:00
Rob Winch 07fb2af74b SEC-3011: AbstractUrlAuthorizationConfigurer postProcess default AccessDecisionManager 2015-07-21 08:52:36 -05:00
Rob Winch ab1b7a1eb6 Remove unnecessary @SuppressWarnings 2015-07-21 08:51:32 -05:00
Rob Winch 7c725a60e2 SEC-3047: SecurityContextHolderAwareRequestFactory update RequestFactory 2015-07-20 14:06:44 -05:00
Rob Winch 9b92d5a1e7 SEC-2963: Fix tests 2015-07-20 12:53:21 -05:00
Rob Winch e25b84c902 SEC-2963: Update to latest Google AppEngine 2015-07-20 12:36:29 -05:00
Rob Winch 9654df2cc3 SEC-3045: Conditionally add MethodSecurityMetadataSourceAdvisor 2015-07-17 15:16:09 -05:00
Rob Winch a3df41b380 Clean Import Statements 2015-07-17 14:52:23 -05:00
Rob Winch abc445d5a7 SEC-2965: Polish 2015-07-16 15:52:00 -05:00
Rob Winch 518a1c3c08 SEC-2965: Fix invalid formatted links in reference documentation 2015-07-16 15:27:04 -05:00
Rob Winch 1ca5946d74 SEC-3003: Document invalid intercept-url attributes for filter-security-metadata-source 2015-07-16 15:03:51 -05:00
Rob Winch 76a2fb9488 SEC-3020: SecurityContextHolderAwareRequestWrapper conditional rolePrefix
Previously SecurityContextHolderAwareRequestWrapper always prefixed with
rolePrefix. This meant the defaults would never return true for a role
that started with the prefix (i.e. ROLE_).

We no longer apply the rolePrefix if the value passed in already starts
with rolePrefix.
2015-07-16 14:49:32 -05:00
Rob Winch 2d448658cd SEC-3042: Add SecurityTestExecutionListeners 2015-07-16 13:51:37 -05:00
Rob Winch 4cafd575c0 SEC-3041: Fix WithSecurityContextTestExecutionListener w/ no ApplicationContext 2015-07-16 13:13:46 -05:00
Rob Winch 0e36f85dab SEC-3019: Java Config for Http Basic supports Rememberme 2015-07-16 11:12:44 -05:00
Rob Winch b96cee7950 SEC-2984: WithMockUser authorities doc 2015-07-16 08:48:53 -05:00
Rob Winch e4517016ca SEC-2984: Add @WithMockUser authorities property 2015-07-16 08:41:40 -05:00
Rob Winch 08b1b56e2c SEC-2973: Add OnCommittedResponseWrapper
This ensures that Spring Session & Security's logic for performing
a save on the response being committed can easily be kept in synch.
Further this ensures that the SecurityContext is now persisted when
the response body meets the content length.
2015-07-14 14:48:41 -05:00
Rob Winch 316886affc SEC-2931: Fix CsrfFilter Javadoc 2015-07-14 13:40:59 -05:00
Rob Winch 75f57b96cb SEC-2493: Fix javadoc for DefaultLdapAuthoritiesPopulator 2015-07-14 13:20:05 -05:00
Andrew Barchuk 3832647ecf Remove unused imports 2015-07-14 16:35:11 +03:00
Rob Winch aad4e70374 SEC-3034: AclPermissionEvaluator specifies Locale.ENGLISH 2015-07-13 23:54:32 -05:00
Rob Winch 821333434d SEC-3013: Add messages_en.properties 2015-07-13 23:18:45 -05:00
Rob Winch 474d624e8e SEC-2988: Renamed OnBeanCondition.java to OnMissingBeanCondition.java 2015-07-13 22:51:45 -05:00
Rob Winch 64938ebcfc SEC-2996: Suport configuring SecurityExpressionHandler<Message<Object>> 2015-07-13 22:45:35 -05:00
Rob Winch 3db01bd9d6 SEC-3002: Add JUnit Assume to GCM encryption tests
Not all JDKs have GCM installed on them.
2015-07-13 16:22:18 -05:00
Andy Wilkinson 92c23fbbdc Upgrade to a version of Powermock that’s compatible with JUnit 4.12 2015-07-13 15:42:50 -05:00
Dave Syer a48cc18858 SEC-3002: Add new option for AES encryption with GCM
The Galois Counter Mode (GCM) is held to be superior than the current
default CBC. This change adds an extra parameter to the constructor
of AesBytesEncryptor and a new convenience method in Encryptors.
2015-07-09 23:27:33 -05:00
Stijn ca0ffb8b5d SEC-2948: Fix error message for wrong xsd schema
When using the wrong xsd schema < 4.0 a message was shown that the
schema needed to be version 3.2.

In reality this schema had to be version 4.0.
2015-07-09 23:17:16 -05:00
Rob Winch aed288da05 Fix Spring IO Tests 2015-07-08 11:48:43 -05:00
Rob Winch 1f74ac811e Fix Spring IO Tests 2015-07-08 11:09:29 -05:00
Andy Wilkinson 350b48e3fd Use the latest version of the Spring IO Plugin
Spring IO Platform 2.0 will remove the managed versions .properties
file as support for it has been removed in Spring Boot 1.3.

This commit moves the build onto a new version of the Spring IO Plugin
that uses the Maven bom rather than the properties file.
2015-07-08 08:42:07 -05:00
Rob Winch 197ddb3cd1 SEC-3029: Fix Compatibility with Spring 4.2.x 2015-07-07 22:46:31 -05:00
Rob Winch 848523e47a SEC-3029: Add springSnapshotTests
Test against Spring Framework's latest Snapshots
2015-07-07 22:43:06 -05:00
Rob Winch 7b4a37f27e SEC-2967w: Update to Gradle 2.4 2015-05-07 10:16:07 -05:00
Rob Winch 7b158d0525 SEC-2966: Fix preauth-xml sample config attributes 2015-05-07 10:10:20 -05:00
Alex Panchenko 0a118336d4 SEC-2955: Convert to "static" for inner classes 2015-04-30 12:54:52 -05:00
kris 1a716d0593 SEC-2954: Update ActiveDirectoryLdapAuthenticationProvider javadoc
Cleaning up docs to match
https://github.com/spring-projects/spring-security/commit/cd352f665bce2bbf8963f6bd4cc40cb6d145291d#diff-c7d6415af2848047b4b7bde824f66fcb
2015-04-30 11:54:18 -05:00
Rob Winch a67ef1c3a2 SEC-2944: Polish 2015-04-30 10:00:04 -05:00
Gunnar Hillert 3099f92154 SEC-2944 Add HttpStatusReturningLogoutSuccessHandler
* Add HttpStatusReturningLogoutSuccessHandler to provide better logout capabilities for RESTful APIs
2015-04-30 09:56:02 -05:00
Rob Winch a46ad0f446 SEC-2951: Polish 2015-04-30 09:52:52 -05:00
Gunnar Hillert 013177c644 SEC-2951: Document Logouthandler and LogoutSuccesshandler
Jira: https://jira.spring.io/browse/SEC-2951
2015-04-30 09:37:17 -05:00
Rob Winch 600927def6 SEC-2952: Document Spring Security leveraging WebMvcConfigurerAdapter 2015-04-29 10:18:02 -05:00
Rob Winch f1352ba492 SEC-2942: Add test EnableWebSecurity supports AuthenticationPrincipal 2015-04-23 16:34:04 -05:00
Spring Buildmaster 81055feb82 Next development version 2015-04-22 18:04:28 -07:00
Rob Winch f548d89b27 SEC-2932: SecurityContextConfigurer defaults SecurityContextRepository 2015-04-22 16:50:51 -05:00
Rob Winch 1bca645add SEC-2935: Multiple MockMvc invocations proper SecurityContext setup
Previously if a MockMvc instance was setup with a user and then again with
no user, then the original user would be setup.

This commit ensures that if a user is setup and then no user is setup no
user is used.
2015-04-22 16:12:18 -05:00
Rob Winch e08e9cda00 SEC-2851: Remove DataAccessException import from Persistent RememberMe 2015-04-21 14:57:32 -05:00
Rob Winch 09acc2b7a5 SEC-2962: SecurityContextHolderAwareRequestFilter default rolePrefix 2015-04-21 11:42:48 -05:00
Rob Winch 38e2e23b86 Fix indentation of InterceptUrlConfigTests 2015-04-21 09:38:17 -05:00
Rob Winch b433cdda7e SEC-2930: Update SecurityExpressionOperations javadoc 2015-04-21 09:21:29 -05:00
Rob Winch 7000652fd1 SEC-2927: No Dependency Management for Bom 2015-04-20 17:06:01 -05:00
Rob Winch a1ff94a34e SEC-2922: Specify Version in Manifest 2015-04-20 16:39:53 -05:00
Rob Winch 1087d19346 SEC-2933: Update ProviderManager reference XML to use constructor 2015-04-20 15:57:04 -05:00
Rob Winch d5dfeeca49 SEC-2927: Update chat-jc pom so Maven Builds
Previously there were some incorrect dependency versions. This commit fixes
that.

We added dependencyManagement for Spring Framework and corrected
Thymeleaf and embedded redis versions.
2015-04-20 15:53:26 -05:00
Rob Winch 67762321f8 SEC-2920: Fix tickets resolved link in reference 2015-04-20 15:14:40 -05:00
Rob Winch 0bfbd2923a SEC-2915: Fix defaut login page tests with tabs 2015-04-17 12:13:44 -05:00
Rob Winch 4fdfb8caba SEC-2915: More Tabs -> Spaces 2015-04-17 11:34:34 -05:00
Rob Winch 5fa5630bc3 Polish ordering of Config and test in NamespaceRememberMeTests
The convention is to put the config just below the test.

This commit fixes the convention for NamespaceRememberMeTests
2015-04-17 11:20:39 -05:00
Kazuki Shimizu 0c77c2071b SEC-2880: Add a setter method to override the cookie name of remember-me 2015-04-17 11:14:58 -05:00
Rob Winch ec89fdcfaa SEC-2919: Polish
Remove now unnecessary AuthenticationConfig.Builder#getLoginFormUrl
method.
2015-04-17 11:12:08 -05:00
Rob Winch 052bd32f40 SEC-2919: DefaultLoginPageGeneratingFilter disabled when login-page specified 2015-04-17 11:12:08 -05:00
Rob Winch 5689383ab1 Update Docbook Reference Plugin 2015-04-17 11:12:08 -05:00
Spring Buildmaster e85e0de877 Next development version 2015-03-25 20:36:51 -07:00
408 changed files with 16111 additions and 12150 deletions
+2
View File
@@ -1,3 +1,5 @@
image::https://badges.gitter.im/Join%20Chat.svg[Gitter,link=https://gitter.im/spring-projects/spring-security?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge]
= Spring Security
Spring Security provides security services for the http://docs.spring.io[Spring IO Platform]. Spring Security 3.1 requires Spring 3.0.3 as
+14 -17
View File
@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-acl</artifactId>
<version>4.0.0.CI-SNAPSHOT</version>
<version>4.0.3.RELEASE</version>
<name>spring-security-acl</name>
<description>spring-security-acl</description>
<url>http://spring.io/spring-security</url>
@@ -30,12 +30,6 @@
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>https://repo.spring.io/snapshot</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>aopalliance</groupId>
@@ -46,25 +40,22 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>4.0.0.CI-SNAPSHOT</version>
<version>4.0.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -76,13 +67,11 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -126,7 +115,7 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.5</version>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -138,22 +127,30 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.1.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.1.6.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>4.2.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
@@ -83,14 +83,14 @@ import org.springframework.util.StringUtils;
* Alternatively, you could have used a common superclass or interface for the
* {@link #processDomainObjectClass} if both <code>BankAccount</code> and
* <code>Customer</code> had common parents.
* </p>
*
* <p>
* If the principal does not have sufficient permissions, the voter will vote to deny
* access.
* </p>
*
* <p>
* All comparisons and prefixes are case sensitive.
* </p>
*
*
* @author Ben Alex
*/
@@ -3,6 +3,7 @@ package org.springframework.security.acls;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -131,7 +132,7 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
p = permissionFactory.buildFromName(permString);
}
catch (IllegalArgumentException notfound) {
p = permissionFactory.buildFromName(permString.toUpperCase());
p = permissionFactory.buildFromName(permString.toUpperCase(Locale.ENGLISH));
}
if (p != null) {
@@ -660,7 +660,7 @@ public class BasicLookupStrategy implements LookupStrategy {
}
}
private class StubAclParent implements Acl {
private static class StubAclParent implements Acl {
private final Long id;
public StubAclParent(Long id) {
@@ -192,7 +192,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
jdbcTemplate.update(insertClass, type);
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
"Transaction must be running");
return new Long(jdbcTemplate.queryForLong(classIdentityQuery));
return jdbcTemplate.queryForObject(classIdentityQuery, Long.class);
}
return null;
@@ -252,7 +252,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
jdbcTemplate.update(insertSid, Boolean.valueOf(sidIsPrincipal), sidName);
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
"Transaction must be running");
return new Long(jdbcTemplate.queryForLong(sidIdentityQuery));
return jdbcTemplate.queryForObject(sidIdentityQuery, Long.class);
}
return null;
@@ -332,8 +332,8 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
*/
protected Long retrieveObjectIdentityPrimaryKey(ObjectIdentity oid) {
try {
return new Long(jdbcTemplate.queryForLong(selectObjectIdentityPrimaryKey,
oid.getType(), oid.getIdentifier()));
return jdbcTemplate.queryForObject(selectObjectIdentityPrimaryKey, Long.class,
oid.getType(), oid.getIdentifier());
}
catch (DataAccessException notFound) {
return null;
@@ -4,6 +4,8 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import java.util.Locale;
import org.junit.Test;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.AclService;
@@ -36,4 +38,26 @@ public class AclPermissionEvaluatorTests {
assertTrue(pe.hasPermission(mock(Authentication.class), new Object(), "READ"));
}
@Test
public void resolvePermissionNonEnglishLocale() {
Locale systemLocale = Locale.getDefault();
Locale.setDefault(new Locale("tr"));
AclService service = mock(AclService.class);
AclPermissionEvaluator pe = new AclPermissionEvaluator(service);
ObjectIdentity oid = mock(ObjectIdentity.class);
ObjectIdentityRetrievalStrategy oidStrategy = mock(ObjectIdentityRetrievalStrategy.class);
when(oidStrategy.getObjectIdentity(anyObject())).thenReturn(oid);
pe.setObjectIdentityRetrievalStrategy(oidStrategy);
pe.setSidRetrievalStrategy(mock(SidRetrievalStrategy.class));
Acl acl = mock(Acl.class);
when(service.readAclById(any(ObjectIdentity.class), anyList())).thenReturn(acl);
when(acl.isGranted(anyList(), anyList(), eq(false))).thenReturn(true);
assertTrue(pe.hasPermission(mock(Authentication.class), new Object(), "write"));
Locale.setDefault(systemLocale);
}
}
@@ -9,94 +9,94 @@
-->
<beans>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="aclCache" class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
<constructor-arg>
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
</property>
<property name="cacheName" value="aclCache"/>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy">
<constructor-arg>
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
</constructor-arg>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_USER"/>
</bean>
</list>
</constructor-arg>
</bean>
</constructor-arg>
<bean id="aclCache" class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
<constructor-arg>
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
</property>
<property name="cacheName" value="aclCache"/>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy">
<constructor-arg>
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
</constructor-arg>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_USER"/>
</bean>
</list>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
</bean>
<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
<constructor-arg ref="dataSource"/>
<constructor-arg ref="aclCache"/>
<constructor-arg ref="aclAuthorizationStrategy"/>
<constructor-arg>
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
</constructor-arg>
</bean>
<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
<constructor-arg ref="dataSource"/>
<constructor-arg ref="aclCache"/>
<constructor-arg ref="aclAuthorizationStrategy"/>
<constructor-arg>
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
</constructor-arg>
</bean>
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ADMINISTRATOR"/>
</bean>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ADMINISTRATOR"/>
</bean>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ADMINISTRATOR"/>
</bean>
</list>
</constructor-arg>
</bean>
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ADMINISTRATOR"/>
</bean>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ADMINISTRATOR"/>
</bean>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ADMINISTRATOR"/>
</bean>
</list>
</constructor-arg>
</bean>
<bean id="aclService" class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
<constructor-arg ref="dataSource"/>
<constructor-arg ref="lookupStrategy"/>
<constructor-arg ref="aclCache"/>
<bean id="aclService" class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
<constructor-arg ref="dataSource"/>
<constructor-arg ref="lookupStrategy"/>
<constructor-arg ref="aclCache"/>
<!-- Uncomment to use PostgreSQL
<property name="classIdentityQuery" value="select currval(pg_get_serial_sequence('acl_class', 'id'))"/>
<property name="sidIdentityQuery" value="select currval(pg_get_serial_sequence('acl_sid', 'id'))"/>
<property name="classIdentityQuery" value="select currval(pg_get_serial_sequence('acl_class', 'id'))"/>
<property name="sidIdentityQuery" value="select currval(pg_get_serial_sequence('acl_sid', 'id'))"/>
-->
</bean>
</bean>
<!-- PostgreSQL DataSource configuration
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver"/>
<property name="url" value="jdbc:postgresql://localhost:5432/acltest"/>
<property name="username" value="acltest"/>
<property name="password" value="acltest"/>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver"/>
<property name="url" value="jdbc:postgresql://localhost:5432/acltest"/>
<property name="username" value="acltest"/>
<property name="password" value="acltest"/>
</bean>
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:acltest"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:acltest"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
+14 -14
View File
@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-aspects</artifactId>
<version>4.0.0.CI-SNAPSHOT</version>
<version>4.0.3.RELEASE</version>
<name>spring-security-aspects</name>
<description>spring-security-aspects</description>
<url>http://spring.io/spring-security</url>
@@ -30,35 +30,26 @@
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>https://repo.spring.io/snapshot</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>4.0.0.CI-SNAPSHOT</version>
<version>4.0.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -108,7 +99,7 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.5</version>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -120,16 +111,25 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.1.6.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>4.2.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
+19 -8
View File
@@ -6,11 +6,11 @@ buildscript {
}
dependencies {
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.7")
classpath("org.springframework.build.gradle:spring-io-plugin:0.0.3.RELEASE")
classpath("io.spring.gradle:spring-io-plugin:0.0.4.RELEASE")
classpath("org.gradle.api.plugins:gradle-tomcat-plugin:1.2.5")
classpath('me.champeau.gradle:gradle-javadoc-hotfix-plugin:0.1')
classpath('org.asciidoctor:asciidoctor-gradle-plugin:1.5.1')
classpath("io.spring.gradle:docbook-reference-plugin:0.3.0")
classpath("io.spring.gradle:docbook-reference-plugin:0.3.1")
}
}
@@ -25,7 +25,7 @@ allprojects {
ext.releaseBuild = version.endsWith('RELEASE')
ext.snapshotBuild = version.endsWith('SNAPSHOT')
ext.springVersion = '4.1.6.RELEASE'
ext.springVersion = '4.2.2.RELEASE'
ext.springLdapVersion = '2.0.2.RELEASE'
group = 'org.springframework.security'
@@ -105,9 +105,15 @@ configure(coreModuleProjects) {
jacoco //Configuration Group used by Sonar to provide Code Coverage using JaCoCo
}
dependencyManagement {
springIoTestRuntime {
imports {
mavenBom "io.spring.platform:platform-bom:${springIoVersion}"
}
}
}
dependencies {
springIoVersions "io.spring.platform:platform-versions:${springIoVersion}@properties"
jacoco "org.jacoco:org.jacoco.agent:0.6.2.201302030002:runtime"
jacoco "org.jacoco:org.jacoco.agent:0.7.5.201505241946:runtime"
}
test {
jvmArgs "-javaagent:${configurations.jacoco.asPath}=destfile=${buildDir}/jacoco.exec,includes=${project.group}.*"
@@ -129,7 +135,7 @@ task coreBuild {
// Task for creating the distro zip
task dist(type: Zip) {
dependsOn subprojects*.tasks*.matching { task -> task.name == 'assemble' || task.name.endsWith('Zip') || task.name.endsWith('generatePom') }
dependsOn { subprojects*.tasks*.matching { task -> task.name.endsWith('generatePom') } }
classifier = 'dist'
evaluationDependsOn(':docs')
@@ -139,14 +145,19 @@ task dist(type: Zip) {
into(zipRootDir) {
from(rootDir) {
include '*.adoc'
include '*.txt'
}
into('docs') {
with(project(':docs').apiSpec)
with(project(':docs:manual').spec)
with(project(':docs:guides').spec)
}
into('dist') {
from coreModuleProjects.collect {project -> project.libsDir }
project.coreModuleProjects*.tasks*.withType(AbstractArchiveTask).flatten().each{ archiveTask ->
if(archiveTask!=dist){
into("$zipRootDir/dist") {
from archiveTask.outputs.files
}
}
}
sampleProjects.each { project->
into("$zipRootDir/samples/$project.name") {
@@ -1,26 +0,0 @@
package gae;
import com.google.appengine.tools.admin.AppCfg
import org.gradle.api.*;
class GaePlugin implements Plugin<Project> {
public void apply(Project project) {
if (!project.hasProperty('appEngineSdkRoot')) {
println "'appEngineSdkRoot' must be set in gradle.properties"
} else {
System.setProperty('appengine.sdk.root', project.property('appEngineSdkRoot'))
}
File explodedWar = new File(project.buildDir, "gae-exploded")
project.task('gaeDeploy') << {
AppCfg.main("update", explodedWar.toString())
}
project.gaeDeploy.dependsOn project.war
project.war.doLast {
ant.unzip(src: project.war.archivePath, dest: explodedWar)
}
}
}
@@ -1 +0,0 @@
implementation-class=gae.GaePlugin
+15 -15
View File
@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
<version>4.0.0.CI-SNAPSHOT</version>
<version>4.0.3.RELEASE</version>
<name>spring-security-cas</name>
<description>spring-security-cas</description>
<url>http://spring.io/spring-security</url>
@@ -30,12 +30,6 @@
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>https://repo.spring.io/snapshot</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.jasig.cas.client</groupId>
@@ -46,31 +40,28 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>4.0.0.CI-SNAPSHOT</version>
<version>4.0.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.0.0.CI-SNAPSHOT</version>
<version>4.0.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -82,7 +73,6 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -126,7 +116,7 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.5</version>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -138,10 +128,20 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.1.6.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>4.2.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
@@ -1,23 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://example.com/j_spring_security_cas"/>
<property name="sendRenew" value="false"/>
</bean>
<bean id="serviceProperties2"
class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://example2.com/j_spring_security_cas"/>
<property name="sendRenew" value="false"/>
</bean>
<bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://example.com/j_spring_security_cas"/>
<property name="sendRenew" value="false"/>
</bean>
<bean id="serviceProperties2"
class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://example2.com/j_spring_security_cas"/>
<property name="sendRenew" value="false"/>
</bean>
<bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource">
<constructor-arg ref="serviceProperties"/>
</bean>
<bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource">
<constructor-arg ref="serviceProperties"/>
</bean>
</beans>
@@ -1,15 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://example.com/j_spring_security_cas"/>
<property name="sendRenew" value="false"/>
</bean>
<bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://example.com/j_spring_security_cas"/>
<property name="sendRenew" value="false"/>
</bean>
<bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource"/>
<bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource"/>
</beans>
+26 -33
View File
@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.0.0.CI-SNAPSHOT</version>
<version>4.0.3.RELEASE</version>
<name>spring-security-config</name>
<description>spring-security-config</description>
<url>http://spring.io/spring-security</url>
@@ -30,12 +30,6 @@
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
<url>https://github.com/spring-projects/spring-security</url>
</scm>
<repositories>
<repository>
<id>spring-snasphot</id>
<url>https://repo.spring.io/snapshot</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>aopalliance</groupId>
@@ -46,31 +40,27 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>4.0.0.CI-SNAPSHOT</version>
<version>4.0.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
<exclusions>
<exclusion>
@@ -96,63 +86,58 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
<version>4.0.0.CI-SNAPSHOT</version>
<version>4.0.3.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-messaging</artifactId>
<version>4.0.0.CI-SNAPSHOT</version>
<version>4.0.3.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-openid</artifactId>
<version>4.0.0.CI-SNAPSHOT</version>
<version>4.0.3.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.0.0.CI-SNAPSHOT</version>
<version>4.0.3.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>4.1.6.RELEASE</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
@@ -267,7 +252,7 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.5</version>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -285,7 +270,7 @@
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.6.0</version>
<version>1.6.2</version>
<scope>test</scope>
<exclusions>
<exclusion>
@@ -297,31 +282,31 @@
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-support</artifactId>
<version>1.6.0</version>
<version>1.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>1.6.0</version>
<version>1.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.6.0</version>
<version>1.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4-common</artifactId>
<version>1.6.0</version>
<version>1.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-reflect</artifactId>
<version>1.6.0</version>
<version>1.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -375,34 +360,42 @@
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-aspects</artifactId>
<version>4.0.0.CI-SNAPSHOT</version>
<version>4.0.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
<version>4.0.0.CI-SNAPSHOT</version>
<version>4.0.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.1.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.1.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.1.6.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>4.2.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
@@ -47,174 +47,174 @@ import org.springframework.test.util.ReflectionTestUtils;
*
*/
class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSpec {
def "default configuration"() {
when:
loadConfig(DefaultLdapConfig)
LdapAuthenticationProvider provider = ldapProvider()
then:
provider.authoritiesPopulator.groupRoleAttribute == "cn"
provider.authoritiesPopulator.groupSearchBase == ""
provider.authoritiesPopulator.groupSearchFilter == "(uniqueMember={0})"
ReflectionTestUtils.getField(provider,"authoritiesMapper").prefix == "ROLE_"
def "default configuration"() {
when:
loadConfig(DefaultLdapConfig)
LdapAuthenticationProvider provider = ldapProvider()
then:
provider.authoritiesPopulator.groupRoleAttribute == "cn"
provider.authoritiesPopulator.groupSearchBase == ""
provider.authoritiesPopulator.groupSearchFilter == "(uniqueMember={0})"
ReflectionTestUtils.getField(provider,"authoritiesMapper").prefix == "ROLE_"
}
}
@Configuration
static class DefaultLdapConfig extends BaseLdapProviderConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
}
}
@Configuration
static class DefaultLdapConfig extends BaseLdapProviderConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
}
}
def "group roles custom"() {
when:
loadConfig(GroupRolesConfig)
LdapAuthenticationProvider provider = ldapProvider()
then:
provider.authoritiesPopulator.groupRoleAttribute == "group"
}
def "group roles custom"() {
when:
loadConfig(GroupRolesConfig)
LdapAuthenticationProvider provider = ldapProvider()
then:
provider.authoritiesPopulator.groupRoleAttribute == "group"
}
@Configuration
static class GroupRolesConfig extends BaseLdapProviderConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
.groupRoleAttribute("group")
}
}
@Configuration
static class GroupRolesConfig extends BaseLdapProviderConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
.groupRoleAttribute("group")
}
}
def "group search custom"() {
when:
loadConfig(GroupSearchConfig)
LdapAuthenticationProvider provider = ldapProvider()
then:
provider.authoritiesPopulator.groupSearchFilter == "ou=groupName"
}
def "group search custom"() {
when:
loadConfig(GroupSearchConfig)
LdapAuthenticationProvider provider = ldapProvider()
then:
provider.authoritiesPopulator.groupSearchFilter == "ou=groupName"
}
@Configuration
static class GroupSearchConfig extends BaseLdapProviderConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
.groupSearchFilter("ou=groupName");
}
}
@Configuration
static class GroupSearchConfig extends BaseLdapProviderConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
.groupSearchFilter("ou=groupName");
}
}
def "role prefix custom"() {
when:
loadConfig(RolePrefixConfig)
LdapAuthenticationProvider provider = ldapProvider()
then:
ReflectionTestUtils.getField(provider,"authoritiesMapper").prefix == "role_"
}
def "role prefix custom"() {
when:
loadConfig(RolePrefixConfig)
LdapAuthenticationProvider provider = ldapProvider()
then:
ReflectionTestUtils.getField(provider,"authoritiesMapper").prefix == "role_"
}
@Configuration
static class RolePrefixConfig extends BaseLdapProviderConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
.rolePrefix("role_")
}
}
@Configuration
static class RolePrefixConfig extends BaseLdapProviderConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.userDnPatterns("uid={0},ou=people")
.rolePrefix("role_")
}
}
def "bind authentication"() {
when:
loadConfig(BindAuthenticationConfig)
AuthenticationManager auth = context.getBean(AuthenticationManager)
then:
auth
auth.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword")).authorities.collect { it.authority }.sort() == ["ROLE_DEVELOPERS"]
}
def "bind authentication"() {
when:
loadConfig(BindAuthenticationConfig)
AuthenticationManager auth = context.getBean(AuthenticationManager)
then:
auth
auth.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword")).authorities.collect { it.authority }.sort() == ["ROLE_DEVELOPERS"]
}
@Configuration
static class BindAuthenticationConfig extends BaseLdapServerConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.groupSearchBase("ou=groups")
.groupSearchFilter("(member={0})")
.userDnPatterns("uid={0},ou=people");
}
}
@Configuration
static class BindAuthenticationConfig extends BaseLdapServerConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.groupSearchBase("ou=groups")
.groupSearchFilter("(member={0})")
.userDnPatterns("uid={0},ou=people");
}
}
def "SEC-2472: Can use crypto PasswordEncoder"() {
setup:
loadConfig(PasswordEncoderConfig)
when:
AuthenticationManager auth = context.getBean(AuthenticationManager)
then:
auth.authenticate(new UsernamePasswordAuthenticationToken("bcrypt","password")).authorities.collect { it.authority }.sort() == ["ROLE_DEVELOPERS"]
}
def "SEC-2472: Can use crypto PasswordEncoder"() {
setup:
loadConfig(PasswordEncoderConfig)
when:
AuthenticationManager auth = context.getBean(AuthenticationManager)
then:
auth.authenticate(new UsernamePasswordAuthenticationToken("bcrypt","password")).authorities.collect { it.authority }.sort() == ["ROLE_DEVELOPERS"]
}
@Configuration
static class PasswordEncoderConfig extends BaseLdapServerConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.passwordEncoder(new BCryptPasswordEncoder())
.groupSearchBase("ou=groups")
.groupSearchFilter("(member={0})")
.userDnPatterns("uid={0},ou=people");
}
}
@Configuration
static class PasswordEncoderConfig extends BaseLdapServerConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.contextSource(contextSource())
.passwordEncoder(new BCryptPasswordEncoder())
.groupSearchBase("ou=groups")
.groupSearchFilter("(member={0})")
.userDnPatterns("uid={0},ou=people");
}
}
def ldapProvider() {
context.getBean(AuthenticationManager).providers[0]
}
def ldapProvider() {
context.getBean(AuthenticationManager).providers[0]
}
@Configuration
static abstract class BaseLdapServerConfig extends BaseLdapProviderConfig {
@Bean
public ApacheDSContainer ldapServer() throws Exception {
ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
apacheDSContainer.setPort(getPort());
return apacheDSContainer;
}
}
@Configuration
static abstract class BaseLdapServerConfig extends BaseLdapProviderConfig {
@Bean
public ApacheDSContainer ldapServer() throws Exception {
ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
apacheDSContainer.setPort(getPort());
return apacheDSContainer;
}
}
@Configuration
@EnableGlobalAuthentication
@Import(ObjectPostProcessorConfiguration)
static abstract class BaseLdapProviderConfig {
@Configuration
@EnableGlobalAuthentication
@Import(ObjectPostProcessorConfiguration)
static abstract class BaseLdapProviderConfig {
@Bean
public BaseLdapPathContextSource contextSource() throws Exception {
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(
"ldap://127.0.0.1:"+ getPort() + "/dc=springframework,dc=org")
contextSource.userDn = "uid=admin,ou=system"
contextSource.password = "secret"
contextSource.afterPropertiesSet()
return contextSource;
}
@Bean
public BaseLdapPathContextSource contextSource() throws Exception {
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(
"ldap://127.0.0.1:"+ getPort() + "/dc=springframework,dc=org")
contextSource.userDn = "uid=admin,ou=system"
contextSource.password = "secret"
contextSource.afterPropertiesSet()
return contextSource;
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth) {
configure(auth)
auth.build()
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth) {
configure(auth)
auth.build()
}
abstract protected void configure(AuthenticationManagerBuilder auth) throws Exception
}
abstract protected void configure(AuthenticationManagerBuilder auth) throws Exception
}
static Integer port;
static Integer port;
static int getPort() {
if(port == null) {
ServerSocket socket = new ServerSocket(0)
port = socket.localPort
socket.close()
}
port
}
static int getPort() {
if(port == null) {
ServerSocket socket = new ServerSocket(0)
port = socket.localPort
socket.close()
}
port
}
}
@@ -37,24 +37,24 @@ import static org.springframework.security.config.annotation.authentication.ldap
*/
class LdapAuthenticationProviderConfigurerTests extends BaseSpringSpec {
def "authentication-manager support multiple default ldap contexts (ports dynamically allocated)"() {
when:
loadConfig(MultiLdapAuthenticationProvidersConfig)
then:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
}
def "authentication-manager support multiple default ldap contexts (ports dynamically allocated)"() {
when:
loadConfig(MultiLdapAuthenticationProvidersConfig)
then:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
}
@EnableWebSecurity
static class MultiLdapAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.groupSearchBase("ou=groups")
.userDnPatterns("uid={0},ou=people")
.and()
.ldapAuthentication()
.groupSearchBase("ou=groups")
.userDnPatterns("uid={0},ou=people")
}
}
@EnableWebSecurity
static class MultiLdapAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.groupSearchBase("ou=groups")
.userDnPatterns("uid={0},ou=people")
.and()
.ldapAuthentication()
.groupSearchBase("ou=groups")
.userDnPatterns("uid={0},ou=people")
}
}
}
@@ -36,45 +36,45 @@ import org.springframework.test.util.ReflectionTestUtils;
*
*/
class NamespaceLdapAuthenticationProviderTests extends BaseSpringSpec {
def "ldap-authentication-provider"() {
when:
loadConfig(LdapAuthenticationProviderConfig)
then:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
}
def "ldap-authentication-provider"() {
when:
loadConfig(LdapAuthenticationProviderConfig)
then:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
}
def "ldap-authentication-provider custom"() {
when:
loadConfig(CustomLdapAuthenticationProviderConfig)
LdapAuthenticationProvider provider = findAuthenticationProvider(LdapAuthenticationProvider)
then:
provider.authoritiesPopulator.groupRoleAttribute == "cn"
provider.authoritiesPopulator.groupSearchBase == "ou=groups"
provider.authoritiesPopulator.groupSearchFilter == "(member={0})"
ReflectionTestUtils.getField(provider,"authoritiesMapper").prefix == "PREFIX_"
provider.userDetailsContextMapper instanceof PersonContextMapper
provider.authenticator.getUserDns("user") == ["uid=user,ou=people"]
provider.authenticator.userSearch.searchBase == "ou=users"
provider.authenticator.userSearch.searchFilter == "(uid={0})"
}
def "ldap-authentication-provider custom"() {
when:
loadConfig(CustomLdapAuthenticationProviderConfig)
LdapAuthenticationProvider provider = findAuthenticationProvider(LdapAuthenticationProvider)
then:
provider.authoritiesPopulator.groupRoleAttribute == "cn"
provider.authoritiesPopulator.groupSearchBase == "ou=groups"
provider.authoritiesPopulator.groupSearchFilter == "(member={0})"
ReflectionTestUtils.getField(provider,"authoritiesMapper").prefix == "PREFIX_"
provider.userDetailsContextMapper instanceof PersonContextMapper
provider.authenticator.getUserDns("user") == ["uid=user,ou=people"]
provider.authenticator.userSearch.searchBase == "ou=users"
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 "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)
LdapAuthenticationProvider provider = findAuthenticationProvider(LdapAuthenticationProvider)
then:
provider.authenticator instanceof PasswordComparisonAuthenticator
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
}
def "ldap-authentication-provider password compare"() {
when:
loadConfig(PasswordCompareLdapConfig)
LdapAuthenticationProvider provider = findAuthenticationProvider(LdapAuthenticationProvider)
then:
provider.authenticator instanceof PasswordComparisonAuthenticator
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword"))
}
}
@@ -21,161 +21,161 @@ import org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper
*/
class LdapProviderBeanDefinitionParserTests extends AbstractXmlConfigTests {
// SEC-1182
def multipleProvidersAreSupported() {
xml.'ldap-server'(url: 'ldap://blah:389/dc=blah')
xml.'authentication-manager'() {
'ldap-authentication-provider'('group-search-filter': 'member={0}')
'ldap-authentication-provider'('group-search-filter': 'uniqueMember={0}')
}
// SEC-1182
def multipleProvidersAreSupported() {
xml.'ldap-server'(url: 'ldap://blah:389/dc=blah')
xml.'authentication-manager'() {
'ldap-authentication-provider'('group-search-filter': 'member={0}')
'ldap-authentication-provider'('group-search-filter': 'uniqueMember={0}')
}
createAppContext('')
createAppContext('')
def providers = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER).providers
def providers = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER).providers
expect:
expect:
providers.size() == 2
providers[0].authoritiesPopulator.groupSearchFilter == "member={0}"
providers[1].authoritiesPopulator.groupSearchFilter == "uniqueMember={0}"
}
providers.size() == 2
providers[0].authoritiesPopulator.groupSearchFilter == "member={0}"
providers[1].authoritiesPopulator.groupSearchFilter == "uniqueMember={0}"
}
def simpleProviderAuthenticatesCorrectly() {
xml.'ldap-server'(ldif:'test-server.ldif')
xml.'authentication-manager'{
'ldap-authentication-provider'('group-search-filter':'member={0}')
}
def simpleProviderAuthenticatesCorrectly() {
xml.'ldap-server'(ldif:'test-server.ldif')
xml.'authentication-manager'{
'ldap-authentication-provider'('group-search-filter':'member={0}')
}
createAppContext('')
createAppContext('')
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
when:
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"))
def ben = auth.principal;
when:
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"))
def ben = auth.principal;
then:
ben.authorities.size() == 3
}
then:
ben.authorities.size() == 3
}
def missingServerEltCausesConfigException() {
xml.'authentication-manager'{
'ldap-authentication-provider'()
}
def missingServerEltCausesConfigException() {
xml.'authentication-manager'{
'ldap-authentication-provider'()
}
when:
createAppContext('')
when:
createAppContext('')
then:
thrown(ApplicationContextException)
}
then:
thrown(ApplicationContextException)
}
def supportsPasswordComparisonAuthentication() {
xml.'ldap-server'(ldif:'test-server.ldif')
xml.'authentication-manager'{
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people')
'password-compare'
}
createAppContext('')
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
def supportsPasswordComparisonAuthentication() {
xml.'ldap-server'(ldif:'test-server.ldif')
xml.'authentication-manager'{
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people')
'password-compare'
}
createAppContext('')
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
when:
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"))
when:
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"))
then:
auth != null
notThrown(AuthenticationException)
}
then:
auth != null
notThrown(AuthenticationException)
}
def supportsPasswordComparisonAuthenticationWithHashAttribute() {
xml.'ldap-server'(ldif:'test-server.ldif')
xml.'authentication-manager'{
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
'password-compare'('password-attribute': 'uid', hash: 'plaintext')
}
}
createAppContext('')
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
def supportsPasswordComparisonAuthenticationWithHashAttribute() {
xml.'ldap-server'(ldif:'test-server.ldif')
xml.'authentication-manager'{
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
'password-compare'('password-attribute': 'uid', hash: 'plaintext')
}
}
createAppContext('')
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
when:
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"))
when:
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"))
then:
auth != null
notThrown(AuthenticationException)
then:
auth != null
notThrown(AuthenticationException)
}
}
def supportsPasswordComparisonAuthenticationWithPasswordEncoder() {
xml.'ldap-server'(ldif:'test-server.ldif')
xml.'authentication-manager'{
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
'password-compare'('password-attribute': 'uid') {
'password-encoder'(hash: 'plaintext')
}
}
}
def supportsPasswordComparisonAuthenticationWithPasswordEncoder() {
xml.'ldap-server'(ldif:'test-server.ldif')
xml.'authentication-manager'{
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
'password-compare'('password-attribute': 'uid') {
'password-encoder'(hash: 'plaintext')
}
}
}
createAppContext('')
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
createAppContext('')
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
when:
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"))
when:
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"))
then:
auth != null
notThrown(AuthenticationException)
}
then:
auth != null
notThrown(AuthenticationException)
}
def 'SEC-2472: Supports Crypto PasswordEncoder'() {
setup:
xml.'ldap-server'(ldif:'test-server.ldif')
xml.'authentication-manager'{
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
'password-compare'() {
'password-encoder'(ref: 'pe')
}
}
}
xml.'b:bean'(id:'pe','class':BCryptPasswordEncoder.class.name)
def 'SEC-2472: Supports Crypto PasswordEncoder'() {
setup:
xml.'ldap-server'(ldif:'test-server.ldif')
xml.'authentication-manager'{
'ldap-authentication-provider'('user-dn-pattern': 'uid={0},ou=people') {
'password-compare'() {
'password-encoder'(ref: 'pe')
}
}
}
xml.'b:bean'(id:'pe','class':BCryptPasswordEncoder.class.name)
createAppContext('')
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
createAppContext('')
def am = appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)
when:
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("bcrypt", 'password'))
when:
def auth = am.authenticate(new UsernamePasswordAuthenticationToken("bcrypt", 'password'))
then:
auth != null
}
then:
auth != null
}
def inetOrgContextMapperIsSupported() {
xml.'ldap-server'(url: 'ldap://127.0.0.1:343/dc=springframework,dc=org')
xml.'authentication-manager'{
'ldap-authentication-provider'('user-details-class' :'inetOrgPerson')
}
createAppContext('')
def inetOrgContextMapperIsSupported() {
xml.'ldap-server'(url: 'ldap://127.0.0.1:343/dc=springframework,dc=org')
xml.'authentication-manager'{
'ldap-authentication-provider'('user-details-class' :'inetOrgPerson')
}
createAppContext('')
expect:
appContext.getBean(BeanIds.AUTHENTICATION_MANAGER).providers[0].userDetailsContextMapper instanceof InetOrgPersonContextMapper
}
expect:
appContext.getBean(BeanIds.AUTHENTICATION_MANAGER).providers[0].userDetailsContextMapper instanceof InetOrgPersonContextMapper
}
def ldapAuthenticationProviderWorksWithPlaceholders() {
System.setProperty('udp','people')
System.setProperty('gsf','member')
def ldapAuthenticationProviderWorksWithPlaceholders() {
System.setProperty('udp','people')
System.setProperty('gsf','member')
xml.'ldap-server'()
xml.'authentication-manager'{
'ldap-authentication-provider'('user-dn-pattern':'uid={0},ou=${udp}','group-search-filter':'${gsf}={0}')
}
bean(PropertyPlaceholderConfigurer.class.name, PropertyPlaceholderConfigurer.class)
xml.'ldap-server'()
xml.'authentication-manager'{
'ldap-authentication-provider'('user-dn-pattern':'uid={0},ou=${udp}','group-search-filter':'${gsf}={0}')
}
bean(PropertyPlaceholderConfigurer.class.name, PropertyPlaceholderConfigurer.class)
createAppContext('')
def provider = this.appContext.getBean(BeanIds.AUTHENTICATION_MANAGER).providers[0]
createAppContext('')
def provider = this.appContext.getBean(BeanIds.AUTHENTICATION_MANAGER).providers[0]
expect:
[new MessageFormat("uid={0},ou=people")] == FieldUtils.getFieldValue(provider,"authenticator.userDnFormat")
"member={0}" == FieldUtils.getFieldValue(provider, "authoritiesPopulator.groupSearchFilter")
}
expect:
[new MessageFormat("uid={0},ou=people")] == FieldUtils.getFieldValue(provider,"authenticator.userDnFormat")
"member={0}" == FieldUtils.getFieldValue(provider, "authoritiesPopulator.groupSearchFilter")
}
}
@@ -85,8 +85,8 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
public BeanDefinition parse(Element element, ParserContext pc) {
if (!namespaceMatchesVersion(element)) {
pc.getReaderContext()
.fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd or spring-security-3.1.xsd schema "
+ "with Spring Security 3.2. Please update your schema declarations to the 3.2 schema.",
.fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd or spring-security-3.1.xsd schema or spring-security-3.2.xsd schema "
+ "with Spring Security 4.0. Please update your schema declarations to the 4.0 schema.",
element);
}
String name = pc.getDelegate().getLocalName(element);
@@ -55,6 +55,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
private final Log logger = LogFactory.getLog(getClass());
private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers = new LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>>();
private final List<SecurityConfigurer<O, B>> configurersAddedInInitializing = new ArrayList<SecurityConfigurer<O, B>>();
private final Map<Class<Object>, Object> sharedObjects = new HashMap<Class<Object>, Object>();
@@ -126,9 +127,9 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
@SuppressWarnings("unchecked")
public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer)
throws Exception {
add(configurer);
configurer.addObjectPostProcessor(objectPostProcessor);
configurer.setBuilder((B) this);
add(configurer);
return configurer;
}
@@ -202,7 +203,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
configs.add(configurer);
this.configurers.put(clazz, configs);
if (buildState.isInitializing()) {
configurer.init((B) this);
this.configurersAddedInInitializing.add(configurer);
}
}
}
@@ -368,6 +369,10 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.init((B) this);
}
for (SecurityConfigurer<O, B> configurer : configurersAddedInInitializing) {
configurer.init((B) this);
}
}
@SuppressWarnings("unchecked")
@@ -58,7 +58,7 @@ public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>
* Gets the {@link SecurityBuilder}. Cannot be null.
*
* @return the {@link SecurityBuilder}
* @throw {@link IllegalStateException} if {@link SecurityBuilder} is null
* @throws IllegalStateException if {@link SecurityBuilder} is null
*/
protected final B getBuilder() {
if (securityBuilder == null) {
@@ -36,9 +36,10 @@ public interface ProviderManagerBuilder<B extends ProviderManagerBuilder<B>> ext
* customizations must be done externally and the {@link ProviderManagerBuilder} is
* returned immediately.
*
* Note that an Exception is thrown if an error occurs when adding the {@link AuthenticationProvider}.
*
* @return a {@link ProviderManagerBuilder} to allow further authentication to be
* provided to the {@link ProviderManagerBuilder}
* @throws Exception if an error occurs when adding the {@link AuthenticationProvider}
*/
B authenticationProvider(AuthenticationProvider authenticationProvider);
}
@@ -61,7 +61,7 @@ public class AuthenticationManagerBuilder
/**
* Creates a new instance
* @param the {@link ObjectPostProcessor} instance to use.
* @param objectPostProcessor the {@link ObjectPostProcessor} instance to use.
*/
public AuthenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
super(objectPostProcessor, true);
@@ -196,7 +196,6 @@ public class AuthenticationManagerBuilder
* <p>
* This method <b>does NOT</b> ensure that a {@link UserDetailsService} is available
* for the {@link #getDefaultUserDetailsService()} method.
* </p>
*
* @return a {@link LdapAuthenticationProviderConfigurer} to allow customization of
* the LDAP authentication
@@ -216,11 +215,11 @@ public class AuthenticationManagerBuilder
* <p>
* This method <b>does NOT</b> ensure that the {@link UserDetailsService} is available
* for the {@link #getDefaultUserDetailsService()} method.
* </p>
*
* Note that an {@link Exception} might be thrown if an error occurs when adding the {@link AuthenticationProvider}.
*
* @return a {@link AuthenticationManagerBuilder} to allow further authentication to
* be provided to the {@link AuthenticationManagerBuilder}
* @throws Exception if an error occurs when adding the {@link AuthenticationProvider}
*/
public AuthenticationManagerBuilder authenticationProvider(
AuthenticationProvider authenticationProvider) {
@@ -27,7 +27,7 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
* to have in memory authentication. It also allows easily adding users to the in memory
* authentication.
*
* @param <B> the type of the {@link SecurityBuilder} that is being configured
* @param <B> the type of the {@link ProviderManagerBuilder} that is being configured
*
* @author Rob Winch
* @since 3.2
@@ -38,7 +38,6 @@ import org.springframework.security.provisioning.JdbcUserDetailsManager;
* <p>
* The only required method is the {@link #dataSource(javax.sql.DataSource)} all other
* methods have reasonable defaults.
* </p>
*
* @param <B> the type of the {@link ProviderManagerBuilder} that is being configured
*
@@ -82,7 +81,7 @@ public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B
* </code>
* @param query The query to use for selecting the username, password, and if the user
* is enabled by username. Must contain a single parameter for the username.
* @return The {@link JdbcUserDetailsManagerRegistry} used for additional
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
* customizations
* @throws Exception
*/
@@ -102,7 +101,7 @@ public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B
*
* @param query The query to use for selecting the username, authority by username.
* Must contain a single parameter for the username.
* @return The {@link JdbcUserDetailsManagerRegistry} used for additional
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
* customizations
* @throws Exception
*/
@@ -126,7 +125,7 @@ public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B
*
* @param query The query to use for selecting the authorities by group. Must contain
* a single parameter for the username.
* @return The {@link JdbcUserDetailsManagerRegistry} used for additional
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
* customizations
* @throws Exception
*/
@@ -181,7 +180,7 @@ public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B
/**
* Populates the default schema that allows users and authorities to be stored.
*
* @return The {@link JdbcUserDetailsManagerRegistry} used for additional
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
* customizations
*/
public JdbcUserDetailsManagerConfigurer<B> withDefaultSchema() {
@@ -80,9 +80,6 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
/**
* Builds the user to be added. At minimum the username, password, and authorities
* should provided. The remaining attributes have reasonable defaults.
*
* @param <T> the type of {@link UserDetailsManagerConfigurer} to return for chaining
* methods.
*/
public class UserDetailsBuilder {
private String username;
@@ -103,11 +100,10 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
}
/**
* Returns the {@link UserDetailsManagerRegistry} for method chaining (i.e. to add
* Returns the {@link UserDetailsManagerConfigurer} for method chaining (i.e. to add
* another user)
*
* @return the {@link UserDetailsManagerRegistry} for method chaining (i.e. to add
* another user)
* @return the {@link UserDetailsManagerConfigurer} for method chaining
*/
public C and() {
return builder;
@@ -27,8 +27,8 @@ import org.springframework.security.core.userdetails.UserDetailsService;
* @author Rob Winch
* @since 3.2
*
* @param <B> the type of the {@link SecurityBuilder}
* @param <C> the {@link SecurityConfigurer} (or this)
* @param <B> the type of the {@link ProviderManagerBuilder}
* @param <C> the {@link UserDetailsServiceConfigurer} (or this)
* @param <U> the type of UserDetailsService being used to allow for returning the
* concrete UserDetailsService.
*/
@@ -29,9 +29,8 @@ import org.springframework.security.config.annotation.configuration.ObjectPostPr
/**
* <p>
* Enables Spring Security global method security similar to the <global-method-security>
* Enables Spring Security global method security similar to the &lt;global-method-security&gt;
* xml support.
* </p>
*
* <p>
* More advanced configurations may wish to extend
@@ -15,14 +15,10 @@
*/
package org.springframework.security.config.annotation.method.configuration;
import java.util.Map;
import org.springframework.aop.config.AopConfigUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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.
@@ -23,9 +23,11 @@ import org.aopalliance.intercept.MethodInterceptor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.*;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.type.AnnotationMetadata;
@@ -45,7 +47,6 @@ import org.springframework.security.access.intercept.AfterInvocationManager;
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
import org.springframework.security.access.intercept.RunAsManager;
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource;
import org.springframework.security.access.method.MethodSecurityMetadataSource;
@@ -317,21 +318,6 @@ public class GlobalMethodSecurityConfiguration implements ImportAware {
return preInvocationAdvice;
}
/**
* Obtains the {@link MethodSecurityMetadataSourceAdvisor} to be used.
*
* @return
*/
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@Bean
public MethodSecurityMetadataSourceAdvisor metaDataSourceAdvisor() {
MethodSecurityMetadataSourceAdvisor methodAdvisor = new MethodSecurityMetadataSourceAdvisor(
"methodSecurityInterceptor", methodSecurityMetadataSource(),
"methodSecurityMetadataSource");
methodAdvisor.setOrder(order());
return methodAdvisor;
}
/**
* Obtains the attributes from {@link EnableGlobalMethodSecurity} if this class was
* imported using the {@link EnableGlobalMethodSecurity} annotation.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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.
@@ -54,13 +54,18 @@ final class GlobalMethodSecuritySelector implements ImportSelector {
.isAssignableFrom(importingClass);
AdviceMode mode = attributes.getEnum("mode");
String autoProxyClassName = AdviceMode.PROXY == mode ? AutoProxyRegistrar.class
boolean isProxy = AdviceMode.PROXY == mode;
String autoProxyClassName = isProxy ? AutoProxyRegistrar.class
.getName() : GlobalMethodSecurityAspectJAutoProxyRegistrar.class
.getName();
boolean jsr250Enabled = attributes.getBoolean("jsr250Enabled");
List<String> classNames = new ArrayList<String>(4);
if(isProxy) {
classNames.add(MethodSecurityMetadataSourceAdvisorRegistrar.class.getName());
}
classNames.add(autoProxyClassName);
if (!skipMethodSecurityConfiguration) {
@@ -0,0 +1,62 @@
/*
* Copyright 2002-2015 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.method.configuration;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor;
import org.springframework.util.MultiValueMap;
/**
* Creates Spring Security's MethodSecurityMetadataSourceAdvisor only when
* using proxy based method security (i.e. do not do it when using ASPECTJ).
* The conditional logic is controlled through {@link GlobalMethodSecuritySelector}.
*
* @author Rob Winch
* @since 4.0.2
* @see GlobalMethodSecuritySelector
*/
class MethodSecurityMetadataSourceAdvisorRegistrar implements
ImportBeanDefinitionRegistrar {
/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableGlobalMethodSecurity#proxyTargetClass()} attribute on the
* importing {@code @Configuration} class.
*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
BeanDefinitionBuilder advisor = BeanDefinitionBuilder
.rootBeanDefinition(MethodSecurityMetadataSourceAdvisor.class);
advisor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
advisor.addConstructorArgValue("methodSecurityInterceptor");
advisor.addConstructorArgReference("methodSecurityMetadataSource");
advisor.addConstructorArgValue("methodSecurityMetadataSource");
MultiValueMap<String,Object> attributes = importingClassMetadata.getAllAnnotationAttributes(EnableGlobalMethodSecurity.class.getName());
Integer order = (Integer) attributes.getFirst("order");
if(order != null) {
advisor.addPropertyValue("order", order);
}
registry.registerBeanDefinition("metaDataSourceAdvisor",
advisor.getBeanDefinition());
}
}
@@ -25,6 +25,7 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.ObjectUtils;
/**
* A base class for registering {@link RequestMatcher}'s. For example, it might allow for
@@ -48,6 +49,20 @@ public abstract class AbstractRequestMatcherRegistry<C> {
return requestMatchers(ANY_REQUEST);
}
/**
* Maps a {@link List} of
* {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher}
* instances.
*
* @param method the {@link HttpMethod} to use for any
* {@link HttpMethod}.
*
* @return the object that is chained after creating the {@link RequestMatcher}
*/
public C antMatchers(HttpMethod method) {
return antMatchers(method, new String[] { "/**" });
}
/**
* Maps a {@link List} of
* {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher}
@@ -55,7 +70,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
*
* @param method the {@link HttpMethod} to use or {@code null} for any
* {@link HttpMethod}.
* @param antPatterns the ant patterns to create
* @param antPatterns the ant patterns to create. If {@code null} or empty, then matches on nothing.
* {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher} from
*
* @return the object that is chained after creating the {@link RequestMatcher}
@@ -142,11 +142,11 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends
* <li>{@link LogoutFilter}</li>
* <li>{@link X509AuthenticationFilter}</li>
* <li>{@link AbstractPreAuthenticatedProcessingFilter}</li>
* <li>{@link org.springframework.security.cas.web.CasAuthenticationFilter}</li>
* <li><a href="{@docRoot}/org/springframework/security/cas/web/CasAuthenticationFilter.html">CasAuthenticationFilter</a></li>
* <li>{@link UsernamePasswordAuthenticationFilter}</li>
* <li>{@link ConcurrentSessionFilter}</li>
* <li>{@link OpenIDAuthenticationFilter}</li>
* <li>{@link DefaultLoginPageGeneratingFilter}</li>
* <li>{@link org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter}</li>
* <li>{@link ConcurrentSessionFilter}</li>
* <li>{@link DigestAuthenticationFilter}</li>
* <li>{@link BasicAuthenticationFilter}</li>
@@ -71,7 +71,7 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
/**
* A {@link HttpSecurity} is similar to Spring Security's XML <http> element in the
* A {@link HttpSecurity} is similar to Spring Security's XML &lt;http&gt; element in the
* namespace configuration. It allows configuring web based security for specific http
* requests. By default it will be applied to all requests, but can be restricted using
* {@link #requestMatcher(RequestMatcher)} or other similar methods.
@@ -283,7 +283,7 @@ public final class HttpSecurity extends
*
* @return
* @throws Exception
* @see {@link HeadersConfigurer}
* @see HeadersConfigurer
*/
public HeadersConfigurer<HttpSecurity> headers() throws Exception {
return getOrApply(new HeadersConfigurer<HttpSecurity>());
@@ -326,8 +326,8 @@ public final class HttpSecurity extends
*
* <pre>
* &lt;listener&gt;
* &ltlistener-class&gt;org.springframework.security.web.session.HttpSessionEventPublisher&lt;/listener-class&gt;
* &lt/listener>
* &lt;listener-class&gt;org.springframework.security.web.session.HttpSessionEventPublisher&lt;/listener-class&gt;
* &lt;/listener&gt;
* </pre>
*
* Alternatively,
@@ -378,7 +378,7 @@ public final class HttpSecurity extends
*
* @return the {@link PortMapperConfigurer} for further customizations
* @throws Exception
* @see {@link #requiresChannel()}
* @see #requiresChannel()
*/
public PortMapperConfigurer<HttpSecurity> portMapper() throws Exception {
return getOrApply(new PortMapperConfigurer<HttpSecurity>());
@@ -716,7 +716,7 @@ public final class HttpSecurity extends
* {@link org.springframework.security.authentication.AnonymousAuthenticationToken}
* and contain the role "ROLE_ANONYMOUS".
*
* <h2>Example Configuration</h2
* <h2>Example Configuration</h2>
*
* The following configuration demonstrates how to specify that anonymous users should
* contain the role "ROLE_ANON" instead.
@@ -908,6 +908,10 @@ public final class HttpSecurity extends
return getOrApply(new HttpBasicConfigurer<HttpSecurity>());
}
public <C> void setSharedObject(Class<C> sharedType, C object) {
super.setSharedObject(sharedType, object);
}
@Override
protected void beforeConfigure() throws Exception {
setSharedObject(AuthenticationManager.class, getAuthenticationRegistry().build());
@@ -1,13 +0,0 @@
package org.springframework.security.config.annotation.web.configuration;
import org.springframework.context.annotation.Conditional;
/**
* @author Rob Winch
* @since 4.0
*/
@Conditional(OnMissingBeanCondition.class)
@interface ConditionalOnMissingBean {
Class<?> value();
}
@@ -1,41 +0,0 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.springframework.security.config.annotation.web.configuration;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.ConfigurationCondition;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.ClassUtils;
import java.util.Map;
/**
* @author Rob Winch
*/
class OnMissingBeanCondition implements ConfigurationCondition {
public ConfigurationPhase getConfigurationPhase() {
return ConfigurationPhase.REGISTER_BEAN;
}
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> attrs = metadata
.getAnnotationAttributes(ConditionalOnMissingBean.class.getName());
Class<?> type = (Class) attrs.get("value");
final Map<String, ?> beans = context.getBeanFactory().getBeansOfType(type);
return beans.isEmpty();
}
}
@@ -29,7 +29,7 @@ import java.util.List;
/**
* Used to add a {@link RequestDataValueProcessor} for Spring MVC and Spring Security CSRF
* integration. This configuration is added whenever {@link EnableWebMvc} is added by
* {@link SpringWebMvcImportSelector} and the DispatcherServlet is present on the
* <a href="{@docRoot}/org/springframework/security/config/annotation/web/configuration/SpringWebMvcImportSelector.html">SpringWebMvcImportSelector</a> and the DispatcherServlet is present on the
* classpath. It also adds the {@link AuthenticationPrincipalArgumentResolver} as a
* {@link HandlerMethodArgumentResolver}.
*
@@ -47,7 +47,6 @@ class WebMvcSecurityConfiguration extends WebMvcConfigurerAdapter {
argumentResolvers.add(new CsrfTokenArgumentResolver());
}
@ConditionalOnMissingBean(RequestDataValueProcessor.class)
@Bean
public RequestDataValueProcessor requestDataValueProcessor() {
return new CsrfRequestDataValueProcessor();
@@ -262,7 +262,7 @@ public abstract class WebSecurityConfigurerAdapter implements
* {@link #userDetailsService()} instead
* @return
* @throws Exception
* @see {@link #userDetailsService()}
* @see #userDetailsService()
*/
public UserDetailsService userDetailsServiceBean() throws Exception {
AuthenticationManagerBuilder globalAuthBuilder = context
@@ -273,7 +273,7 @@ public abstract class WebSecurityConfigurerAdapter implements
/**
* Allows modifying and accessing the {@link UserDetailsService} from
* {@link #userDetailsServiceBean()()} without interacting with the
* {@link #userDetailsServiceBean()} without interacting with the
* {@link ApplicationContext}. Developers should override this method when changing
* the instance of {@link #userDetailsServiceBean()}.
*
@@ -178,8 +178,8 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
}
/**
* Ensures the urls for {@link #failureUrl(String)} and
* {@link #authenticationUrls(String)} are granted access to any user.
* Ensures the urls for {@link #failureUrl(String)} as well as for the {@link HttpSecurityBuilder}, the
* {@link #getLoginPage} and {@link #getLoginProcessingUrl} are granted access to any user.
*
* @param permitAll true to grant access to the URLs false to skip this step
* @return the {@link FormLoginConfigurer} for additional customization
@@ -51,7 +51,7 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
*
* <ul>
* <li>
* {@link org.springframework.security.config.annotation.web.builders.HttpSecurity#getAuthenticationManager()}
* {@link AuthenticationManager}
* </li>
* </ul>
*
@@ -108,7 +108,6 @@ abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConf
* @return the {@link AccessDecisionVoter} instances used to create the default
* {@link AccessDecisionManager}
*/
@SuppressWarnings("rawtypes")
abstract List<AccessDecisionVoter<? extends Object>> getDecisionVoters(H http);
abstract class AbstractInterceptUrlRegistry<R extends AbstractInterceptUrlRegistry<R, T>, T>
@@ -116,7 +115,7 @@ abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConf
/**
* Allows setting the {@link AccessDecisionManager}. If none is provided, a
* default {@l AccessDecisionManager} is created.
* default {@link AccessDecisionManager} is created.
*
* @param accessDecisionManager the {@link AccessDecisionManager} to use
* @return the {@link AbstractInterceptUrlConfigurer} for further customization
@@ -157,12 +156,13 @@ abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConf
* @return the default {@code AccessDecisionManager}
*/
private AccessDecisionManager createDefaultAccessDecisionManager(H http) {
return new AffirmativeBased(getDecisionVoters(http));
AffirmativeBased result = new AffirmativeBased(getDecisionVoters(http));
return postProcess(result);
}
/**
* If currently null, creates a default {@link AccessDecisionManager} using
* {@link #createDefaultAccessDecisionManager()}. Otherwise returns the
* {@link #createDefaultAccessDecisionManager(HttpSecurityBuilder)}. Otherwise returns the
* {@link AccessDecisionManager}.
*
* @param http the builder to use
@@ -84,7 +84,7 @@ public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>
* @param accessDeniedUrl the URL to the access denied page (i.e. /errors/401)
* @return the {@link ExceptionHandlingConfigurer} for further customization
* @see AccessDeniedHandlerImpl
* @see {@link #accessDeniedHandler(org.springframework.security.web.access.AccessDeniedHandler)}
* @see #accessDeniedHandler(org.springframework.security.web.access.AccessDeniedHandler)
*/
public ExceptionHandlingConfigurer<H> accessDeniedPage(String accessDeniedUrl) {
AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl();
@@ -70,7 +70,7 @@ import org.springframework.util.StringUtils;
*
* @author Rob Winch
* @since 3.2
* @see {@link org.springframework.security.config.annotation.web.builders.HttpSecurity#authorizeRequests()}
* @see org.springframework.security.config.annotation.web.builders.HttpSecurity#authorizeRequests()
*/
public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
extends
@@ -339,7 +339,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
*
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
* customization
* @see {@link RememberMeConfigurer}
* @see RememberMeConfigurer
*/
public ExpressionInterceptUrlRegistry rememberMe() {
return access(rememberMe);
@@ -371,7 +371,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
*
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
* customization
* @see {@link RememberMeConfigurer}
* @see RememberMeConfigurer
*/
public ExpressionInterceptUrlRegistry fullyAuthenticated() {
return access(fullyAuthenticated);
@@ -53,7 +53,7 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
* The following shared objects are used:
*
* <ul>
* <li>{@link AuthenticationManager}</li>
* <li>{@link org.springframework.security.authentication.AuthenticationManager}</li>
* <li>{@link RememberMeServices} - is optionally used. See {@link RememberMeConfigurer}</li>
* <li>{@link SessionAuthenticationStrategy} - is optionally used. See
* {@link SessionManagementConfigurer}</li>
@@ -186,7 +186,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
* X-XSS-Protection: 1
* </pre>
*
* or if {@link #setBlock(boolean)} is true
* or if {@link XXssProtectionHeaderWriter#setBlock(boolean)} of the given {@link XXssProtectionHeaderWriter} is true
*
*
* <pre>
@@ -29,6 +29,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
@@ -65,6 +66,7 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
*
* <ul>
* <li>{@link AuthenticationManager}</li>
* <li>{@link RememberMeServices}</li>
* </ul>
*
* @author Rob Winch
@@ -81,7 +83,7 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
/**
* Creates a new instance
* @throws Exception
* @see {@link HttpSecurity#httpBasic()}
* @see HttpSecurity#httpBasic()
*/
public HttpBasicConfigurer() throws Exception {
realmName(DEFAULT_REALM);
@@ -177,6 +179,10 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
basicAuthenticationFilter
.setAuthenticationDetailsSource(authenticationDetailsSource);
}
RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);
if(rememberMeServices != null) {
basicAuthenticationFilter.setRememberMeServices(rememberMeServices);
}
basicAuthenticationFilter = postProcess(basicAuthenticationFilter);
http.addFilter(basicAuthenticationFilter);
}
@@ -187,7 +187,7 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends
* Populates a {@link PreAuthenticatedAuthenticationProvider} into
* {@link HttpSecurity#authenticationProvider(org.springframework.security.authentication.AuthenticationProvider)}
* and a {@link Http403ForbiddenEntryPoint} into
* {@link HttpSecurity#authenticationEntryPoint(org.springframework.security.web.AuthenticationEntryPoint)}
* {@link HttpSecurityBuilder#setSharedObject(Class, Object)}
*
* @see org.springframework.security.config.annotation.SecurityConfigurerAdapter#init(org.springframework.security.config.annotation.SecurityBuilder)
*/
@@ -23,6 +23,7 @@ import javax.servlet.http.HttpSession;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.LogoutHandler;
@@ -35,7 +36,7 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
/**
* Adds logout support. Other {@link SecurityConfigurer} instances may invoke
* {@link #addLogoutHandler(LogoutHandler)} in the {@link #init(HttpSecurity)} phase.
* {@link #addLogoutHandler(LogoutHandler)} in the {@link #init(HttpSecurityBuilder)} phase.
*
* <h2>Security Filters</h2>
*
@@ -88,6 +89,17 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
return this;
}
/**
* Specifies if {@link SecurityContextLogoutHandler} should clear the {@link Authentication} at the time of logout.
* @param clearAuthentication true {@link SecurityContextLogoutHandler} should clear the {@link Authentication} (default), or false otherwise.
* @return the {@link LogoutConfigurer} for further customization
*/
public LogoutConfigurer<H> clearAuthentication(boolean clearAuthentication) {
contextLogoutHandler.setClearAuthentication(clearAuthentication);
return this;
}
/**
* Configures {@link SecurityContextLogoutHandler} to invalidate the
* {@link HttpSession} at the time of logout.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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.
@@ -180,6 +180,18 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>> extend
return this;
}
/**
* The name of cookie which store the token for remember me authentication. Defaults to 'remember-me'.
*
* @param rememberMeCookieName the name of cookie which store the token for remember me authentication
* @return the {@link RememberMeConfigurer} for further customization
* @since 4.0.1
*/
public RememberMeConfigurer<H> rememberMeCookieName(String rememberMeCookieName) {
this.rememberMeCookieName = rememberMeCookieName;
return this;
}
/**
* Allows control over the destination a remembered user is sent to when they are
* successfully authenticated. By default, the filter will just allow the current
@@ -20,6 +20,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.security.web.context.SecurityContextRepository;
@@ -85,6 +86,9 @@ public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>> e
SecurityContextRepository securityContextRepository = http
.getSharedObject(SecurityContextRepository.class);
if(securityContextRepository == null) {
securityContextRepository = new HttpSessionSecurityContextRepository();
}
SecurityContextPersistenceFilter securityContextFilter = new SecurityContextPersistenceFilter(
securityContextRepository);
SessionManagementConfigurer<?> sessionManagement = http
@@ -199,7 +199,7 @@ public final class OpenIDLoginConfigurer<H extends HttpSecurityBuilder<H>>
* {@link HttpServletRequest} matches this URL the {@link OpenIDAuthenticationFilter}
* will attempt to authenticate the request. The default is "/login/openid".
*
* @param loginUrl the URL used to perform authentication
* @param loginProcessingUrl the URL used to perform authentication
* @return the {@link OpenIDLoginConfigurer} for additional customization
*/
public OpenIDLoginConfigurer<H> loginProcessingUrl(String loginProcessingUrl) {
@@ -15,9 +15,17 @@
*/
package org.springframework.security.config.annotation.web.messaging;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.messaging.Message;
import org.springframework.messaging.simp.SimpMessageType;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.config.annotation.web.configurers.RememberMeConfigurer;
import org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler;
import org.springframework.security.messaging.access.expression.ExpressionBasedMessageSecurityMetadataSourceFactory;
import org.springframework.security.messaging.access.intercept.MessageSecurityMetadataSource;
import org.springframework.security.messaging.util.matcher.MessageMatcher;
@@ -28,8 +36,6 @@ import org.springframework.util.Assert;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
import java.util.*;
/**
* Allows mapping security constraints using {@link MessageMatcher} to the security
* expressions.
@@ -45,6 +51,8 @@ public class MessageSecurityMetadataSourceRegistry {
private static final String fullyAuthenticated = "fullyAuthenticated";
private static final String rememberMe = "rememberMe";
private SecurityExpressionHandler<Message<Object>> expressionHandler = new DefaultMessageSecurityExpressionHandler<Object>();
private final LinkedHashMap<MatcherBuilder, String> matcherToExpression = new LinkedHashMap<MatcherBuilder, String>();
private DelegatingPathMatcher pathMatcher = new DelegatingPathMatcher();
@@ -97,7 +105,7 @@ public class MessageSecurityMetadataSourceRegistry {
* {@link MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)} .
*
* @return the {@link Constraint} that is associated to the {@link MessageMatcher}
* @see {@link MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)}
* @see MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)
*/
public Constraint simpDestMatchers(String... patterns) {
return simpDestMatchers(null, patterns);
@@ -114,7 +122,7 @@ public class MessageSecurityMetadataSourceRegistry {
* {@link MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)}.
*
* @return the {@link Constraint} that is associated to the {@link MessageMatcher}
* @see {@link MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)}
* @see MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)
*/
public Constraint simpMessageDestMatchers(String... patterns) {
return simpDestMatchers(SimpMessageType.MESSAGE, patterns);
@@ -131,7 +139,7 @@ public class MessageSecurityMetadataSourceRegistry {
* {@link MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)}.
*
* @return the {@link Constraint} that is associated to the {@link MessageMatcher}
* @see {@link MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)}
* @see MessageSecurityMetadataSourceRegistry#simpDestPathMatcher(PathMatcher)
*/
public Constraint simpSubscribeDestMatchers(String... patterns) {
return simpDestMatchers(SimpMessageType.SUBSCRIBE, patterns);
@@ -200,6 +208,20 @@ public class MessageSecurityMetadataSourceRegistry {
return new Constraint(builders);
}
/**
* The {@link SecurityExpressionHandler} to be used. The
* default is to use {@link DefaultMessageSecurityExpressionHandler}.
*
* @param expressionHandler the {@link SecurityExpressionHandler} to use. Cannot be null.
* @return the {@link MessageSecurityMetadataSourceRegistry} for further
* customization.
*/
public MessageSecurityMetadataSourceRegistry expressionHandler(SecurityExpressionHandler<Message<Object>> expressionHandler) {
Assert.notNull(expressionHandler, "expressionHandler cannot be null");
this.expressionHandler = expressionHandler;
return this;
}
/**
* Allows subclasses to create creating a {@link MessageSecurityMetadataSource}.
*
@@ -217,7 +239,7 @@ public class MessageSecurityMetadataSourceRegistry {
matcherToExpression.put(entry.getKey().build(), entry.getValue());
}
return ExpressionBasedMessageSecurityMetadataSourceFactory
.createExpressionMessageMetadataSource(matcherToExpression);
.createExpressionMessageMetadataSource(matcherToExpression, expressionHandler);
}
/**
@@ -331,7 +353,7 @@ public class MessageSecurityMetadataSourceRegistry {
*
* @return the {@link MessageSecurityMetadataSourceRegistry} for further
* customization
* @see {@link RememberMeConfigurer}
* @see RememberMeConfigurer
*/
public MessageSecurityMetadataSourceRegistry rememberMe() {
return access(rememberMe);
@@ -363,7 +385,7 @@ public class MessageSecurityMetadataSourceRegistry {
*
* @return the {@link MessageSecurityMetadataSourceRegistry} for further
* customization
* @see {@link RememberMeConfigurer}
* @see RememberMeConfigurer
*/
public MessageSecurityMetadataSourceRegistry fullyAuthenticated() {
return access(fullyAuthenticated);
@@ -410,7 +432,7 @@ public class MessageSecurityMetadataSourceRegistry {
return "hasAnyAuthority('" + anyAuthorities + "')";
}
private class PreBuiltMatcherBuilder implements MatcherBuilder {
private static class PreBuiltMatcherBuilder implements MatcherBuilder {
private MessageMatcher<?> matcher;
private PreBuiltMatcherBuilder(MessageMatcher<?> matcher) {
@@ -30,7 +30,7 @@ import org.springframework.web.servlet.support.RequestDataValueProcessor;
/**
* Used to add a {@link RequestDataValueProcessor} for Spring MVC and Spring Security CSRF
* integration. This configuration is added whenever {@link EnableWebMvc} is added by
* {@link SpringWebMvcImportSelector} and the DispatcherServlet is present on the
* <a href="{@docRoot}/org/springframework/security/config/annotation/web/configuration/SpringWebMvcImportSelector.html">SpringWebMvcImportSelector</a> and the DispatcherServlet is present on the
* classpath. It also adds the {@link AuthenticationPrincipalArgumentResolver} as a
* {@link HandlerMethodArgumentResolver}.
*
@@ -26,10 +26,12 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.messaging.Message;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry;
import org.springframework.security.messaging.access.expression.MessageExpressionVoter;
@@ -80,6 +82,8 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends
AbstractWebSocketMessageBrokerConfigurer implements SmartInitializingSingleton {
private final WebSocketMessageSecurityMetadataSourceRegistry inboundRegistry = new WebSocketMessageSecurityMetadataSourceRegistry();
private SecurityExpressionHandler<Message<Object>> expressionHandler;
private ApplicationContext context;
public void registerStompEndpoints(StompEndpointRegistry registry) {
@@ -145,8 +149,14 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends
public ChannelSecurityInterceptor inboundChannelSecurity() {
ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor(
inboundMessageSecurityMetadataSource());
MessageExpressionVoter<Object> voter = new MessageExpressionVoter<Object>();
if(expressionHandler != null) {
voter.setExpressionHandler(expressionHandler);
}
List<AccessDecisionVoter<? extends Object>> voters = new ArrayList<AccessDecisionVoter<? extends Object>>();
voters.add(new MessageExpressionVoter<Object>());
voters.add(voter);
AffirmativeBased manager = new AffirmativeBased(voters);
channelSecurityInterceptor.setAccessDecisionManager(manager);
return channelSecurityInterceptor;
@@ -159,6 +169,9 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends
@Bean
public MessageSecurityMetadataSource inboundMessageSecurityMetadataSource() {
if(expressionHandler != null) {
inboundRegistry.expressionHandler(expressionHandler);
}
configureInbound(inboundRegistry);
return inboundRegistry.createMetadataSource();
}
@@ -170,7 +183,7 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
}
private class WebSocketMessageSecurityMetadataSourceRegistry extends
private static class WebSocketMessageSecurityMetadataSourceRegistry extends
MessageSecurityMetadataSourceRegistry {
@Override
public MessageSecurityMetadataSource createMetadataSource() {
@@ -193,6 +206,13 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends
this.context = context;
}
@Autowired(required = false)
public void setMessageExpessionHandler(List<SecurityExpressionHandler<Message<Object>>> expressionHandlers) {
if(expressionHandlers.size() == 1) {
this.expressionHandler = expressionHandlers.get(0);
}
}
public void afterSingletonsInstantiated() {
if (sameOriginDisabled()) {
return;
@@ -25,7 +25,7 @@ import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
* Stateful parser for the <password-encoder> element.
* Stateful parser for the &lt;password-encoder&gt; element.
*
* Will produce a PasswordEncoder and (optionally) a SaltSource.
*
@@ -131,6 +131,10 @@ final class AuthenticationConfigBuilder {
private String loginProcessingUrl;
private String openidLoginProcessingUrl;
private String formLoginPage;
private String openIDLoginPage;
public AuthenticationConfigBuilder(Element element, boolean forceAutoConfig,
ParserContext pc, SessionCreationPolicy sessionPolicy,
BeanReference requestCache, BeanReference authenticationManager,
@@ -212,6 +216,7 @@ final class AuthenticationConfigBuilder {
formFilter = parser.getFilterBean();
formEntryPoint = parser.getEntryPointBean();
loginProcessingUrl = parser.getLoginProcessingUrl();
formLoginPage = parser.getLoginPage();
}
if (formFilter != null) {
@@ -242,6 +247,7 @@ final class AuthenticationConfigBuilder {
openIDFilter = parser.getFilterBean();
openIDEntryPoint = parser.getEntryPointBean();
openidLoginProcessingUrl = parser.getLoginProcessingUrl();
openIDLoginPage = parser.getLoginPage();
List<Element> attrExElts = DomUtils.getChildElementsByTagName(openIDLoginElt,
Elements.OPENID_ATTRIBUTE_EXCHANGE);
@@ -527,8 +533,6 @@ final class AuthenticationConfigBuilder {
void createLoginPageFilterIfNeeded() {
boolean needLoginPage = formFilterId != null || openIDFilterId != null;
String formLoginPage = getLoginFormUrl(formEntryPoint);
String openIDLoginPage = getLoginFormUrl(openIDEntryPoint);
// If no login page has been defined, add in the default page generator.
if (needLoginPage && formLoginPage == null && openIDLoginPage == null) {
@@ -556,7 +560,7 @@ final class AuthenticationConfigBuilder {
void createLogoutFilter() {
Element logoutElt = DomUtils.getChildElementByTagName(httpElt, Elements.LOGOUT);
if (logoutElt != null || autoConfig) {
String formLoginPage = getLoginFormUrl(formEntryPoint);
String formLoginPage = this.formLoginPage;
if (formLoginPage == null) {
formLoginPage = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL;
}
@@ -716,8 +720,6 @@ final class AuthenticationConfigBuilder {
// If formLogin has been enabled either through an element or auto-config, then it
// is used if no openID login page
// has been set.
String formLoginPage = getLoginFormUrl(formEntryPoint);
String openIDLoginPage = getLoginFormUrl(openIDEntryPoint);
if (formLoginPage != null && openIDLoginPage != null) {
pc.getReaderContext().error(
@@ -747,26 +749,6 @@ final class AuthenticationConfigBuilder {
return null;
}
private String getLoginFormUrl(BeanDefinition entryPoint) {
if (entryPoint == null) {
return null;
}
ConstructorArgumentValues cavs = entryPoint.getConstructorArgumentValues();
ValueHolder vh = cavs.getIndexedArgumentValue(0, String.class);
if (vh == null) {
return null;
}
// If the login URL is the default one, then it is assumed not to have been set
// explicitly
if (DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL.equals(vh.getValue())) {
return null;
}
return (String) vh.getValue();
}
private void createUserDetailsServiceFactory() {
if (pc.getRegistry().containsBeanDefinition(BeanIds.USER_DETAILS_SERVICE_FACTORY)) {
// Multiple <http> case
@@ -15,12 +15,24 @@
*/
package org.springframework.security.config.websocket;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import static org.springframework.security.config.Elements.*;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.*;
import org.springframework.beans.factory.support.*;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.ManagedList;
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.beans.factory.xml.XmlReaderContext;
@@ -43,10 +55,6 @@ import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
/**
* Parses Spring Security's websocket namespace support. A simple example is:
*
@@ -111,6 +119,11 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
ManagedMap<BeanDefinition, String> matcherToExpression = new ManagedMap<BeanDefinition, String>();
String id = element.getAttribute(ID_ATTR);
Element expressionHandlerElt = DomUtils.getChildElementByTagName(element,
EXPRESSION_HANDLER);
String expressionHandlerRef = expressionHandlerElt == null ? null : expressionHandlerElt.getAttribute("ref");
boolean expressionHandlerDefined = StringUtils.hasText(expressionHandlerRef);
boolean sameOriginDisabled = Boolean.parseBoolean(element
.getAttribute(DISABLED_ATTR));
@@ -130,11 +143,18 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
.rootBeanDefinition(ExpressionBasedMessageSecurityMetadataSourceFactory.class);
mds.setFactoryMethod("createExpressionMessageMetadataSource");
mds.addConstructorArgValue(matcherToExpression);
if(expressionHandlerDefined) {
mds.addConstructorArgReference(expressionHandlerRef);
}
String mdsId = context.registerWithGeneratedName(mds.getBeanDefinition());
ManagedList<BeanDefinition> voters = new ManagedList<BeanDefinition>();
voters.add(new RootBeanDefinition(MessageExpressionVoter.class));
BeanDefinitionBuilder messageExpressionVoterBldr = BeanDefinitionBuilder.rootBeanDefinition(MessageExpressionVoter.class);
if(expressionHandlerDefined) {
messageExpressionVoterBldr.addPropertyReference("expressionHandler", expressionHandlerRef);
}
voters.add(messageExpressionVoterBldr.getBeanDefinition());
BeanDefinitionBuilder adm = BeanDefinitionBuilder
.rootBeanDefinition(ConsensusBased.class);
adm.addConstructorArgValue(voters);
@@ -208,6 +228,11 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
static class MessageSecurityPostProcessor implements
BeanDefinitionRegistryPostProcessor {
/**
* This is not available prior to Spring 4.2
*/
private static final String WEB_SOCKET_AMMH_CLASS_NAME = "org.springframework.web.socket.messaging.WebSocketAnnotationMethodMessageHandler";
private static final String CLIENT_INBOUND_CHANNEL_BEAN_ID = "clientInboundChannel";
private static final String INTERCEPTORS_PROP = "interceptors";
@@ -231,7 +256,7 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
BeanDefinition bd = registry.getBeanDefinition(beanName);
String beanClassName = bd.getBeanClassName();
if (beanClassName.equals(SimpAnnotationMethodMessageHandler.class
.getName())) {
.getName()) || beanClassName.equals(WEB_SOCKET_AMMH_CLASS_NAME)) {
PropertyValue current = bd.getPropertyValues().getPropertyValue(
CUSTOM_ARG_RESOLVERS_PROP);
ManagedList<Object> argResolvers = new ManagedList<Object>();
@@ -274,7 +274,7 @@ protect-pointcut.attlist &=
websocket-message-broker =
## Allows securing a Message Broker. There are two modes. If no id is specified: ensures that any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver registered as a custom argument resolver; ensures that the SecurityContextChannelInterceptor is automatically registered for the clientInboundChannel; and that a ChannelSecurityInterceptor is registered with the clientInboundChannel. If the id is specified, creates a ChannelSecurityInterceptor that can be manually registered with the clientInboundChannel.
element websocket-message-broker { websocket-message-broker.attrlist, (intercept-message*) }
element websocket-message-broker { websocket-message-broker.attrlist, (intercept-message* & expression-handler?) }
websocket-message-broker.attrlist &=
## A bean identifier, used for referring to the bean elsewhere in the context. If specified, explicit configuration within clientInboundChannel is required. If not specified, ensures that any SimpAnnotationMethodMessageHandler has the AuthenticationPrincipalArgumentResolver registered as a custom argument resolver; ensures that the SecurityContextChannelInterceptor is automatically registered for the clientInboundChannel; and that a ChannelSecurityInterceptor is registered with the clientInboundChannel.
@@ -291,10 +291,10 @@ intercept-message.attrlist &=
## The destination ant pattern which will be mapped to the access attribute. For example, /** matches any message with a destination, /admin/** matches any message that has a destination that starts with admin.
attribute pattern {xsd:token}?
intercept-message.attrlist &=
## The access configuration attributes that apply for the configured message. For example, permitAll grants access to anyone, hasRole('ROLE_ADMIN') requires the user have the role 'ROLE_ADMIN'.
## The access configuration attributes that apply for the configured message. For example, permitAll grants access to anyone, hasRole('ROLE_ADMIN') requires the user have the role 'ROLE_ADMIN'.
attribute access {xsd:token}?
intercept-message.attrlist &=
## The type of message to match on. Valid values are defined in SimpMessageType (i.e. CONNECT, CONNECT_ACK, HEARTBEAT, MESSAGE, SUBSCRIBE, UNSUBSCRIBE, DISCONNECT, DISCONNECT_ACK, OTHER).
## The type of message to match on. Valid values are defined in SimpMessageType (i.e. CONNECT, CONNECT_ACK, HEARTBEAT, MESSAGE, SUBSCRIBE, UNSUBSCRIBE, DISCONNECT, DISCONNECT_ACK, OTHER).
attribute type {"CONNECT" | "CONNECT_ACK" | "HEARTBEAT" | "MESSAGE" | "SUBSCRIBE"| "UNSUBSCRIBE" | "DISCONNECT" | "DISCONNECT_ACK" | "OTHER"}?
http-firewall =
@@ -389,7 +389,7 @@ logout.attlist &=
## Specifies the URL that will cause a logout. Spring Security will initialize a filter that responds to this particular URL. Defaults to /logout if unspecified.
attribute logout-url {xsd:token}?
logout.attlist &=
## Specifies the URL to display once the user has logged out. If not specified, defaults to /.
## Specifies the URL to display once the user has logged out. If not specified, defaults to <form-login-login-page>/?logout (i.e. /login?logout).
attribute logout-success-url {xsd:token}?
logout.attlist &=
## Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true.
@@ -704,7 +704,7 @@ user.attlist &=
## Can be set to "true" to mark an account as locked and unusable.
attribute locked {xsd:boolean}?
user.attlist &=
## Can be set to "true" to mark an account as disabled and unusable.
## Can be set to "true" to mark an account as disabled and unusable.
attribute disabled {xsd:boolean}?
jdbc-user-service =
@@ -851,9 +851,20 @@
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="security:intercept-message"/>
</xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="security:intercept-message"/>
<xs:element name="expression-handler">
<xs:annotation>
<xs:documentation>Defines the SecurityExpressionHandler instance which will be used if expression-based
access-control is enabled. A default implementation (with no ACL support) will be used if
not supplied.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attributeGroup ref="security:ref"/>
</xs:complexType>
</xs:element>
</xs:choice>
<xs:attributeGroup ref="security:websocket-message-broker.attrlist"/>
</xs:complexType>
</xs:element>
@@ -1344,7 +1355,7 @@
<xs:attribute name="logout-success-url" type="xs:token">
<xs:annotation>
<xs:documentation>Specifies the URL to display once the user has logged out. If not specified, defaults to
/.
&lt;form-login-login-page&gt;/?logout (i.e. /login?logout).
</xs:documentation>
</xs:annotation>
</xs:attribute>
@@ -44,127 +44,127 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
*
*/
class AuthenticationManagerBuilderTests extends BaseSpringSpec {
def "add(AuthenticationProvider) does not perform registration"() {
setup:
ObjectPostProcessor opp = Mock()
AuthenticationProvider provider = Mock()
AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder(objectPostProcessor).objectPostProcessor(opp)
when: "Adding an AuthenticationProvider"
builder.authenticationProvider(provider)
builder.build()
then: "AuthenticationProvider is not passed into LifecycleManager (it should be managed externally)"
0 * opp._(_ as AuthenticationProvider)
}
def "add(AuthenticationProvider) does not perform registration"() {
setup:
ObjectPostProcessor opp = Mock()
AuthenticationProvider provider = Mock()
AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder(objectPostProcessor).objectPostProcessor(opp)
when: "Adding an AuthenticationProvider"
builder.authenticationProvider(provider)
builder.build()
then: "AuthenticationProvider is not passed into LifecycleManager (it should be managed externally)"
0 * opp._(_ as AuthenticationProvider)
}
// https://github.com/SpringSource/spring-security-javaconfig/issues/132
def "#132 Custom AuthenticationEventPublisher with Web configure(AuthenticationManagerBuilder)"() {
setup:
AuthenticationEventPublisher aep = Mock()
when:
AuthenticationManager am = new AuthenticationManagerBuilder(objectPostProcessor)
.authenticationEventPublisher(aep)
.inMemoryAuthentication()
.and()
.build()
then:
am.eventPublisher == aep
}
// https://github.com/SpringSource/spring-security-javaconfig/issues/132
def "#132 Custom AuthenticationEventPublisher with Web configure(AuthenticationManagerBuilder)"() {
setup:
AuthenticationEventPublisher aep = Mock()
when:
AuthenticationManager am = new AuthenticationManagerBuilder(objectPostProcessor)
.authenticationEventPublisher(aep)
.inMemoryAuthentication()
.and()
.build()
then:
am.eventPublisher == aep
}
def "authentication-manager support multiple DaoAuthenticationProvider's"() {
setup:
loadConfig(MultiAuthenticationProvidersConfig)
when:
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
then:
auth.name == "user"
auth.authorities*.authority == ['ROLE_USER']
when:
auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("admin","password"))
then:
auth.name == "admin"
auth.authorities*.authority.sort() == ['ROLE_ADMIN','ROLE_USER']
}
def "authentication-manager support multiple DaoAuthenticationProvider's"() {
setup:
loadConfig(MultiAuthenticationProvidersConfig)
when:
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
then:
auth.name == "user"
auth.authorities*.authority == ['ROLE_USER']
when:
auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("admin","password"))
then:
auth.name == "admin"
auth.authorities*.authority.sort() == ['ROLE_ADMIN','ROLE_USER']
}
@EnableWebSecurity
static class MultiAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.and()
.inMemoryAuthentication()
.withUser("admin").password("password").roles("USER","ADMIN")
}
}
@EnableWebSecurity
static class MultiAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.and()
.inMemoryAuthentication()
.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 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 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
}
def "isConfigured not configured"() {
setup:
ObjectPostProcessor opp = Mock()
when:
AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(opp)
then:
auth.isConfigured() == false
}
def "user from properties"() {
setup:
loadConfig(UserFromPropertiesConfig)
AuthenticationManager manager = context.getBean(AuthenticationConfiguration).authenticationManager
when:
manager.authenticate(new UsernamePasswordAuthenticationToken("joe","joespassword"))
then:
noExceptionThrown()
}
def "user from properties"() {
setup:
loadConfig(UserFromPropertiesConfig)
AuthenticationManager manager = context.getBean(AuthenticationConfiguration).authenticationManager
when:
manager.authenticate(new UsernamePasswordAuthenticationToken("joe","joespassword"))
then:
noExceptionThrown()
}
@Configuration
@EnableGlobalAuthentication
@Import(ObjectPostProcessorConfiguration.class)
static class UserFromPropertiesConfig {
@Configuration
@EnableGlobalAuthentication
@Import(ObjectPostProcessorConfiguration.class)
static class UserFromPropertiesConfig {
@Value("classpath:org/springframework/security/config/users.properties")
Resource users;
@Value("classpath:org/springframework/security/config/users.properties")
Resource users;
@Bean
public AuthenticationManager authenticationManager() {
return new ProviderManager(Arrays.asList(authenticationProvider()));
}
@Bean
public AuthenticationManager authenticationManager() {
return new ProviderManager(Arrays.asList(authenticationProvider()));
}
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService())
return provider;
}
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService())
return provider;
}
@Bean
public UserDetailsService userDetailsService() {
Properties properties = new Properties();
properties.load(users.getInputStream());
return new InMemoryUserDetailsManager(properties);
}
}
@Bean
public UserDetailsService userDetailsService() {
Properties properties = new Properties();
properties.load(users.getInputStream());
return new InMemoryUserDetailsManager(properties);
}
}
}
@@ -34,11 +34,11 @@ import org.springframework.security.core.userdetails.UserDetailsService;
*/
@Configuration
class BaseAuthenticationConfig {
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN").and()
}
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN").and()
}
}
@@ -32,80 +32,80 @@ import org.springframework.security.core.Authentication
*
*/
class NamespaceAuthenticationManagerTests extends BaseSpringSpec {
def "authentication-manager@erase-credentials=true (default)"() {
when:
loadConfig(EraseCredentialsTrueDefaultConfig)
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
then:
auth.principal.password == null
auth.credentials == null
when: "authenticate the same user"
auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
then: "successfully authenticate again"
noExceptionThrown()
}
def "authentication-manager@erase-credentials=true (default)"() {
when:
loadConfig(EraseCredentialsTrueDefaultConfig)
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
then:
auth.principal.password == null
auth.credentials == null
when: "authenticate the same user"
auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
then: "successfully authenticate again"
noExceptionThrown()
}
@EnableWebSecurity
static class EraseCredentialsTrueDefaultConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
@EnableWebSecurity
static class EraseCredentialsTrueDefaultConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
def "authentication-manager@erase-credentials=false"() {
when:
loadConfig(EraseCredentialsFalseConfig)
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
then:
auth.credentials == "password"
auth.principal.password == "password"
}
def "authentication-manager@erase-credentials=false"() {
when:
loadConfig(EraseCredentialsFalseConfig)
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password"))
then:
auth.credentials == "password"
auth.principal.password == "password"
}
@EnableWebSecurity
static class EraseCredentialsFalseConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.eraseCredentials(false)
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
@EnableWebSecurity
static class EraseCredentialsFalseConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.eraseCredentials(false)
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
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"
}
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
static class GlobalEraseCredentialsFalseConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.eraseCredentials(false)
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
}
@EnableWebSecurity
static class GlobalEraseCredentialsFalseConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.eraseCredentials(false)
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
}
}
@@ -31,51 +31,51 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager
*
*/
class NamespaceAuthenticationProviderTests extends BaseSpringSpec {
def "authentication-provider@ref"() {
when:
loadConfig(AuthenticationProviderRefConfig)
then:
authenticationProviders()[1] == AuthenticationProviderRefConfig.expected
}
def "authentication-provider@ref"() {
when:
loadConfig(AuthenticationProviderRefConfig)
then:
authenticationProviders()[1] == AuthenticationProviderRefConfig.expected
}
@EnableWebSecurity
static class AuthenticationProviderRefConfig extends WebSecurityConfigurerAdapter {
static DaoAuthenticationProvider expected = new DaoAuthenticationProvider()
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(expected)
}
@EnableWebSecurity
static class AuthenticationProviderRefConfig extends WebSecurityConfigurerAdapter {
static DaoAuthenticationProvider expected = new DaoAuthenticationProvider()
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(expected)
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
def "authentication-provider@user-service-ref"() {
when:
loadConfig(UserServiceRefConfig)
then:
findAuthenticationProvider(DaoAuthenticationProvider).userDetailsService == UserServiceRefConfig.expected
}
def "authentication-provider@user-service-ref"() {
when:
loadConfig(UserServiceRefConfig)
then:
findAuthenticationProvider(DaoAuthenticationProvider).userDetailsService == UserServiceRefConfig.expected
}
@EnableWebSecurity
static class UserServiceRefConfig extends WebSecurityConfigurerAdapter {
static InMemoryUserDetailsManager expected = new InMemoryUserDetailsManager([] as Collection)
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(expected)
}
@EnableWebSecurity
static class UserServiceRefConfig extends WebSecurityConfigurerAdapter {
static InMemoryUserDetailsManager expected = new InMemoryUserDetailsManager([] as Collection)
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(expected)
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
}
@@ -41,145 +41,145 @@ import org.springframework.security.provisioning.JdbcUserDetailsManager
*
*/
class NamespaceJdbcUserServiceTests extends BaseSpringSpec {
def "jdbc-user-service"() {
when:
loadConfig(DataSourceConfig,JdbcUserServiceConfig)
then:
findAuthenticationProvider(DaoAuthenticationProvider).userDetailsService instanceof JdbcUserDetailsManager
}
def "jdbc-user-service"() {
when:
loadConfig(DataSourceConfig,JdbcUserServiceConfig)
then:
findAuthenticationProvider(DaoAuthenticationProvider).userDetailsService instanceof JdbcUserDetailsManager
}
@EnableWebSecurity
static class JdbcUserServiceConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@EnableWebSecurity
static class JdbcUserServiceConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource) // jdbc-user-service@data-source-ref
}
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource) // jdbc-user-service@data-source-ref
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
def "jdbc-user-service in memory testing sample"() {
when:
loadConfig(DataSourceConfig,JdbcUserServiceInMemorySampleConfig)
then:
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
auth.authorities.collect {it.authority} == ['ROLE_USER']
auth.name == "user"
}
def "jdbc-user-service in memory testing sample"() {
when:
loadConfig(DataSourceConfig,JdbcUserServiceInMemorySampleConfig)
then:
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
auth.authorities.collect {it.authority} == ['ROLE_USER']
auth.name == "user"
}
@EnableWebSecurity
static class JdbcUserServiceInMemorySampleConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@EnableWebSecurity
static class JdbcUserServiceInMemorySampleConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource)
// imports the default schema (will fail if already exists)
.withDefaultSchema()
// adds this user automatically (will fail if already exists)
.withUser("user")
.password("password")
.roles("USER")
}
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource)
// imports the default schema (will fail if already exists)
.withDefaultSchema()
// adds this user automatically (will fail if already exists)
.withUser("user")
.password("password")
.roles("USER")
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
}
@Configuration
static class DataSourceConfig {
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
}
@Configuration
static class DataSourceConfig {
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
}
def "jdbc-user-service custom"() {
when:
loadConfig(CustomDataSourceConfig,CustomJdbcUserServiceSampleConfig)
then:
findAuthenticationProvider(DaoAuthenticationProvider).userDetailsService.userCache instanceof CustomUserCache
when:
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
then:
auth.authorities.collect {it.authority}.sort() == ['ROLE_DBA','ROLE_USER']
auth.name == 'user'
}
def "jdbc-user-service custom"() {
when:
loadConfig(CustomDataSourceConfig,CustomJdbcUserServiceSampleConfig)
then:
findAuthenticationProvider(DaoAuthenticationProvider).userDetailsService.userCache instanceof CustomUserCache
when:
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
then:
auth.authorities.collect {it.authority}.sort() == ['ROLE_DBA','ROLE_USER']
auth.name == 'user'
}
@EnableWebSecurity
static class CustomJdbcUserServiceSampleConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@EnableWebSecurity
static class CustomJdbcUserServiceSampleConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
// jdbc-user-service@dataSource
.dataSource(dataSource)
// jdbc-user-service@cache-ref
.userCache(new CustomUserCache())
// jdbc-user-service@users-byusername-query
.usersByUsernameQuery("select principal,credentials,true from users where principal = ?")
// jdbc-user-service@authorities-by-username-query
.authoritiesByUsernameQuery("select principal,role from roles where principal = ?")
// jdbc-user-service@group-authorities-by-username-query
.groupAuthoritiesByUsername(JdbcUserDetailsManager.DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY)
// jdbc-user-service@role-prefix
.rolePrefix("ROLE_")
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
// jdbc-user-service@dataSource
.dataSource(dataSource)
// jdbc-user-service@cache-ref
.userCache(new CustomUserCache())
// jdbc-user-service@users-byusername-query
.usersByUsernameQuery("select principal,credentials,true from users where principal = ?")
// jdbc-user-service@authorities-by-username-query
.authoritiesByUsernameQuery("select principal,role from roles where principal = ?")
// jdbc-user-service@group-authorities-by-username-query
.groupAuthoritiesByUsername(JdbcUserDetailsManager.DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY)
// jdbc-user-service@role-prefix
.rolePrefix("ROLE_")
}
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
// Only necessary to have access to verify the AuthenticationManager
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
static class CustomUserCache implements UserCache {
static class CustomUserCache implements UserCache {
@Override
public UserDetails getUserFromCache(String username) {
return null;
}
@Override
public UserDetails getUserFromCache(String username) {
return null;
}
@Override
public void putUserInCache(UserDetails user) {
}
@Override
public void putUserInCache(UserDetails user) {
}
@Override
public void removeUserFromCache(String username) {
}
}
}
@Override
public void removeUserFromCache(String username) {
}
}
}
@Configuration
static class CustomDataSourceConfig {
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
// simulate that the DB already has the schema loaded and users in it
.addScript("CustomJdbcUserServiceSampleConfig.sql")
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
}
@Configuration
static class CustomDataSourceConfig {
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
// simulate that the DB already has the schema loaded and users in it
.addScript("CustomJdbcUserServiceSampleConfig.sql")
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
}
}
@@ -43,78 +43,78 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager
*
*/
class NamespacePasswordEncoderTests extends BaseSpringSpec {
def "password-encoder@ref with in memory"() {
when:
loadConfig(PasswordEncoderWithInMemoryConfig)
then:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
}
def "password-encoder@ref with in memory"() {
when:
loadConfig(PasswordEncoderWithInMemoryConfig)
then:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
}
@EnableWebSecurity
static class PasswordEncoderWithInMemoryConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
@EnableWebSecurity
static class PasswordEncoderWithInMemoryConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder()
auth
.inMemoryAuthentication()
.withUser("user").password(encoder.encode("password")).roles("USER").and()
.passwordEncoder(encoder)
}
}
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder()
auth
.inMemoryAuthentication()
.withUser("user").password(encoder.encode("password")).roles("USER").and()
.passwordEncoder(encoder)
}
}
def "password-encoder@ref with jdbc"() {
when:
loadConfig(PasswordEncoderWithJdbcConfig)
then:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
}
def "password-encoder@ref with jdbc"() {
when:
loadConfig(PasswordEncoderWithJdbcConfig)
then:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
}
@EnableWebSecurity
static class PasswordEncoderWithJdbcConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
@EnableWebSecurity
static class PasswordEncoderWithJdbcConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder()
auth
.jdbcAuthentication()
.withDefaultSchema()
.dataSource(dataSource())
.withUser("user").password(encoder.encode("password")).roles("USER").and()
.passwordEncoder(encoder)
}
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder()
auth
.jdbcAuthentication()
.withDefaultSchema()
.dataSource(dataSource())
.withUser("user").password(encoder.encode("password")).roles("USER").and()
.passwordEncoder(encoder)
}
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
}
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
}
def "password-encoder@ref with userdetailsservice"() {
when:
loadConfig(PasswordEncoderWithUserDetailsServiceConfig)
then:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
}
def "password-encoder@ref with userdetailsservice"() {
when:
loadConfig(PasswordEncoderWithUserDetailsServiceConfig)
then:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
}
@EnableWebSecurity
static class PasswordEncoderWithUserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
@EnableWebSecurity
static class PasswordEncoderWithUserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder()
User user = new User("user",encoder.encode("password"), AuthorityUtils.createAuthorityList("ROLE_USER"))
InMemoryUserDetailsManager uds = new InMemoryUserDetailsManager([user])
auth
.userDetailsService(uds)
.passwordEncoder(encoder)
}
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder()
User user = new User("user",encoder.encode("password"), AuthorityUtils.createAuthorityList("ROLE_USER"))
InMemoryUserDetailsManager uds = new InMemoryUserDetailsManager([user])
auth
.userDetailsService(uds)
.passwordEncoder(encoder)
}
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
}
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
}
}
@@ -44,18 +44,18 @@ import org.springframework.test.util.ReflectionTestUtils;
*
*/
class PasswordEncoderConfigurerTests extends BaseSpringSpec {
def "password-encoder@ref with No AuthenticationManager Bean"() {
when:
loadConfig(PasswordEncoderNoAuthManagerLoadsConfig)
then:
noExceptionThrown()
}
def "password-encoder@ref with No AuthenticationManager Bean"() {
when:
loadConfig(PasswordEncoderNoAuthManagerLoadsConfig)
then:
noExceptionThrown()
}
def "password-encoder@ref with AuthenticationManagerBuilder"() {
when:
loadConfig(PasswordEncoderConfig)
AuthenticationManager authMgr = authenticationManager()
then:
authMgr.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
}
def "password-encoder@ref with AuthenticationManagerBuilder"() {
when:
loadConfig(PasswordEncoderConfig)
AuthenticationManager authMgr = authenticationManager()
then:
authMgr.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
}
}
@@ -50,320 +50,320 @@ 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()
}
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
@Import([GlobalMethodSecurityAutowiredConfig,ServicesConfig])
static class GlobalMethodSecurityAutowiredConfigAndServicesConfig {}
@EnableGlobalMethodSecurity(securedEnabled = true)
static class GlobalMethodSecurityAutowiredConfig {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
}
}
@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()
}
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
@Import([GlobalMethodSecurityConfig,WebSecurityConfig,ServicesConfig])
static class GlobalMethodSecurityConfigAndServicesConfig {}
@EnableGlobalMethodSecurity(securedEnabled = true)
static class GlobalMethodSecurityConfig {}
@EnableGlobalMethodSecurity(securedEnabled = true)
static class GlobalMethodSecurityConfig {}
@EnableWebSecurity
static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
}
}
@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()
}
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
@Import([GlobalMethodSecurityConfig,WebMvcSecurityConfig,ServicesConfig])
static class GlobalMethodSecurityMvcSecurityAndServicesConfig {}
@EnableWebSecurity
static class WebMvcSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER")
}
}
@EnableWebSecurity
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 "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
}
def "QuiesentGlobalAuthenticationConfiguererAdapter falls back to null"() {
when:
loadConfig(AuthenticationConfiguration,ObjectPostProcessorConfiguration,QuiesentGlobalAuthenticationConfiguererAdapter)
then:
context.getBean(AuthenticationConfiguration).authenticationManager == null
}
@Configuration
static class QuiesentGlobalAuthenticationConfiguererAdapter extends GlobalAuthenticationConfigurerAdapter {}
@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"
}
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")
}
}
@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
}
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 AuthenticationManagerBeanConfig {
static AuthenticationManager AM
@Bean
public AuthenticationManager authenticationManager() {
AM
}
}
//
//
@Configuration
static class ServicesConfig {
@Bean
public Service service() {
return new ServiceImpl()
}
}
@Configuration
static class ServicesConfig {
@Bean
public Service service() {
return new ServiceImpl()
}
}
static interface Service {
public void run();
}
static interface Service {
public void run();
}
static class ServiceImpl implements Service {
@Secured("ROLE_USER")
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]
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 = []
static class DefaultOrderGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
static List inits = []
static List configs = []
public void init(AuthenticationManagerBuilder auth) throws Exception {
inits.add(getClass())
}
public void init(AuthenticationManagerBuilder auth) throws Exception {
inits.add(getClass())
}
public void configure(AuthenticationManagerBuilder auth) throws Exception {
configs.add(getClass())
}
}
public void configure(AuthenticationManagerBuilder auth) throws Exception {
configs.add(getClass())
}
}
@Order(Ordered.LOWEST_PRECEDENCE)
static class LowestOrderGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {}
@Order(Ordered.LOWEST_PRECEDENCE)
static class LowestOrderGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {}
@Order(Ordered.HIGHEST_PRECEDENCE)
static class HighestOrderGlobalAuthenticationConfigurerAdapter 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 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()
}
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 {
static class ConfiguresInMemoryConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
}
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())
}
}
@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;
}
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"))
User user = new User("boot","password", AuthorityUtils.createAuthorityList("ROLE_USER"))
List<User> users = Arrays.asList(user);
InMemoryUserDetailsManager inMemory = new InMemoryUserDetailsManager(users);
List<User> users = Arrays.asList(user);
InMemoryUserDetailsManager inMemory = new InMemoryUserDetailsManager(users);
DaoAuthenticationProvider provider = new DaoAuthenticationProvider()
provider.userDetailsService = inMemory
DaoAuthenticationProvider provider = new DaoAuthenticationProvider()
provider.userDetailsService = inMemory
auth.authenticationProvider(provider)
}
}
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]
}
}
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
@Configuration
@Import(AuthenticationConfiguration)
static class Sec2531Config {
static ObjectPostProcessor opp
@Bean
public ObjectPostProcessor objectPostProcessor() {
opp
}
@Bean
public ObjectPostProcessor objectPostProcessor() {
opp
}
@Bean
public AuthenticationManager manager() {
null
}
}
@Bean
public AuthenticationManager manager() {
null
}
}
def "SEC-2822: Cannot Force Authentication already built"() {
setup:
loadConfig(Sec2822WebSecurity,Sec2822UseAuth,Sec2822Config)
when:
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
config.getAuthenticationManager()
then:
noExceptionThrown()
}
def "SEC-2822: Cannot Force Authentication already built"() {
setup:
loadConfig(Sec2822WebSecurity,Sec2822UseAuth,Sec2822Config)
when:
AuthenticationConfiguration config = context.getBean(AuthenticationConfiguration)
config.getAuthenticationManager()
then:
noExceptionThrown()
}
@Configuration
@Import(AuthenticationConfiguration)
static class Sec2822Config {}
@Configuration
@Import(AuthenticationConfiguration)
static class Sec2822Config {}
@Configuration
@EnableWebSecurity
static class Sec2822WebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.inMemoryAuthentication()
}
}
@Configuration
@EnableWebSecurity
static class Sec2822WebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.inMemoryAuthentication()
}
}
@Configuration
static class Sec2822UseAuth {
@Autowired
public void useAuthenticationManager(AuthenticationConfiguration auth) {
auth.authenticationManager
}
@Configuration
static class Sec2822UseAuth {
@Autowired
public void useAuthenticationManager(AuthenticationConfiguration auth) {
auth.authenticationManager
}
// Ensures that Sec2822UseAuth is initialized before Sec2822WebSecurity
// must have additional GlobalAuthenticationConfigurerAdapter to trigger SEC-2822
@Bean
public static GlobalAuthenticationConfigurerAdapter bootGlobalAuthenticationConfigurerAdapter() {
new BootGlobalAuthenticationConfigurerAdapter()
}
// Ensures that Sec2822UseAuth is initialized before Sec2822WebSecurity
// must have additional GlobalAuthenticationConfigurerAdapter to trigger SEC-2822
@Bean
public static GlobalAuthenticationConfigurerAdapter bootGlobalAuthenticationConfigurerAdapter() {
new BootGlobalAuthenticationConfigurerAdapter()
}
static class BootGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter { }
}
static class BootGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter { }
}
}
@@ -42,100 +42,100 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon
*/
class AutowireBeanFactoryObjectPostProcessorTests extends BaseSpringSpec {
def "Verify All Aware methods are invoked"() {
setup:
ApplicationContextAware contextAware = Mock(ApplicationContextAware)
ApplicationEventPublisherAware publisher = Mock(ApplicationEventPublisherAware)
BeanClassLoaderAware classloader = Mock(BeanClassLoaderAware)
BeanFactoryAware beanFactory = Mock(BeanFactoryAware)
EnvironmentAware environment = Mock(EnvironmentAware)
MessageSourceAware messageSource = Mock(MessageSourceAware)
ServletConfigAware servletConfig = Mock(ServletConfigAware)
ServletContextAware servletContext = Mock(ServletContextAware)
DisposableBean disposable = Mock(DisposableBean)
def "Verify All Aware methods are invoked"() {
setup:
ApplicationContextAware contextAware = Mock(ApplicationContextAware)
ApplicationEventPublisherAware publisher = Mock(ApplicationEventPublisherAware)
BeanClassLoaderAware classloader = Mock(BeanClassLoaderAware)
BeanFactoryAware beanFactory = Mock(BeanFactoryAware)
EnvironmentAware environment = Mock(EnvironmentAware)
MessageSourceAware messageSource = Mock(MessageSourceAware)
ServletConfigAware servletConfig = Mock(ServletConfigAware)
ServletContextAware servletContext = Mock(ServletContextAware)
DisposableBean disposable = Mock(DisposableBean)
context = new AnnotationConfigWebApplicationContext([servletConfig:new MockServletConfig(),servletContext:new MockServletContext()])
context.register(Config)
context.refresh()
context.start()
context = new AnnotationConfigWebApplicationContext([servletConfig:new MockServletConfig(),servletContext:new MockServletContext()])
context.register(Config)
context.refresh()
context.start()
ObjectPostProcessor opp = context.getBean(ObjectPostProcessor)
when:
opp.postProcess(contextAware)
then:
1 * contextAware.setApplicationContext(!null)
ObjectPostProcessor opp = context.getBean(ObjectPostProcessor)
when:
opp.postProcess(contextAware)
then:
1 * contextAware.setApplicationContext(!null)
when:
opp.postProcess(publisher)
then:
1 * publisher.setApplicationEventPublisher(!null)
when:
opp.postProcess(publisher)
then:
1 * publisher.setApplicationEventPublisher(!null)
when:
opp.postProcess(classloader)
then:
1 * classloader.setBeanClassLoader(!null)
when:
opp.postProcess(classloader)
then:
1 * classloader.setBeanClassLoader(!null)
when:
opp.postProcess(beanFactory)
then:
1 * beanFactory.setBeanFactory(!null)
when:
opp.postProcess(beanFactory)
then:
1 * beanFactory.setBeanFactory(!null)
when:
opp.postProcess(environment)
then:
1 * environment.setEnvironment(!null)
when:
opp.postProcess(environment)
then:
1 * environment.setEnvironment(!null)
when:
opp.postProcess(messageSource)
then:
1 * messageSource.setMessageSource(!null)
when:
opp.postProcess(messageSource)
then:
1 * messageSource.setMessageSource(!null)
when:
opp.postProcess(servletConfig)
then:
1 * servletConfig.setServletConfig(!null)
when:
opp.postProcess(servletConfig)
then:
1 * servletConfig.setServletConfig(!null)
when:
opp.postProcess(servletContext)
then:
1 * servletContext.setServletContext(!null)
when:
opp.postProcess(servletContext)
then:
1 * servletContext.setServletContext(!null)
when:
opp.postProcess(disposable)
context.close()
context = null
then:
1 * disposable.destroy()
}
when:
opp.postProcess(disposable)
context.close()
context = null
then:
1 * disposable.destroy()
}
@Configuration
static class Config {
@Bean
public ObjectPostProcessor objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
}
}
@Configuration
static class Config {
@Bean
public ObjectPostProcessor objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
}
}
def "SEC-2382: AutowireBeanFactoryObjectPostProcessor works with BeanNameAutoProxyCreator"() {
when:
// must load with XML for BeanPostProcessors to work
context = new ClassPathXmlApplicationContext("AutowireBeanFactoryObjectPostProcessorTests-aopconfig.xml", getClass());
then:
noExceptionThrown()
and: "make sure autoproxying was actually enabled"
context.getBean(MyAdvisedBean).doStuff() == "null"
}
def "SEC-2382: AutowireBeanFactoryObjectPostProcessor works with BeanNameAutoProxyCreator"() {
when:
// must load with XML for BeanPostProcessors to work
context = new ClassPathXmlApplicationContext("AutowireBeanFactoryObjectPostProcessorTests-aopconfig.xml", getClass());
then:
noExceptionThrown()
and: "make sure autoproxying was actually enabled"
context.getBean(MyAdvisedBean).doStuff() == "null"
}
@Configuration
static class WithBanNameAutoProxyCreatorConfig {
@Bean
public ObjectPostProcessor objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
return new AutowireBeanFactoryObjectPostProcessor(beanFactory)
}
@Configuration
static class WithBanNameAutoProxyCreatorConfig {
@Bean
public ObjectPostProcessor objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
return new AutowireBeanFactoryObjectPostProcessor(beanFactory)
}
@Autowired
public void configure(ObjectPostProcessor<Object> p) {
p.postProcess(new Object())
}
}
@Autowired
public void configure(ObjectPostProcessor<Object> p) {
p.postProcess(new Object())
}
}
}
@@ -15,6 +15,9 @@
*/
package org.springframework.security.config.annotation.method.configuration
import java.lang.reflect.Proxy;
import org.junit.After;
import org.springframework.beans.BeansException
import org.springframework.beans.factory.config.BeanPostProcessor
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter
@@ -29,6 +32,7 @@ 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.AdviceMode
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@@ -44,357 +48,384 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
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.method.TestPermissionEvaluator;
import org.springframework.security.core.Authentication
import org.springframework.security.core.authority.AuthorityUtils
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
*
* @author Rob Winch
*/
public class GlobalMethodSecurityConfigurationTests extends BaseSpringSpec {
def "messages set when using GlobalMethodSecurityConfiguration"() {
when:
loadConfig(InMemoryAuthWithGlobalMethodSecurityConfig)
then:
authenticationManager.messages.messageSource instanceof ApplicationContext
}
def "messages set when using GlobalMethodSecurityConfiguration"() {
when:
loadConfig(InMemoryAuthWithGlobalMethodSecurityConfig)
then:
authenticationManager.messages.messageSource instanceof ApplicationContext
}
def "AuthenticationEventPublisher is registered GlobalMethodSecurityConfiguration"() {
when:
loadConfig(InMemoryAuthWithGlobalMethodSecurityConfig)
then:
authenticationManager.eventPublisher instanceof DefaultAuthenticationEventPublisher
when:
Authentication auth = new UsernamePasswordAuthenticationToken("user",null,AuthorityUtils.createAuthorityList("ROLE_USER"))
authenticationManager.eventPublisher.publishAuthenticationSuccess(auth)
then:
InMemoryAuthWithGlobalMethodSecurityConfig.EVENT.authentication == auth
}
def "AuthenticationEventPublisher is registered GlobalMethodSecurityConfiguration"() {
when:
loadConfig(InMemoryAuthWithGlobalMethodSecurityConfig)
then:
authenticationManager.eventPublisher instanceof DefaultAuthenticationEventPublisher
when:
Authentication auth = new UsernamePasswordAuthenticationToken("user",null,AuthorityUtils.createAuthorityList("ROLE_USER"))
authenticationManager.eventPublisher.publishAuthenticationSuccess(auth)
then:
InMemoryAuthWithGlobalMethodSecurityConfig.EVENT.authentication == auth
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class InMemoryAuthWithGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration implements ApplicationListener<AuthenticationSuccessEvent> {
static AuthenticationSuccessEvent EVENT
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class InMemoryAuthWithGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration implements ApplicationListener<AuthenticationSuccessEvent> {
static AuthenticationSuccessEvent EVENT
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Override
public void onApplicationEvent(AuthenticationSuccessEvent e) {
EVENT = e
}
}
@Override
public void onApplicationEvent(AuthenticationSuccessEvent e) {
EVENT = e
}
}
AuthenticationManager getAuthenticationManager() {
context.getBean(MethodInterceptor).authenticationManager
}
AuthenticationManager getAuthenticationManager() {
context.getBean(MethodInterceptor).authenticationManager
}
def "AuthenticationTrustResolver autowires"() {
setup:
CustomTrustResolverConfig.TR = Mock(AuthenticationTrustResolver)
when:
loadConfig(CustomTrustResolverConfig)
def preAdviceVoter = context.getBean(MethodInterceptor).accessDecisionManager.decisionVoters.find { it instanceof PreInvocationAuthorizationAdviceVoter}
then:
preAdviceVoter.preAdvice.expressionHandler.trustResolver == CustomTrustResolverConfig.TR
}
def "AuthenticationTrustResolver autowires"() {
setup:
CustomTrustResolverConfig.TR = Mock(AuthenticationTrustResolver)
when:
loadConfig(CustomTrustResolverConfig)
def preAdviceVoter = context.getBean(MethodInterceptor).accessDecisionManager.decisionVoters.find { it instanceof PreInvocationAuthorizationAdviceVoter}
then:
preAdviceVoter.preAdvice.expressionHandler.trustResolver == CustomTrustResolverConfig.TR
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class CustomTrustResolverConfig extends GlobalMethodSecurityConfiguration {
static AuthenticationTrustResolver TR
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class CustomTrustResolverConfig extends GlobalMethodSecurityConfiguration {
static AuthenticationTrustResolver TR
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Bean
public AuthenticationTrustResolver tr() {
return TR
}
}
@Bean
public AuthenticationTrustResolver tr() {
return TR
}
}
def "SEC-2301: DefaultWebSecurityExpressionHandler has BeanResolver set"() {
setup:
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
loadConfig(ExpressionHandlerHasBeanResolverSetConfig)
def service = context.getBean(ServiceImpl)
when: "service with bean reference on PreAuthorize invoked"
service.message()
then: "properly throws AccessDeniedException"
thrown(AccessDeniedException)
when: "service with bean reference on PreAuthorize invoked"
context.getBean(CustomAuthzService).grantAccess = true
service.message()
then: "grants access too"
noExceptionThrown()
}
def "SEC-2301: DefaultWebSecurityExpressionHandler has BeanResolver set"() {
setup:
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
loadConfig(ExpressionHandlerHasBeanResolverSetConfig)
def service = context.getBean(ServiceImpl)
when: "service with bean reference on PreAuthorize invoked"
service.message()
then: "properly throws AccessDeniedException"
thrown(AccessDeniedException)
when: "service with bean reference on PreAuthorize invoked"
context.getBean(CustomAuthzService).grantAccess = true
service.message()
then: "grants access too"
noExceptionThrown()
}
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
static class ExpressionHandlerHasBeanResolverSetConfig extends GlobalMethodSecurityConfiguration {
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
static class ExpressionHandlerHasBeanResolverSetConfig extends GlobalMethodSecurityConfiguration {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Bean
public ServiceImpl service() {
return new ServiceImpl()
}
@Bean
public ServiceImpl service() {
return new ServiceImpl()
}
@Bean
public CustomAuthzService authz() {
return new CustomAuthzService()
}
}
@Bean
public CustomAuthzService authz() {
return new CustomAuthzService()
}
}
static class ServiceImpl {
@PreAuthorize("@authz.authorize()")
public String message() {
null
}
}
static class ServiceImpl {
@PreAuthorize("@authz.authorize()")
public String message() {
null
}
}
static class CustomAuthzService {
boolean grantAccess
static class CustomAuthzService {
boolean grantAccess
public boolean authorize() {
grantAccess
}
}
public boolean authorize() {
grantAccess
}
}
def "Method Security supports annotations on interface parameter names"() {
setup:
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
loadConfig(MethodSecurityServiceConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when: "service with annotated argument"
service.postAnnotation('deny')
then: "properly throws AccessDeniedException"
thrown(AccessDeniedException)
when: "service with annotated argument"
service.postAnnotation('grant')
then: "properly throws AccessDeniedException"
noExceptionThrown()
}
def "Method Security supports annotations on interface parameter names"() {
setup:
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
loadConfig(MethodSecurityServiceConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when: "service with annotated argument"
service.postAnnotation('deny')
then: "properly throws AccessDeniedException"
thrown(AccessDeniedException)
when: "service with annotated argument"
service.postAnnotation('grant')
then: "properly throws AccessDeniedException"
noExceptionThrown()
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class MethodSecurityServiceConfig extends GlobalMethodSecurityConfiguration {
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class MethodSecurityServiceConfig extends GlobalMethodSecurityConfiguration {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Bean
public MethodSecurityService service() {
new MethodSecurityServiceImpl()
}
}
@Bean
public MethodSecurityService service() {
new MethodSecurityServiceImpl()
}
}
def "GlobalMethodSecurityConfiguration autowires PermissionEvaluator"() {
setup:
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
PermissionEvaluator evaluator = Mock()
AutowirePermissionEvaluatorConfig.PE = evaluator
loadConfig(AutowirePermissionEvaluatorConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.hasPermission("something")
then:
1 * evaluator.hasPermission(_, "something", "read") >> true
when:
service.hasPermission("something")
then:
1 * evaluator.hasPermission(_, "something", "read") >> false
thrown(AccessDeniedException)
}
def "GlobalMethodSecurityConfiguration autowires PermissionEvaluator"() {
setup:
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
PermissionEvaluator evaluator = Mock()
AutowirePermissionEvaluatorConfig.PE = evaluator
loadConfig(AutowirePermissionEvaluatorConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.hasPermission("something")
then:
1 * evaluator.hasPermission(_, "something", "read") >> true
when:
service.hasPermission("something")
then:
1 * evaluator.hasPermission(_, "something", "read") >> false
thrown(AccessDeniedException)
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class AutowirePermissionEvaluatorConfig extends GlobalMethodSecurityConfiguration {
static PermissionEvaluator PE
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class AutowirePermissionEvaluatorConfig extends GlobalMethodSecurityConfiguration {
static PermissionEvaluator PE
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Bean
public PermissionEvaluator pe() {
PE
}
@Bean
public PermissionEvaluator pe() {
PE
}
@Bean
public MethodSecurityService service() {
new MethodSecurityServiceImpl()
}
}
@Bean
public MethodSecurityService service() {
new MethodSecurityServiceImpl()
}
}
def "GlobalMethodSecurityConfiguration does not failw with multiple PermissionEvaluator"() {
when:
loadConfig(MultiPermissionEvaluatorConfig)
then:
noExceptionThrown()
}
def "GlobalMethodSecurityConfiguration does not failw with multiple PermissionEvaluator"() {
when:
loadConfig(MultiPermissionEvaluatorConfig)
then:
noExceptionThrown()
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class MultiPermissionEvaluatorConfig extends GlobalMethodSecurityConfiguration {
static PermissionEvaluator PE
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class MultiPermissionEvaluatorConfig extends GlobalMethodSecurityConfiguration {
static PermissionEvaluator PE = new TestPermissionEvaluator()
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Bean
public PermissionEvaluator pe() {
PE
}
@Bean
public PermissionEvaluator pe() {
PE
}
@Bean
public PermissionEvaluator pe2() {
PE
}
@Bean
public PermissionEvaluator pe2() {
PE
}
@Bean
public MethodSecurityService service() {
new MethodSecurityServiceImpl()
}
}
@Bean
public MethodSecurityService service() {
new MethodSecurityServiceImpl()
}
}
def "SEC-2425: EnableGlobalMethodSecurity works on superclass"() {
setup:
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
loadConfig(ParentConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
}
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 {}
static class ChildConfig extends ParentConfig {}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class ParentConfig {
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class ParentConfig {
@Autowired
protected void configurGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Autowired
protected void configurGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Bean
public MethodSecurityService service() {
new MethodSecurityServiceImpl()
}
}
@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()
}
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
@Configuration
static class Sec2479ParentConfig {
static AuthenticationManager AM
@Bean
public AuthenticationManager am() {
AM
}
}
@Bean
public AuthenticationManager am() {
AM
}
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class Sec2479ChildConfig {
@Bean
public MethodSecurityService service() {
new MethodSecurityServiceImpl()
}
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class Sec2479ChildConfig {
@Bean
public MethodSecurityService service() {
new MethodSecurityServiceImpl()
}
}
def "SEC-2815: @EnableGlobalMethodSecurity does not trigger eager initialization of Beans in GlobalAuthenticationConfigurer"() {
setup:
Sec2815Config.dataSource = Mock(DataSource)
when: 'load a Configuration that uses a Bean (DataSource) in a GlobalAuthenticationConfigurerAdapter'
loadConfig(Sec2815Config)
then: 'The Bean (DataSource) is still properly post processed with all BeanPostProcessor'
context.getBean(MockBeanPostProcessor).beforeInit['dataSource']
context.getBean(MockBeanPostProcessor).afterInit['dataSource']
}
def "SEC-2815: @EnableGlobalMethodSecurity does not trigger eager initialization of Beans in GlobalAuthenticationConfigurer"() {
setup:
Sec2815Config.dataSource = Mock(DataSource)
when: 'load a Configuration that uses a Bean (DataSource) in a GlobalAuthenticationConfigurerAdapter'
loadConfig(Sec2815Config)
then: 'The Bean (DataSource) is still properly post processed with all BeanPostProcessor'
context.getBean(MockBeanPostProcessor).beforeInit['dataSource']
context.getBean(MockBeanPostProcessor).afterInit['dataSource']
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class Sec2815Config {
static DataSource dataSource;
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class Sec2815Config {
static DataSource dataSource;
@Bean
public MethodSecurityService service() {
new MethodSecurityServiceImpl()
}
@Bean
public MethodSecurityService service() {
new MethodSecurityServiceImpl()
}
@Bean
public MockBeanPostProcessor mockBeanPostProcessor() {
new MockBeanPostProcessor()
}
@Bean
public MockBeanPostProcessor mockBeanPostProcessor() {
new MockBeanPostProcessor()
}
@Bean
public DataSource dataSource() {
dataSource
}
@Bean
public DataSource dataSource() {
dataSource
}
@Configuration
static class AuthConfig extends GlobalAuthenticationConfigurerAdapter {
@Autowired
DataSource dataSource
@Configuration
static class AuthConfig extends GlobalAuthenticationConfigurerAdapter {
@Autowired
DataSource dataSource
@Override
void init(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
}
}
}
@Override
void init(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
}
}
}
static class MockBeanPostProcessor implements BeanPostProcessor {
Map<String,Object> beforeInit = new HashMap<String,Object>()
Map<String,Object> afterInit = new HashMap<String,Object>()
static class MockBeanPostProcessor implements BeanPostProcessor {
Map<String,Object> beforeInit = new HashMap<String,Object>()
Map<String,Object> afterInit = new HashMap<String,Object>()
@Override
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
beforeInit[beanName] = bean
bean
}
@Override
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
beforeInit[beanName] = bean
bean
}
@Override
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
afterInit[beanName] = bean
bean
}
}
@Override
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
afterInit[beanName] = bean
bean
}
}
def "SEC-3045: Global Security proxies security"() {
setup:
when: 'load a Configuration that uses a Bean (DataSource) in a GlobalAuthenticationConfigurerAdapter'
loadConfig(Sec3005Config)
MethodSecurityService service = context.getBean(MethodSecurityService)
then: 'The Bean (DataSource) is still properly post processed with all BeanPostProcessor'
!Proxy.isProxyClass(service.getClass())
}
@EnableGlobalMethodSecurity(prePostEnabled = true, mode= AdviceMode.ASPECTJ)
@EnableTransactionManagement
static class Sec3005Config {
static DataSource dataSource;
@Bean
public MethodSecurityService service() {
new MethodSecurityServiceImpl()
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.inMemoryAuthentication()
}
}
}
@@ -30,33 +30,33 @@ import org.springframework.security.core.Authentication
* @author Rob Winch
*/
public interface MethodSecurityService {
@PreAuthorize("denyAll")
public String preAuthorize();
@PreAuthorize("denyAll")
public String preAuthorize();
@Secured("ROLE_ADMIN")
public String secured();
@Secured("ROLE_ADMIN")
public String secured();
@Secured("ROLE_USER")
public String securedUser();
@Secured("ROLE_USER")
public String securedUser();
@DenyAll
public String jsr250();
@DenyAll
public String jsr250();
@PermitAll
public String jsr250PermitAll();
@PermitAll
public String jsr250PermitAll();
@Secured(["ROLE_USER","RUN_AS_SUPER"])
public Authentication runAs();
@Secured(["ROLE_USER","RUN_AS_SUPER"])
public Authentication runAs();
@PreAuthorize("permitAll")
public String preAuthorizePermitAll();
@PreAuthorize("permitAll")
public String preAuthorizePermitAll();
@PreAuthorize("hasPermission(#object,'read')")
public String hasPermission(String object);
@PreAuthorize("hasPermission(#object,'read')")
public String hasPermission(String object);
@PostAuthorize("hasPermission(#object,'read')")
public String postHasPermission(String object);
@PostAuthorize("hasPermission(#object,'read')")
public String postHasPermission(String object);
@PostAuthorize("#o?.contains('grant')")
public String postAnnotation(@P("o") String object);
@PostAuthorize("#o?.contains('grant')")
public String postAnnotation(@P("o") String object);
}
@@ -25,53 +25,53 @@ import org.springframework.security.core.context.SecurityContextHolder
*/
public class MethodSecurityServiceImpl implements MethodSecurityService {
@Override
public String preAuthorize() {
return null;
}
@Override
public String preAuthorize() {
return null;
}
@Override
public String secured() {
return null;
}
@Override
public String secured() {
return null;
}
@Override
public String securedUser() {
return null;
}
@Override
public String securedUser() {
return null;
}
@Override
public String jsr250() {
return null;
}
@Override
public String jsr250() {
return null;
}
@Override
public String jsr250PermitAll() {
return null;
}
@Override
public String jsr250PermitAll() {
return null;
}
@Override
public Authentication runAs() {
return SecurityContextHolder.getContext().getAuthentication();
}
@Override
public Authentication runAs() {
return SecurityContextHolder.getContext().getAuthentication();
}
@Override
public String preAuthorizePermitAll() {
return null;
}
@Override
public String preAuthorizePermitAll() {
return null;
}
@Override
public String hasPermission(String object) {
return null;
}
@Override
public String hasPermission(String object) {
return null;
}
@Override
public String postHasPermission(String object) {
return null;
}
@Override
public String postHasPermission(String object) {
return null;
}
@Override
public String postAnnotation(String object) {
return null;
}
@Override
public String postAnnotation(String object) {
return null;
}
}
@@ -40,53 +40,53 @@ import org.springframework.security.core.context.SecurityContextHolder
* @author Rob Winch
*/
public class NamespaceGlobalMethodSecurityExpressionHandlerTests extends BaseSpringSpec {
def setup() {
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
}
def setup() {
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
}
def "global-method-security/expression-handler @PreAuthorize"() {
setup:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAccessDecisionManagerConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.hasPermission("granted")
then:
noExceptionThrown()
when:
service.hasPermission("denied")
then:
thrown(AccessDeniedException)
}
def "global-method-security/expression-handler @PreAuthorize"() {
setup:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAccessDecisionManagerConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.hasPermission("granted")
then:
noExceptionThrown()
when:
service.hasPermission("denied")
then:
thrown(AccessDeniedException)
}
def "global-method-security/expression-handler @PostAuthorize"() {
setup:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAccessDecisionManagerConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.postHasPermission("granted")
then:
noExceptionThrown()
when:
service.postHasPermission("denied")
then:
thrown(AccessDeniedException)
}
def "global-method-security/expression-handler @PostAuthorize"() {
setup:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAccessDecisionManagerConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.postHasPermission("granted")
then:
noExceptionThrown()
when:
service.postHasPermission("denied")
then:
thrown(AccessDeniedException)
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class CustomAccessDecisionManagerConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler()
expressionHandler.permissionEvaluator = new PermissionEvaluator() {
boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
"granted" == targetDomainObject
}
boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
throw new UnsupportedOperationException()
}
}
return expressionHandler
}
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class CustomAccessDecisionManagerConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler()
expressionHandler.permissionEvaluator = new PermissionEvaluator() {
boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
"granted" == targetDomainObject
}
boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
throw new UnsupportedOperationException()
}
}
return expressionHandler
}
}
}
@@ -57,387 +57,387 @@ import org.springframework.security.core.context.SecurityContextHolder
* @author Rob Winch
*/
public class NamespaceGlobalMethodSecurityTests extends BaseSpringSpec {
def setup() {
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
}
def setup() {
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
}
// --- access-decision-manager-ref ---
// --- access-decision-manager-ref ---
def "custom AccessDecisionManager can be used"() {
setup: "Create an instance with an AccessDecisionManager that always denies access"
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAccessDecisionManagerConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
when:
service.secured()
then:
thrown(AccessDeniedException)
}
def "custom AccessDecisionManager can be used"() {
setup: "Create an instance with an AccessDecisionManager that always denies access"
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAccessDecisionManagerConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
when:
service.secured()
then:
thrown(AccessDeniedException)
}
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public static class CustomAccessDecisionManagerConfig extends GlobalMethodSecurityConfiguration {
@Override
protected AccessDecisionManager accessDecisionManager() {
return new DenyAllAccessDecisionManager()
}
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public static class CustomAccessDecisionManagerConfig extends GlobalMethodSecurityConfiguration {
@Override
protected AccessDecisionManager accessDecisionManager() {
return new DenyAllAccessDecisionManager()
}
public static class DenyAllAccessDecisionManager implements AccessDecisionManager {
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) {
throw new AccessDeniedException("Always Denied")
}
public boolean supports(ConfigAttribute attribute) {
return true
}
public boolean supports(Class<?> clazz) {
return true
}
}
}
public static class DenyAllAccessDecisionManager implements AccessDecisionManager {
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) {
throw new AccessDeniedException("Always Denied")
}
public boolean supports(ConfigAttribute attribute) {
return true
}
public boolean supports(Class<?> clazz) {
return true
}
}
}
// --- authentication-manager-ref ---
// --- authentication-manager-ref ---
def "custom AuthenticationManager can be used"() {
when:
context = new AnnotationConfigApplicationContext(CustomAuthenticationConfig)
MethodSecurityInterceptor interceptor = context.getBean(MethodSecurityInterceptor)
interceptor.authenticationManager.authenticate(SecurityContextHolder.context.authentication)
then:
thrown(UnsupportedOperationException)
}
def "custom AuthenticationManager can be used"() {
when:
context = new AnnotationConfigApplicationContext(CustomAuthenticationConfig)
MethodSecurityInterceptor interceptor = context.getBean(MethodSecurityInterceptor)
interceptor.authenticationManager.authenticate(SecurityContextHolder.context.authentication)
then:
thrown(UnsupportedOperationException)
}
@EnableGlobalMethodSecurity
public static class CustomAuthenticationConfig extends GlobalMethodSecurityConfiguration {
@Override
protected AuthenticationManager authenticationManager() {
return new AuthenticationManager() {
Authentication authenticate(Authentication authentication) {
throw new UnsupportedOperationException()
}
}
}
}
@EnableGlobalMethodSecurity
public static class CustomAuthenticationConfig extends GlobalMethodSecurityConfiguration {
@Override
protected AuthenticationManager authenticationManager() {
return new AuthenticationManager() {
Authentication authenticate(Authentication authentication) {
throw new UnsupportedOperationException()
}
}
}
}
// --- jsr250-annotations ---
// --- jsr250-annotations ---
def "enable jsr250"() {
when:
context = new AnnotationConfigApplicationContext(Jsr250Config)
MethodSecurityService service = context.getBean(MethodSecurityService)
then: "@Secured and @PreAuthorize are ignored"
service.secured() == null
service.preAuthorize() == null
def "enable jsr250"() {
when:
context = new AnnotationConfigApplicationContext(Jsr250Config)
MethodSecurityService service = context.getBean(MethodSecurityService)
then: "@Secured and @PreAuthorize are ignored"
service.secured() == null
service.preAuthorize() == null
when: "@DenyAll method invoked"
service.jsr250()
then: "access is denied"
thrown(AccessDeniedException)
when: "@PermitAll method invoked"
String jsr250PermitAll = service.jsr250PermitAll()
then: "access is allowed"
jsr250PermitAll == null
}
when: "@DenyAll method invoked"
service.jsr250()
then: "access is denied"
thrown(AccessDeniedException)
when: "@PermitAll method invoked"
String jsr250PermitAll = service.jsr250PermitAll()
then: "access is allowed"
jsr250PermitAll == null
}
@EnableGlobalMethodSecurity(jsr250Enabled = true)
@Configuration
public static class Jsr250Config extends BaseMethodConfig {
}
@EnableGlobalMethodSecurity(jsr250Enabled = true)
@Configuration
public static class Jsr250Config extends BaseMethodConfig {
}
// --- metadata-source-ref ---
// --- metadata-source-ref ---
def "custom MethodSecurityMetadataSource can be used with higher priority than other sources"() {
setup:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomMethodSecurityMetadataSourceConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
when:
service.secured()
then:
thrown(AccessDeniedException)
when:
service.jsr250()
then:
thrown(AccessDeniedException)
}
def "custom MethodSecurityMetadataSource can be used with higher priority than other sources"() {
setup:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomMethodSecurityMetadataSourceConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
when:
service.secured()
then:
thrown(AccessDeniedException)
when:
service.jsr250()
then:
thrown(AccessDeniedException)
}
@EnableGlobalMethodSecurity
public static class CustomMethodSecurityMetadataSourceConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
return new AbstractMethodSecurityMetadataSource() {
public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
// require ROLE_NOBODY for any method on MethodSecurityService class
return MethodSecurityService.isAssignableFrom(targetClass) ? [new SecurityConfig("ROLE_NOBODY")] : []
}
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null
}
}
}
}
@EnableGlobalMethodSecurity
public static class CustomMethodSecurityMetadataSourceConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
return new AbstractMethodSecurityMetadataSource() {
public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
// require ROLE_NOBODY for any method on MethodSecurityService class
return MethodSecurityService.isAssignableFrom(targetClass) ? [new SecurityConfig("ROLE_NOBODY")] : []
}
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null
}
}
}
}
// --- mode ---
// --- mode ---
def "aspectj mode works"() {
when:
context = new AnnotationConfigApplicationContext(AspectJModeConfig)
then:
context.getBean(AnnotationSecurityAspect)
context.getBean(AspectJMethodSecurityInterceptor)
}
def "aspectj mode works"() {
when:
context = new AnnotationConfigApplicationContext(AspectJModeConfig)
then:
context.getBean(AnnotationSecurityAspect)
context.getBean(AspectJMethodSecurityInterceptor)
}
@EnableGlobalMethodSecurity(mode = AdviceMode.ASPECTJ, proxyTargetClass = true)
public static class AspectJModeConfig extends BaseMethodConfig {
}
@EnableGlobalMethodSecurity(mode = AdviceMode.ASPECTJ, proxyTargetClass = true)
public static class AspectJModeConfig extends BaseMethodConfig {
}
def "aspectj mode works extending GlobalMethodSecurityConfiguration"() {
when:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,AspectJModeExtendsGMSCConfig)
then:
context.getBean(AnnotationSecurityAspect)
context.getBean(AspectJMethodSecurityInterceptor)
}
def "aspectj mode works extending GlobalMethodSecurityConfiguration"() {
when:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,AspectJModeExtendsGMSCConfig)
then:
context.getBean(AnnotationSecurityAspect)
context.getBean(AspectJMethodSecurityInterceptor)
}
@EnableGlobalMethodSecurity(mode = AdviceMode.ASPECTJ)
public static class AspectJModeExtendsGMSCConfig extends GlobalMethodSecurityConfiguration {
}
@EnableGlobalMethodSecurity(mode = AdviceMode.ASPECTJ)
public static class AspectJModeExtendsGMSCConfig extends GlobalMethodSecurityConfiguration {
}
// --- order ---
// --- order ---
def order() {
when:
context = new AnnotationConfigApplicationContext(CustomOrderConfig)
MethodSecurityMetadataSourceAdvisor advisor = context.getBean(MethodSecurityMetadataSourceAdvisor)
then:
advisor.order == 135
}
def order() {
when:
context = new AnnotationConfigApplicationContext(CustomOrderConfig)
MethodSecurityMetadataSourceAdvisor advisor = context.getBean(MethodSecurityMetadataSourceAdvisor)
then:
advisor.order == 135
}
@EnableGlobalMethodSecurity(order = 135)
public static class CustomOrderConfig extends BaseMethodConfig {
}
@EnableGlobalMethodSecurity(order = 135)
public static class CustomOrderConfig extends BaseMethodConfig {
}
def "order is defaulted to Ordered.LOWEST_PRECEDENCE when using @EnableGlobalMethodSecurity"() {
when:
context = new AnnotationConfigApplicationContext(DefaultOrderConfig)
MethodSecurityMetadataSourceAdvisor advisor = context.getBean(MethodSecurityMetadataSourceAdvisor)
then:
advisor.order == Ordered.LOWEST_PRECEDENCE
}
def "order is defaulted to Ordered.LOWEST_PRECEDENCE when using @EnableGlobalMethodSecurity"() {
when:
context = new AnnotationConfigApplicationContext(DefaultOrderConfig)
MethodSecurityMetadataSourceAdvisor advisor = context.getBean(MethodSecurityMetadataSourceAdvisor)
then:
advisor.order == Ordered.LOWEST_PRECEDENCE
}
@EnableGlobalMethodSecurity
public static class DefaultOrderConfig extends BaseMethodConfig {
}
@EnableGlobalMethodSecurity
public static class DefaultOrderConfig extends BaseMethodConfig {
}
def "order is defaulted to Ordered.LOWEST_PRECEDENCE when extending GlobalMethodSecurityConfiguration"() {
when:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,DefaultOrderExtendsMethodSecurityConfig)
MethodSecurityMetadataSourceAdvisor advisor = context.getBean(MethodSecurityMetadataSourceAdvisor)
then:
advisor.order == Ordered.LOWEST_PRECEDENCE
}
def "order is defaulted to Ordered.LOWEST_PRECEDENCE when extending GlobalMethodSecurityConfiguration"() {
when:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,DefaultOrderExtendsMethodSecurityConfig)
MethodSecurityMetadataSourceAdvisor advisor = context.getBean(MethodSecurityMetadataSourceAdvisor)
then:
advisor.order == Ordered.LOWEST_PRECEDENCE
}
@EnableGlobalMethodSecurity
public static class DefaultOrderExtendsMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
}
@EnableGlobalMethodSecurity
public static class DefaultOrderExtendsMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
}
// --- pre-post-annotations ---
// --- pre-post-annotations ---
def preAuthorize() {
when:
context = new AnnotationConfigApplicationContext(PreAuthorizeConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.secured() == null
service.jsr250() == null
def preAuthorize() {
when:
context = new AnnotationConfigApplicationContext(PreAuthorizeConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.secured() == null
service.jsr250() == null
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
}
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public static class PreAuthorizeConfig extends BaseMethodConfig {
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public static class PreAuthorizeConfig extends BaseMethodConfig {
}
def "prePostEnabled extends GlobalMethodSecurityConfiguration"() {
when:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,PreAuthorizeExtendsGMSCConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.secured() == null
service.jsr250() == null
def "prePostEnabled extends GlobalMethodSecurityConfiguration"() {
when:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,PreAuthorizeExtendsGMSCConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.secured() == null
service.jsr250() == null
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
}
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public static class PreAuthorizeExtendsGMSCConfig extends GlobalMethodSecurityConfiguration {
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public static class PreAuthorizeExtendsGMSCConfig extends GlobalMethodSecurityConfiguration {
}
// --- proxy-target-class ---
// --- proxy-target-class ---
def "proxying classes works"() {
when:
context = new AnnotationConfigApplicationContext(ProxyTargetClass)
MethodSecurityServiceImpl service = context.getBean(MethodSecurityServiceImpl)
then:
noExceptionThrown()
}
def "proxying classes works"() {
when:
context = new AnnotationConfigApplicationContext(ProxyTargetClass)
MethodSecurityServiceImpl service = context.getBean(MethodSecurityServiceImpl)
then:
noExceptionThrown()
}
@EnableGlobalMethodSecurity(proxyTargetClass = true)
@Configuration
public static class ProxyTargetClass extends BaseMethodConfig {
}
@EnableGlobalMethodSecurity(proxyTargetClass = true)
@Configuration
public static class ProxyTargetClass extends BaseMethodConfig {
}
def "proxying interfaces works"() {
when:
context = new AnnotationConfigApplicationContext(PreAuthorizeConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then: "we get an instance of the interface"
noExceptionThrown()
when: "try to cast to the class"
MethodSecurityServiceImpl serviceImpl = service
then: "we get a class cast exception"
thrown(ClassCastException)
}
def "proxying interfaces works"() {
when:
context = new AnnotationConfigApplicationContext(PreAuthorizeConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then: "we get an instance of the interface"
noExceptionThrown()
when: "try to cast to the class"
MethodSecurityServiceImpl serviceImpl = service
then: "we get a class cast exception"
thrown(ClassCastException)
}
// --- run-as-manager-ref ---
// --- run-as-manager-ref ---
def "custom RunAsManager"() {
when:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomRunAsManagerConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.runAs().authorities.find { it.authority == "ROLE_RUN_AS_SUPER"}
}
def "custom RunAsManager"() {
when:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomRunAsManagerConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.runAs().authorities.find { it.authority == "ROLE_RUN_AS_SUPER"}
}
@EnableGlobalMethodSecurity(securedEnabled = true)
public static class CustomRunAsManagerConfig extends GlobalMethodSecurityConfiguration {
@Override
protected RunAsManager runAsManager() {
RunAsManagerImpl runAsManager = new RunAsManagerImpl()
runAsManager.setKey("some key")
return runAsManager
}
}
@EnableGlobalMethodSecurity(securedEnabled = true)
public static class CustomRunAsManagerConfig extends GlobalMethodSecurityConfiguration {
@Override
protected RunAsManager runAsManager() {
RunAsManagerImpl runAsManager = new RunAsManagerImpl()
runAsManager.setKey("some key")
return runAsManager
}
}
// --- secured-annotation ---
// --- secured-annotation ---
def "secured enabled"() {
setup:
context = new AnnotationConfigApplicationContext(SecuredConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.secured()
then:
thrown(AccessDeniedException)
and: "service with ROLE_USER allowed"
service.securedUser() == null
and:
service.preAuthorize() == null
service.jsr250() == null
}
def "secured enabled"() {
setup:
context = new AnnotationConfigApplicationContext(SecuredConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.secured()
then:
thrown(AccessDeniedException)
and: "service with ROLE_USER allowed"
service.securedUser() == null
and:
service.preAuthorize() == null
service.jsr250() == null
}
@EnableGlobalMethodSecurity(securedEnabled = true)
@Configuration
public static class SecuredConfig extends BaseMethodConfig {
}
@EnableGlobalMethodSecurity(securedEnabled = true)
@Configuration
public static class SecuredConfig extends BaseMethodConfig {
}
// --- after-invocation-provider
// --- after-invocation-provider
def "custom AfterInvocationManager"() {
setup:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAfterInvocationManagerConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.preAuthorizePermitAll()
then:
AccessDeniedException e = thrown()
e.message == "custom AfterInvocationManager"
}
def "custom AfterInvocationManager"() {
setup:
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomAfterInvocationManagerConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
when:
service.preAuthorizePermitAll()
then:
AccessDeniedException e = thrown()
e.message == "custom AfterInvocationManager"
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class CustomAfterInvocationManagerConfig extends GlobalMethodSecurityConfiguration {
@Override
protected AfterInvocationManager afterInvocationManager() {
return new AfterInvocationManagerStub()
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class CustomAfterInvocationManagerConfig extends GlobalMethodSecurityConfiguration {
@Override
protected AfterInvocationManager afterInvocationManager() {
return new AfterInvocationManagerStub()
}
public static class AfterInvocationManagerStub implements AfterInvocationManager {
Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> attributes,
Object returnedObject) throws AccessDeniedException {
throw new AccessDeniedException("custom AfterInvocationManager")
}
public static class AfterInvocationManagerStub implements AfterInvocationManager {
Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> attributes,
Object returnedObject) throws AccessDeniedException {
throw new AccessDeniedException("custom AfterInvocationManager")
}
boolean supports(ConfigAttribute attribute) {
return true
}
boolean supports(Class<?> clazz) {
return true
}
}
}
boolean supports(ConfigAttribute attribute) {
return true
}
boolean supports(Class<?> clazz) {
return true
}
}
}
// --- misc ---
// --- misc ---
def "good error message when no Enable annotation"() {
when:
context = new AnnotationConfigApplicationContext(ExtendsNoEnableAnntotationConfig)
MethodSecurityInterceptor interceptor = context.getBean(MethodSecurityInterceptor)
interceptor.authenticationManager.authenticate(SecurityContextHolder.context.authentication)
then:
BeanCreationException e = thrown()
e.message.contains(EnableGlobalMethodSecurity.class.getName() + " is required")
}
def "good error message when no Enable annotation"() {
when:
context = new AnnotationConfigApplicationContext(ExtendsNoEnableAnntotationConfig)
MethodSecurityInterceptor interceptor = context.getBean(MethodSecurityInterceptor)
interceptor.authenticationManager.authenticate(SecurityContextHolder.context.authentication)
then:
BeanCreationException e = thrown()
e.message.contains(EnableGlobalMethodSecurity.class.getName() + " is required")
}
@Configuration
public static class ExtendsNoEnableAnntotationConfig extends GlobalMethodSecurityConfiguration {
@Override
protected AuthenticationManager authenticationManager() {
return new AuthenticationManager() {
Authentication authenticate(Authentication authentication) {
throw new UnsupportedOperationException()
}
}
}
}
@Configuration
public static class ExtendsNoEnableAnntotationConfig extends GlobalMethodSecurityConfiguration {
@Override
protected AuthenticationManager authenticationManager() {
return new AuthenticationManager() {
Authentication authenticate(Authentication authentication) {
throw new UnsupportedOperationException()
}
}
}
}
def "import subclass of GlobalMethodSecurityConfiguration"() {
when:
context = new AnnotationConfigApplicationContext(ImportSubclassGMSCConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.secured() == null
service.jsr250() == null
def "import subclass of GlobalMethodSecurityConfiguration"() {
when:
context = new AnnotationConfigApplicationContext(ImportSubclassGMSCConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.secured() == null
service.jsr250() == null
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
}
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
}
@Configuration
@Import(PreAuthorizeExtendsGMSCConfig)
public static class ImportSubclassGMSCConfig extends BaseMethodConfig {
}
@Configuration
@Import(PreAuthorizeExtendsGMSCConfig)
public static class ImportSubclassGMSCConfig extends BaseMethodConfig {
}
@Configuration
public static class BaseMethodConfig extends BaseAuthenticationConfig {
@Bean
public MethodSecurityService methodSecurityService() {
return new MethodSecurityServiceImpl()
}
}
@Configuration
public static class BaseMethodConfig extends BaseAuthenticationConfig {
@Bean
public MethodSecurityService methodSecurityService() {
return new MethodSecurityServiceImpl()
}
}
}
@@ -39,87 +39,87 @@ import org.springframework.security.core.context.SecurityContextHolder
*
*/
public class SampleEnableGlobalMethodSecurityTests extends BaseSpringSpec {
def setup() {
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
}
def setup() {
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password","ROLE_USER"))
}
def preAuthorize() {
when:
loadConfig(SampleWebSecurityConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.secured() == null
service.jsr250() == null
def preAuthorize() {
when:
loadConfig(SampleWebSecurityConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.secured() == null
service.jsr250() == null
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
}
when:
service.preAuthorize()
then:
thrown(AccessDeniedException)
}
@EnableGlobalMethodSecurity(prePostEnabled=true)
public static class SampleWebSecurityConfig {
@Bean
public MethodSecurityService methodSecurityService() {
return new MethodSecurityServiceImpl()
}
@EnableGlobalMethodSecurity(prePostEnabled=true)
public static class SampleWebSecurityConfig {
@Bean
public MethodSecurityService methodSecurityService() {
return new MethodSecurityServiceImpl()
}
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
}
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
}
def 'custom permission handler'() {
when:
loadConfig(CustomPermissionEvaluatorWebSecurityConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.hasPermission("allowed") == null
def 'custom permission handler'() {
when:
loadConfig(CustomPermissionEvaluatorWebSecurityConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.hasPermission("allowed") == null
when:
service.hasPermission("denied") == null
then:
thrown(AccessDeniedException)
}
when:
service.hasPermission("denied") == null
then:
thrown(AccessDeniedException)
}
@EnableGlobalMethodSecurity(prePostEnabled=true)
public static class CustomPermissionEvaluatorWebSecurityConfig extends GlobalMethodSecurityConfiguration {
@Bean
public MethodSecurityService methodSecurityService() {
return new MethodSecurityServiceImpl()
}
@EnableGlobalMethodSecurity(prePostEnabled=true)
public static class CustomPermissionEvaluatorWebSecurityConfig extends GlobalMethodSecurityConfiguration {
@Bean
public MethodSecurityService methodSecurityService() {
return new MethodSecurityServiceImpl()
}
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator());
return expressionHandler;
}
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator());
return expressionHandler;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
}
static class CustomPermissionEvaluator implements PermissionEvaluator {
public boolean hasPermission(Authentication authentication,
Object targetDomainObject, Object permission) {
return !"denied".equals(targetDomainObject);
}
static class CustomPermissionEvaluator implements PermissionEvaluator {
public boolean hasPermission(Authentication authentication,
Object targetDomainObject, Object permission) {
return !"denied".equals(targetDomainObject);
}
public boolean hasPermission(Authentication authentication,
Serializable targetId, String targetType, Object permission) {
return !"denied".equals(targetId);
}
public boolean hasPermission(Authentication authentication,
Serializable targetId, String targetType, Object permission) {
return !"denied".equals(targetId);
}
}
}
}
@@ -29,69 +29,69 @@ import spock.lang.Specification
*/
class UserDetailsManagerConfigurerTests extends Specification {
def "all attributes supported"() {
setup:
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
when:
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
.withUser("user")
.password("password")
.roles("USER")
.disabled(true)
.accountExpired(true)
.accountLocked(true)
.credentialsExpired(true)
.build()
then:
userDetails.username == 'user'
userDetails.password == 'password'
userDetails.authorities.collect { it.authority } == ["ROLE_USER"]
!userDetails.accountNonExpired
!userDetails.accountNonLocked
!userDetails.credentialsNonExpired
!userDetails.enabled
}
def "all attributes supported"() {
setup:
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
when:
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
.withUser("user")
.password("password")
.roles("USER")
.disabled(true)
.accountExpired(true)
.accountLocked(true)
.credentialsExpired(true)
.build()
then:
userDetails.username == 'user'
userDetails.password == 'password'
userDetails.authorities.collect { it.authority } == ["ROLE_USER"]
!userDetails.accountNonExpired
!userDetails.accountNonLocked
!userDetails.credentialsNonExpired
!userDetails.enabled
}
def "authorities(GrantedAuthorities...) works"() {
setup:
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER")
when:
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
.withUser("user")
.password("password")
.authorities(authority)
.build()
then:
userDetails.authorities == [authority] as Set
}
def "authorities(GrantedAuthorities...) works"() {
setup:
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER")
when:
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
.withUser("user")
.password("password")
.authorities(authority)
.build()
then:
userDetails.authorities == [authority] as Set
}
def "authorities(String...) works"() {
setup:
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
String authority = "ROLE_USER"
when:
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
.withUser("user")
.password("password")
.authorities(authority)
.build()
then:
userDetails.authorities.collect { it.authority } == [authority]
}
def "authorities(String...) works"() {
setup:
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
String authority = "ROLE_USER"
when:
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
.withUser("user")
.password("password")
.authorities(authority)
.build()
then:
userDetails.authorities.collect { it.authority } == [authority]
}
def "authorities(List) works"() {
setup:
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER")
when:
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
.withUser("user")
.password("password")
.authorities([authority])
.build()
then:
userDetails.authorities == [authority] as Set
}
def "authorities(List) works"() {
setup:
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager([])
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER")
when:
UserDetails userDetails = new UserDetailsManagerConfigurer<UserDetailsManagerConfigurer<InMemoryUserDetailsManager>>(userDetailsManager)
.withUser("user")
.password("password")
.authorities([authority])
.build()
then:
userDetails.authorities == [authority] as Set
}
}
@@ -30,144 +30,144 @@ import spock.lang.Specification
*/
class AbstractConfiguredSecurityBuilderTests extends BaseSpringSpec {
ConcreteAbstractConfiguredBuilder builder
ConcreteAbstractConfiguredBuilder builder
def setup() {
builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor)
}
def setup() {
builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor)
}
def "Null ObjectPostProcessor rejected"() {
when:
new ConcreteAbstractConfiguredBuilder(null)
then:
thrown(IllegalArgumentException)
when:
builder.objectPostProcessor(null);
then:
thrown(IllegalArgumentException)
}
def "Null ObjectPostProcessor rejected"() {
when:
new ConcreteAbstractConfiguredBuilder(null)
then:
thrown(IllegalArgumentException)
when:
builder.objectPostProcessor(null);
then:
thrown(IllegalArgumentException)
}
def "apply null is rejected"() {
when:
builder.apply(null)
then:
thrown(IllegalArgumentException)
}
def "apply null is rejected"() {
when:
builder.apply(null)
then:
thrown(IllegalArgumentException)
}
def "Duplicate configurer is removed"() {
when:
builder.apply(new ConcreteConfigurer())
builder.apply(new ConcreteConfigurer())
then:
ReflectionTestUtils.getField(builder,"configurers").size() == 1
}
def "Duplicate configurer is removed"() {
when:
builder.apply(new ConcreteConfigurer())
builder.apply(new ConcreteConfigurer())
then:
ReflectionTestUtils.getField(builder,"configurers").size() == 1
}
def "build twice fails"() {
setup:
builder.build()
when:
builder.build()
then:
thrown(IllegalStateException)
}
def "build twice fails"() {
setup:
builder.build()
when:
builder.build()
then:
thrown(IllegalStateException)
}
def "getObject before build fails"() {
when:
builder.getObject()
then:
thrown(IllegalStateException)
}
def "getObject before build fails"() {
when:
builder.getObject()
then:
thrown(IllegalStateException)
}
def "Configurer.init can apply another configurer"() {
setup:
DelegateConfigurer.CONF = Mock(SecurityConfigurerAdapter)
when:
builder.apply(new DelegateConfigurer())
builder.build()
then:
1 * DelegateConfigurer.CONF.init(builder)
1 * DelegateConfigurer.CONF.configure(builder)
}
def "Configurer.init can apply another configurer"() {
setup:
DelegateConfigurer.CONF = Mock(SecurityConfigurerAdapter)
when:
builder.apply(new DelegateConfigurer())
builder.build()
then:
1 * DelegateConfigurer.CONF.init(builder)
1 * DelegateConfigurer.CONF.configure(builder)
}
def "getConfigurer with multi fails"() {
setup:
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
builder.apply(new DelegateConfigurer())
builder.apply(new DelegateConfigurer())
when:
builder.getConfigurer(DelegateConfigurer)
then: "Fail due to trying to obtain a single DelegateConfigurer and multiple are provided"
thrown(IllegalStateException)
}
def "getConfigurer with multi fails"() {
setup:
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
builder.apply(new DelegateConfigurer())
builder.apply(new DelegateConfigurer())
when:
builder.getConfigurer(DelegateConfigurer)
then: "Fail due to trying to obtain a single DelegateConfigurer and multiple are provided"
thrown(IllegalStateException)
}
def "removeConfigurer with multi fails"() {
setup:
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
builder.apply(new DelegateConfigurer())
builder.apply(new DelegateConfigurer())
when:
builder.removeConfigurer(DelegateConfigurer)
then: "Fail due to trying to remove and obtain a single DelegateConfigurer and multiple are provided"
thrown(IllegalStateException)
}
def "removeConfigurer with multi fails"() {
setup:
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
builder.apply(new DelegateConfigurer())
builder.apply(new DelegateConfigurer())
when:
builder.removeConfigurer(DelegateConfigurer)
then: "Fail due to trying to remove and obtain a single DelegateConfigurer and multiple are provided"
thrown(IllegalStateException)
}
def "removeConfigurers with multi"() {
setup:
DelegateConfigurer c1 = new DelegateConfigurer()
DelegateConfigurer c2 = new DelegateConfigurer()
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
builder.apply(c1)
builder.apply(c2)
when:
def result = builder.removeConfigurers(DelegateConfigurer)
then:
result.size() == 2
result.contains(c1)
result.contains(c2)
builder.getConfigurers(DelegateConfigurer).empty
}
def "removeConfigurers with multi"() {
setup:
DelegateConfigurer c1 = new DelegateConfigurer()
DelegateConfigurer c2 = new DelegateConfigurer()
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
builder.apply(c1)
builder.apply(c2)
when:
def result = builder.removeConfigurers(DelegateConfigurer)
then:
result.size() == 2
result.contains(c1)
result.contains(c2)
builder.getConfigurers(DelegateConfigurer).empty
}
def "getConfigurers with multi"() {
setup:
DelegateConfigurer c1 = new DelegateConfigurer()
DelegateConfigurer c2 = new DelegateConfigurer()
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
builder.apply(c1)
builder.apply(c2)
when:
def result = builder.getConfigurers(DelegateConfigurer)
then:
result.size() == 2
result.contains(c1)
result.contains(c2)
builder.getConfigurers(DelegateConfigurer).size() == 2
}
def "getConfigurers with multi"() {
setup:
DelegateConfigurer c1 = new DelegateConfigurer()
DelegateConfigurer c2 = new DelegateConfigurer()
ConcreteAbstractConfiguredBuilder builder = new ConcreteAbstractConfiguredBuilder(objectPostProcessor, true)
builder.apply(c1)
builder.apply(c2)
when:
def result = builder.getConfigurers(DelegateConfigurer)
then:
result.size() == 2
result.contains(c1)
result.contains(c2)
builder.getConfigurers(DelegateConfigurer).size() == 2
}
private static class DelegateConfigurer extends SecurityConfigurerAdapter<Object, ConcreteAbstractConfiguredBuilder> {
private static SecurityConfigurer<Object, ConcreteAbstractConfiguredBuilder> CONF;
private static class DelegateConfigurer extends SecurityConfigurerAdapter<Object, ConcreteAbstractConfiguredBuilder> {
private static SecurityConfigurer<Object, ConcreteAbstractConfiguredBuilder> CONF;
@Override
public void init(ConcreteAbstractConfiguredBuilder builder)
throws Exception {
builder.apply(CONF);
}
}
@Override
public void init(ConcreteAbstractConfiguredBuilder builder)
throws Exception {
builder.apply(CONF);
}
}
private static class ConcreteConfigurer extends SecurityConfigurerAdapter<Object, ConcreteAbstractConfiguredBuilder> { }
private static class ConcreteConfigurer extends SecurityConfigurerAdapter<Object, ConcreteAbstractConfiguredBuilder> { }
private class ConcreteAbstractConfiguredBuilder extends AbstractConfiguredSecurityBuilder<Object, ConcreteAbstractConfiguredBuilder> {
private class ConcreteAbstractConfiguredBuilder extends AbstractConfiguredSecurityBuilder<Object, ConcreteAbstractConfiguredBuilder> {
public ConcreteAbstractConfiguredBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
super(objectPostProcessor);
}
public ConcreteAbstractConfiguredBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
super(objectPostProcessor);
}
public ConcreteAbstractConfiguredBuilder(ObjectPostProcessor<Object> objectPostProcessor, boolean allowMulti) {
super(objectPostProcessor,allowMulti);
}
public ConcreteAbstractConfiguredBuilder(ObjectPostProcessor<Object> objectPostProcessor, boolean allowMulti) {
super(objectPostProcessor,allowMulti);
}
public Object performBuild() throws Exception {
return "success";
}
}
public Object performBuild() throws Exception {
return "success";
}
}
}
@@ -34,286 +34,286 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
*
*/
public class SampleWebSecurityConfigurerAdapterTests extends BaseSpringSpec {
def "README HelloWorld Sample works"() {
setup: "Sample Config is loaded"
loadConfig(HelloWorldWebSecurityConfigurerAdapter)
when:
request.addHeader("Accept", "text/html")
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getRedirectedUrl() == "http://localhost/login"
when: "fail to log in"
super.setup()
request.addHeader("Accept", "text/html")
request.servletPath = "/login"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/login?error"
when: "login success"
super.setup()
request.servletPath = "/login"
request.method = "POST"
request.parameters.username = ["user"] as String[]
request.parameters.password = ["password"] as String[]
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default succes page"
response.getRedirectedUrl() == "/"
}
def "README HelloWorld Sample works"() {
setup: "Sample Config is loaded"
loadConfig(HelloWorldWebSecurityConfigurerAdapter)
when:
request.addHeader("Accept", "text/html")
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getRedirectedUrl() == "http://localhost/login"
when: "fail to log in"
super.setup()
request.addHeader("Accept", "text/html")
request.servletPath = "/login"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/login?error"
when: "login success"
super.setup()
request.servletPath = "/login"
request.method = "POST"
request.parameters.username = ["user"] as String[]
request.parameters.password = ["password"] as String[]
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default succes page"
response.getRedirectedUrl() == "/"
}
/**
* <code>
* <http>
* <intercept-url pattern="/resources/**" access="permitAll"/>
* <intercept-url pattern="/**" access="authenticated"/>
* <logout
* logout-success-url="/login?logout"
* logout-url="/logout"
* <form-login
* authentication-failure-url="/login?error"
* login-page="/login" <!-- Except Spring Security renders the login page -->
* login-processing-url="/login" <!-- but only POST -->
* password-parameter="password"
* username-parameter="username"
* />
* </http>
* <authentication-manager>
* <authentication-provider>
* <user-service>
* <user username="user" password="password" authorities="ROLE_USER"/>
* </user-service>
* </authentication-provider>
* </authentication-manager>
* </code>
* @author Rob Winch
*/
@EnableWebSecurity
public static class HelloWorldWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
/**
* <code>
* <http>
* <intercept-url pattern="/resources/**" access="permitAll"/>
* <intercept-url pattern="/**" access="authenticated"/>
* <logout
* logout-success-url="/login?logout"
* logout-url="/logout"
* <form-login
* authentication-failure-url="/login?error"
* login-page="/login" <!-- Except Spring Security renders the login page -->
* login-processing-url="/login" <!-- but only POST -->
* password-parameter="password"
* username-parameter="username"
* />
* </http>
* <authentication-manager>
* <authentication-provider>
* <user-service>
* <user username="user" password="password" authorities="ROLE_USER"/>
* </user-service>
* </authentication-provider>
* </authentication-manager>
* </code>
* @author Rob Winch
*/
@EnableWebSecurity
public static class HelloWorldWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
def "README Sample works"() {
setup: "Sample Config is loaded"
loadConfig(SampleWebSecurityConfigurerAdapter)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getRedirectedUrl() == "http://localhost/login"
when: "fail to log in"
super.setup()
request.servletPath = "/login"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/login?error"
when: "login success"
super.setup()
request.servletPath = "/login"
request.method = "POST"
request.parameters.username = ["user"] as String[]
request.parameters.password = ["password"] as String[]
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default succes page"
response.getRedirectedUrl() == "/"
}
def "README Sample works"() {
setup: "Sample Config is loaded"
loadConfig(SampleWebSecurityConfigurerAdapter)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getRedirectedUrl() == "http://localhost/login"
when: "fail to log in"
super.setup()
request.servletPath = "/login"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/login?error"
when: "login success"
super.setup()
request.servletPath = "/login"
request.method = "POST"
request.parameters.username = ["user"] as String[]
request.parameters.password = ["password"] as String[]
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default succes page"
response.getRedirectedUrl() == "/"
}
/**
* <code>
* <http security="none" pattern="/resources/**"/>
* <http>
* <intercept-url pattern="/logout" access="permitAll"/>
* <intercept-url pattern="/login" access="permitAll"/>
* <intercept-url pattern="/signup" access="permitAll"/>
* <intercept-url pattern="/about" access="permitAll"/>
* <intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
* <logout
* logout-success-url="/login?logout"
* logout-url="/logout"
* <form-login
* authentication-failure-url="/login?error"
* login-page="/login"
* login-processing-url="/login" <!-- but only POST -->
* password-parameter="password"
* username-parameter="username"
* />
* </http>
* <authentication-manager>
* <authentication-provider>
* <user-service>
* <user username="user" password="password" authorities="ROLE_USER"/>
* <user username="admin" password="password" authorities="ROLE_USER,ROLE_ADMIN"/>
* </user-service>
* </authentication-provider>
* </authentication-manager>
* </code>
* @author Rob Winch
*/
@EnableWebSecurity
public static class SampleWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
/**
* <code>
* <http security="none" pattern="/resources/**"/>
* <http>
* <intercept-url pattern="/logout" access="permitAll"/>
* <intercept-url pattern="/login" access="permitAll"/>
* <intercept-url pattern="/signup" access="permitAll"/>
* <intercept-url pattern="/about" access="permitAll"/>
* <intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
* <logout
* logout-success-url="/login?logout"
* logout-url="/logout"
* <form-login
* authentication-failure-url="/login?error"
* login-page="/login"
* login-processing-url="/login" <!-- but only POST -->
* password-parameter="password"
* username-parameter="username"
* />
* </http>
* <authentication-manager>
* <authentication-provider>
* <user-service>
* <user username="user" password="password" authorities="ROLE_USER"/>
* <user username="admin" password="password" authorities="ROLE_USER,ROLE_ADMIN"/>
* </user-service>
* </authentication-provider>
* </authentication-manager>
* </code>
* @author Rob Winch
*/
@EnableWebSecurity
public static class SampleWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/signup","/about").permitAll()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.loginPage("/login")
// set permitAll for all URLs associated with Form Login
.permitAll();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/signup","/about").permitAll()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.loginPage("/login")
// set permitAll for all URLs associated with Form Login
.permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
}
@Override
protected void configure(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
}
def "README Multi http Sample works"() {
setup:
loadConfig(SampleMultiHttpSecurityConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getRedirectedUrl() == "http://localhost/login"
when: "fail to log in"
super.setup()
request.servletPath = "/login"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/login?error"
when: "login success"
super.setup()
request.servletPath = "/login"
request.method = "POST"
request.parameters.username = ["user"] as String[]
request.parameters.password = ["password"] as String[]
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default succes page"
response.getRedirectedUrl() == "/"
def "README Multi http Sample works"() {
setup:
loadConfig(SampleMultiHttpSecurityConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getRedirectedUrl() == "http://localhost/login"
when: "fail to log in"
super.setup()
request.servletPath = "/login"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/login?error"
when: "login success"
super.setup()
request.servletPath = "/login"
request.method = "POST"
request.parameters.username = ["user"] as String[]
request.parameters.password = ["password"] as String[]
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default succes page"
response.getRedirectedUrl() == "/"
when: "request protected API URL"
super.setup()
request.servletPath = "/api/admin/test"
springSecurityFilterChain.doFilter(request,response,chain)
then: "get 401"
response.getStatus() == HttpServletResponse.SC_UNAUTHORIZED
when: "request protected API URL"
super.setup()
request.servletPath = "/api/admin/test"
springSecurityFilterChain.doFilter(request,response,chain)
then: "get 401"
response.getStatus() == HttpServletResponse.SC_UNAUTHORIZED
when: "request API for admins with user"
super.setup()
request.servletPath = "/api/admin/test"
request.addHeader("Authorization", "Basic " + "user:password".bytes.encodeBase64().toString())
springSecurityFilterChain.doFilter(request,response,chain)
then: "get 403"
response.getStatus() == HttpServletResponse.SC_FORBIDDEN
when: "request API for admins with user"
super.setup()
request.servletPath = "/api/admin/test"
request.addHeader("Authorization", "Basic " + "user:password".bytes.encodeBase64().toString())
springSecurityFilterChain.doFilter(request,response,chain)
then: "get 403"
response.getStatus() == HttpServletResponse.SC_FORBIDDEN
when: "request API for admins with admin"
super.setup()
request.servletPath = "/api/admin/test"
request.addHeader("Authorization", "Basic " + "admin:password".bytes.encodeBase64().toString())
springSecurityFilterChain.doFilter(request,response,chain)
then: "get 200"
response.getStatus() == HttpServletResponse.SC_OK
}
when: "request API for admins with admin"
super.setup()
request.servletPath = "/api/admin/test"
request.addHeader("Authorization", "Basic " + "admin:password".bytes.encodeBase64().toString())
springSecurityFilterChain.doFilter(request,response,chain)
then: "get 200"
response.getStatus() == HttpServletResponse.SC_OK
}
/**
* <code>
* <http security="none" pattern="/resources/**"/>
* <http pattern="/api/**">
* <intercept-url pattern="/api/admin/**" access="hasRole('ROLE_ADMIN')"/>
* <intercept-url pattern="/api/**" access="hasRole('ROLE_USER')"/>
* <http-basic />
* </http>
* <http>
* <intercept-url pattern="/logout" access="permitAll"/>
* <intercept-url pattern="/login" access="permitAll"/>
* <intercept-url pattern="/signup" access="permitAll"/>
* <intercept-url pattern="/about" access="permitAll"/>
* <intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
* <logout
* logout-success-url="/login?logout"
* logout-url="/logout"
* <form-login
* authentication-failure-url="/login?error"
* login-page="/login"
* login-processing-url="/login" <!-- but only POST -->
* password-parameter="password"
* username-parameter="username"
* />
* </http>
* <authentication-manager>
* <authentication-provider>
* <user-service>
* <user username="user" password="password" authorities="ROLE_USER"/>
* <user username="admin" password="password" authorities="ROLE_USER,ROLE_ADMIN"/>
* </user-service>
* </authentication-provider>
* </authentication-manager>
* </code>
* @author Rob Winch
*/
@EnableWebSecurity
public static class SampleMultiHttpSecurityConfig {
@Autowired
protected void configure(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
/**
* <code>
* <http security="none" pattern="/resources/**"/>
* <http pattern="/api/**">
* <intercept-url pattern="/api/admin/**" access="hasRole('ROLE_ADMIN')"/>
* <intercept-url pattern="/api/**" access="hasRole('ROLE_USER')"/>
* <http-basic />
* </http>
* <http>
* <intercept-url pattern="/logout" access="permitAll"/>
* <intercept-url pattern="/login" access="permitAll"/>
* <intercept-url pattern="/signup" access="permitAll"/>
* <intercept-url pattern="/about" access="permitAll"/>
* <intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
* <logout
* logout-success-url="/login?logout"
* logout-url="/logout"
* <form-login
* authentication-failure-url="/login?error"
* login-page="/login"
* login-processing-url="/login" <!-- but only POST -->
* password-parameter="password"
* username-parameter="username"
* />
* </http>
* <authentication-manager>
* <authentication-provider>
* <user-service>
* <user username="user" password="password" authorities="ROLE_USER"/>
* <user username="admin" password="password" authorities="ROLE_USER,ROLE_ADMIN"/>
* </user-service>
* </authentication-provider>
* </authentication-manager>
* </code>
* @author Rob Winch
*/
@EnableWebSecurity
public static class SampleMultiHttpSecurityConfig {
@Autowired
protected void configure(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
@Configuration
@Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**")
.authorizeRequests()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/api/**").hasRole("USER")
.and()
.httpBasic();
}
}
@Configuration
@Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**")
.authorizeRequests()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/api/**").hasRole("USER")
.and()
.httpBasic();
}
}
@Configuration
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
@Configuration
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/signup","/about").permitAll()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.loginPage("/login")
.permitAll();
}
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/signup","/about").permitAll()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.loginPage("/login")
.permitAll();
}
}
}
}
@@ -56,240 +56,240 @@ import org.springframework.web.filter.OncePerRequestFilter
*/
class WebSecurityConfigurerAdapterTests extends BaseSpringSpec {
def "MessageSources populated on AuthenticationProviders"() {
when:
loadConfig(MessageSourcesPopulatedConfig)
List<AuthenticationProvider> providers = authenticationProviders()
then:
providers*.messages*.messageSource == [context,context,context,context]
}
def "MessageSources populated on AuthenticationProviders"() {
when:
loadConfig(MessageSourcesPopulatedConfig)
List<AuthenticationProvider> providers = authenticationProviders()
then:
providers*.messages*.messageSource == [context,context,context,context]
}
def "messages set when using WebSecurityConfigurerAdapter"() {
when:
loadConfig(InMemoryAuthWithWebSecurityConfigurerAdapter)
then:
authenticationManager.messages.messageSource instanceof ApplicationContext
}
def "messages set when using WebSecurityConfigurerAdapter"() {
when:
loadConfig(InMemoryAuthWithWebSecurityConfigurerAdapter)
then:
authenticationManager.messages.messageSource instanceof ApplicationContext
}
def "headers are populated by default"() {
setup: "load config that overrides http and accepts defaults"
loadConfig(HeadersArePopulatedByDefaultConfig)
request.secure = true
when: "invoke the springSecurityFilterChain"
springSecurityFilterChain.doFilter(request, response, chain)
then: "the default headers are added"
responseHeaders == ['X-Content-Type-Options':'nosniff',
'X-Frame-Options':'DENY',
'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
'Pragma':'no-cache',
'Expires' : '0',
'X-XSS-Protection' : '1; mode=block']
}
def "headers are populated by default"() {
setup: "load config that overrides http and accepts defaults"
loadConfig(HeadersArePopulatedByDefaultConfig)
request.secure = true
when: "invoke the springSecurityFilterChain"
springSecurityFilterChain.doFilter(request, response, chain)
then: "the default headers are added"
responseHeaders == ['X-Content-Type-Options':'nosniff',
'X-Frame-Options':'DENY',
'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
'Pragma':'no-cache',
'Expires' : '0',
'X-XSS-Protection' : '1; mode=block']
}
@EnableWebSecurity
static class HeadersArePopulatedByDefaultConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class HeadersArePopulatedByDefaultConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
@Override
protected void configure(HttpSecurity http) throws Exception {
@Override
protected void configure(HttpSecurity http) throws Exception {
}
}
}
}
def "webasync populated by default"() {
when: "load config that overrides http and accepts defaults"
loadConfig(WebAsyncPopulatedByDefaultConfig)
then: "WebAsyncManagerIntegrationFilter is populated"
findFilter(WebAsyncManagerIntegrationFilter)
}
def "webasync populated by default"() {
when: "load config that overrides http and accepts defaults"
loadConfig(WebAsyncPopulatedByDefaultConfig)
then: "WebAsyncManagerIntegrationFilter is populated"
findFilter(WebAsyncManagerIntegrationFilter)
}
@EnableWebSecurity
static class WebAsyncPopulatedByDefaultConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class WebAsyncPopulatedByDefaultConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
@Override
protected void configure(HttpSecurity http) throws Exception {
@Override
protected void configure(HttpSecurity http) throws Exception {
}
}
}
}
def "AuthenticationEventPublisher is registered for Web configure(AuthenticationManagerBuilder auth)"() {
when:
loadConfig(InMemoryAuthWithWebSecurityConfigurerAdapter)
then:
authenticationManager.parent.eventPublisher instanceof DefaultAuthenticationEventPublisher
when:
Authentication token = new UsernamePasswordAuthenticationToken("user","password")
authenticationManager.authenticate(token)
then: "We only receive the AuthenticationSuccessEvent once"
InMemoryAuthWithWebSecurityConfigurerAdapter.EVENTS.size() == 1
InMemoryAuthWithWebSecurityConfigurerAdapter.EVENTS[0].authentication.name == token.principal
}
def "AuthenticationEventPublisher is registered for Web configure(AuthenticationManagerBuilder auth)"() {
when:
loadConfig(InMemoryAuthWithWebSecurityConfigurerAdapter)
then:
authenticationManager.parent.eventPublisher instanceof DefaultAuthenticationEventPublisher
when:
Authentication token = new UsernamePasswordAuthenticationToken("user","password")
authenticationManager.authenticate(token)
then: "We only receive the AuthenticationSuccessEvent once"
InMemoryAuthWithWebSecurityConfigurerAdapter.EVENTS.size() == 1
InMemoryAuthWithWebSecurityConfigurerAdapter.EVENTS[0].authentication.name == token.principal
}
@EnableWebSecurity
static class InMemoryAuthWithWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter implements ApplicationListener<AuthenticationSuccessEvent> {
static List<AuthenticationSuccessEvent> EVENTS = []
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
@EnableWebSecurity
static class InMemoryAuthWithWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter implements ApplicationListener<AuthenticationSuccessEvent> {
static List<AuthenticationSuccessEvent> EVENTS = []
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
@Override
public void onApplicationEvent(AuthenticationSuccessEvent e) {
EVENTS.add(e)
}
}
@Override
public void onApplicationEvent(AuthenticationSuccessEvent e) {
EVENTS.add(e)
}
}
def "Override ContentNegotiationStrategy with @Bean"() {
setup:
OverrideContentNegotiationStrategySharedObjectConfig.CNS = Mock(ContentNegotiationStrategy)
when:
loadConfig(OverrideContentNegotiationStrategySharedObjectConfig)
then:
context.getBean(OverrideContentNegotiationStrategySharedObjectConfig).http.getSharedObject(ContentNegotiationStrategy) == OverrideContentNegotiationStrategySharedObjectConfig.CNS
}
def "Override ContentNegotiationStrategy with @Bean"() {
setup:
OverrideContentNegotiationStrategySharedObjectConfig.CNS = Mock(ContentNegotiationStrategy)
when:
loadConfig(OverrideContentNegotiationStrategySharedObjectConfig)
then:
context.getBean(OverrideContentNegotiationStrategySharedObjectConfig).http.getSharedObject(ContentNegotiationStrategy) == OverrideContentNegotiationStrategySharedObjectConfig.CNS
}
@EnableWebSecurity
static class OverrideContentNegotiationStrategySharedObjectConfig extends WebSecurityConfigurerAdapter {
static ContentNegotiationStrategy CNS
@EnableWebSecurity
static class OverrideContentNegotiationStrategySharedObjectConfig extends WebSecurityConfigurerAdapter {
static ContentNegotiationStrategy CNS
@Bean
public ContentNegotiationStrategy cns() {
return CNS
}
}
@Bean
public ContentNegotiationStrategy cns() {
return CNS
}
}
def "ContentNegotiationStrategy shareObject defaults to Header with no @Bean"() {
when:
loadConfig(ContentNegotiationStrategyDefaultSharedObjectConfig)
then:
context.getBean(ContentNegotiationStrategyDefaultSharedObjectConfig).http.getSharedObject(ContentNegotiationStrategy).class == HeaderContentNegotiationStrategy
}
def "ContentNegotiationStrategy shareObject defaults to Header with no @Bean"() {
when:
loadConfig(ContentNegotiationStrategyDefaultSharedObjectConfig)
then:
context.getBean(ContentNegotiationStrategyDefaultSharedObjectConfig).http.getSharedObject(ContentNegotiationStrategy).class == HeaderContentNegotiationStrategy
}
@EnableWebSecurity
static class ContentNegotiationStrategyDefaultSharedObjectConfig extends WebSecurityConfigurerAdapter {}
@EnableWebSecurity
static class ContentNegotiationStrategyDefaultSharedObjectConfig extends WebSecurityConfigurerAdapter {}
def "UserDetailsService lazy"() {
setup:
loadConfig(RequiresUserDetailsServiceConfig,UserDetailsServiceConfig)
when:
findFilter(MyFilter).userDetailsService.loadUserByUsername("user")
then:
noExceptionThrown()
when:
findFilter(MyFilter).userDetailsService.loadUserByUsername("admin")
then:
thrown(UsernameNotFoundException)
}
def "UserDetailsService lazy"() {
setup:
loadConfig(RequiresUserDetailsServiceConfig,UserDetailsServiceConfig)
when:
findFilter(MyFilter).userDetailsService.loadUserByUsername("user")
then:
noExceptionThrown()
when:
findFilter(MyFilter).userDetailsService.loadUserByUsername("admin")
then:
thrown(UsernameNotFoundException)
}
@Configuration
static class RequiresUserDetailsServiceConfig {
@Bean
public MyFilter myFilter(UserDetailsService uds) {
return new MyFilter(uds)
}
}
@Configuration
static class RequiresUserDetailsServiceConfig {
@Bean
public MyFilter myFilter(UserDetailsService uds) {
return new MyFilter(uds)
}
}
@EnableWebSecurity
static class UserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyFilter myFilter;
@EnableWebSecurity
static class UserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyFilter myFilter;
@Bean
@Override
public UserDetailsService userDetailsServiceBean() {
return super.userDetailsServiceBean()
}
@Bean
@Override
public UserDetailsService userDetailsServiceBean() {
return super.userDetailsServiceBean()
}
@Override
public void configure(HttpSecurity http) {
http
.addFilterBefore(myFilter,UsernamePasswordAuthenticationFilter)
}
@Override
public void configure(HttpSecurity http) {
http
.addFilterBefore(myFilter,UsernamePasswordAuthenticationFilter)
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
}
def "SEC-2274: WebSecurityConfigurer adds ApplicationContext as a shared object"() {
when:
loadConfig(ApplicationContextSharedObjectConfig)
then:
context.getBean(ApplicationContextSharedObjectConfig).http.getSharedObject(ApplicationContext) == context
}
def "SEC-2274: WebSecurityConfigurer adds ApplicationContext as a shared object"() {
when:
loadConfig(ApplicationContextSharedObjectConfig)
then:
context.getBean(ApplicationContextSharedObjectConfig).http.getSharedObject(ApplicationContext) == context
}
@EnableWebSecurity
static class ApplicationContextSharedObjectConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class ApplicationContextSharedObjectConfig extends WebSecurityConfigurerAdapter {
}
}
static class MyFilter extends OncePerRequestFilter {
private UserDetailsService userDetailsService
public MyFilter(UserDetailsService uds) {
assert uds != null
this.userDetailsService = uds
}
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
chain.doFilter(request,response)
}
}
static class MyFilter extends OncePerRequestFilter {
private UserDetailsService userDetailsService
public MyFilter(UserDetailsService uds) {
assert uds != null
this.userDetailsService = uds
}
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
chain.doFilter(request,response)
}
}
def "AuthenticationTrustResolver populated as defaultObject"() {
setup:
CustomTrustResolverConfig.TR = Mock(AuthenticationTrustResolver)
when:
loadConfig(CustomTrustResolverConfig)
then:
context.getBean(CustomTrustResolverConfig).http.getSharedObject(AuthenticationTrustResolver) == CustomTrustResolverConfig.TR
}
def "AuthenticationTrustResolver populated as defaultObject"() {
setup:
CustomTrustResolverConfig.TR = Mock(AuthenticationTrustResolver)
when:
loadConfig(CustomTrustResolverConfig)
then:
context.getBean(CustomTrustResolverConfig).http.getSharedObject(AuthenticationTrustResolver) == CustomTrustResolverConfig.TR
}
@EnableWebSecurity
static class CustomTrustResolverConfig extends WebSecurityConfigurerAdapter {
static AuthenticationTrustResolver TR
@EnableWebSecurity
static class CustomTrustResolverConfig extends WebSecurityConfigurerAdapter {
static AuthenticationTrustResolver TR
@Bean
public AuthenticationTrustResolver tr() {
return TR
}
}
@Bean
public AuthenticationTrustResolver tr() {
return TR
}
}
def "WebSecurityConfigurerAdapter has Ordered between 0 and lowest priority"() {
when:
def lowestConfig = new LowestPriorityWebSecurityConfig()
def defaultConfig = new DefaultOrderWebSecurityConfig()
def compare = new AnnotationAwareOrderComparator()
then: "the default ordering is between 0 and lowest priority (Boot adapters)"
compare.compare(lowestConfig, defaultConfig) > 0
}
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 {}
class DefaultOrderWebSecurityConfig extends WebSecurityConfigurerAdapter {}
@Order(Ordered.LOWEST_PRECEDENCE)
class LowestPriorityWebSecurityConfig extends WebSecurityConfigurerAdapter {}
@Order(Ordered.LOWEST_PRECEDENCE)
class LowestPriorityWebSecurityConfig extends WebSecurityConfigurerAdapter {}
}
@@ -41,81 +41,81 @@ import spock.lang.Unroll;
*
*/
public class HttpSecurityTests extends BaseSpringSpec {
def "addFilter with unregistered Filter"() {
when:
loadConfig(UnregisteredFilterConfig)
then:
BeanCreationException success = thrown()
success.message.contains "The Filter class ${UnregisteredFilter.name} does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead."
}
def "addFilter with unregistered Filter"() {
when:
loadConfig(UnregisteredFilterConfig)
then:
BeanCreationException success = thrown()
success.message.contains "The Filter class ${UnregisteredFilter.name} does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead."
}
@Configuration
static class UnregisteredFilterConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.addFilter(new UnregisteredFilter())
}
}
@Configuration
static class UnregisteredFilterConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.addFilter(new UnregisteredFilter())
}
}
static class UnregisteredFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
filterChain.doFilter(request, response);
}
}
static class UnregisteredFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
filterChain.doFilter(request, response);
}
}
// https://github.com/SpringSource/spring-security-javaconfig/issues/104
def "#104 addFilter CasAuthenticationFilter"() {
when:
loadConfig(CasAuthenticationFilterConfig)
then:
findFilter(CasAuthenticationFilter)
}
// https://github.com/SpringSource/spring-security-javaconfig/issues/104
def "#104 addFilter CasAuthenticationFilter"() {
when:
loadConfig(CasAuthenticationFilterConfig)
then:
findFilter(CasAuthenticationFilter)
}
@Configuration
static class CasAuthenticationFilterConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.addFilter(new CasAuthenticationFilter())
}
}
@Configuration
static class CasAuthenticationFilterConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.addFilter(new CasAuthenticationFilter())
}
}
@Unroll
def "requestMatchers javadoc"() {
setup: "load configuration like the config on the requestMatchers() javadoc"
loadConfig(RequestMatcherRegistryConfigs)
when:
super.setup()
request.servletPath = "/oauth/a"
springSecurityFilterChain.doFilter(request, response, chain)
then:
response.status == HttpServletResponse.SC_UNAUTHORIZED
where:
servletPath | _
"/oauth/a" | _
"/oauth/b" | _
"/api/a" | _
"/api/b" | _
"/oauth2/b" | _
"/api2/b" | _
}
@Unroll
def "requestMatchers javadoc"() {
setup: "load configuration like the config on the requestMatchers() javadoc"
loadConfig(RequestMatcherRegistryConfigs)
when:
super.setup()
request.servletPath = "/oauth/a"
springSecurityFilterChain.doFilter(request, response, chain)
then:
response.status == HttpServletResponse.SC_UNAUTHORIZED
where:
servletPath | _
"/oauth/a" | _
"/oauth/b" | _
"/api/a" | _
"/api/b" | _
"/oauth2/b" | _
"/api2/b" | _
}
@EnableWebSecurity
static class RequestMatcherRegistryConfigs extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/api/**")
.antMatchers("/oauth/**")
.and()
.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.and()
.httpBasic()
}
}
@EnableWebSecurity
static class RequestMatcherRegistryConfigs extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/api/**")
.antMatchers("/oauth/**")
.and()
.authorizeRequests()
.antMatchers("/**").hasRole("USER")
.and()
.httpBasic()
}
}
}
@@ -13,8 +13,22 @@
* 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.configuration
import org.springframework.mock.web.MockServletContext
import org.springframework.security.authentication.TestingAuthenticationToken
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.security.core.context.SecurityContext
import org.springframework.security.core.context.SecurityContextImpl
import org.springframework.security.core.userdetails.User
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
import org.springframework.test.context.web.WebAppConfiguration
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.mock.web.MockHttpServletRequest
@@ -25,61 +39,105 @@ 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.web.authentication.AnonymousAuthenticationFilter
import org.springframework.security.web.debug.DebugFilter;
import org.springframework.security.web.debug.DebugFilter
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
class EnableWebSecurityTests extends BaseSpringSpec {
def "@Bean(BeanIds.AUTHENTICATION_MANAGER) includes HttpSecurity's AuthenticationManagerBuilder"() {
when:
loadConfig(SecurityConfig)
AuthenticationManager authenticationManager = context.getBean(AuthenticationManager)
AnonymousAuthenticationToken anonymousAuthToken = findFilter(AnonymousAuthenticationFilter).createAuthentication(new MockHttpServletRequest())
then:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
authenticationManager.authenticate(anonymousAuthToken)
def "@Bean(BeanIds.AUTHENTICATION_MANAGER) includes HttpSecurity's AuthenticationManagerBuilder"() {
when:
loadConfig(SecurityConfig)
AuthenticationManager authenticationManager = context.getBean(AuthenticationManager)
AnonymousAuthenticationToken anonymousAuthToken = findFilter(AnonymousAuthenticationFilter).createAuthentication(new MockHttpServletRequest())
then:
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"))
authenticationManager.authenticate(anonymousAuthToken)
}
}
@EnableWebSecurity
static class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
@EnableWebSecurity
static class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/*").hasRole("USER")
.and()
.formLogin();
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/*").hasRole("USER")
.and()
.formLogin();
}
}
def "@EnableWebSecurity on superclass"() {
when:
loadConfig(ChildSecurityConfig)
then:
context.getBean("springSecurityFilterChain", DebugFilter)
}
def "@EnableWebSecurity on superclass"() {
when:
loadConfig(ChildSecurityConfig)
then:
context.getBean("springSecurityFilterChain", DebugFilter)
}
@Configuration
static class ChildSecurityConfig extends DebugSecurityConfig {
}
@Configuration
static class ChildSecurityConfig extends DebugSecurityConfig {
}
@EnableWebSecurity(debug=true)
static class DebugSecurityConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity(debug=true)
static class DebugSecurityConfig extends WebSecurityConfigurerAdapter {
}
}
def "SEC-2942: EnableWebSecurity adds AuthenticationPrincipalArgumentResolver"() {
setup:
def username = "test"
context = new AnnotationConfigWebApplicationContext()
context.servletContext = new MockServletContext()
context.register(AuthenticationPrincipalConfig)
context.refresh()
SecurityContext securityContext = new SecurityContextImpl(authentication: new TestingAuthenticationToken(username, "pass", "ROLE_USER"))
MockMvc mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.addFilters(springSecurityFilterChain)
.build()
when:
String body = mockMvc
.perform(get("/").sessionAttr(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, securityContext))
.andReturn().response.contentAsString
then:
body == username
}
@EnableWebSecurity
@EnableWebMvc
@Configuration
static class AuthenticationPrincipalConfig {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.inMemoryAuthentication()
}
@RestController
static class AuthController {
@RequestMapping("/")
String principal(@AuthenticationPrincipal String principal) {
principal
}
}
}
}
@@ -47,295 +47,295 @@ import org.springframework.test.util.ReflectionTestUtils
*/
class WebSecurityConfigurationTests extends BaseSpringSpec {
def "WebSecurityConfigurers are sorted"() {
when:
loadConfig(SortedWebSecurityConfigurerAdaptersConfig);
List<SecurityFilterChain> filterChains = context.getBean(FilterChainProxy).filterChains
then:
filterChains[0].requestMatcher.pattern == "/ignore1"
filterChains[0].filters.empty
filterChains[1].requestMatcher.pattern == "/ignore2"
filterChains[1].filters.empty
def "WebSecurityConfigurers are sorted"() {
when:
loadConfig(SortedWebSecurityConfigurerAdaptersConfig);
List<SecurityFilterChain> filterChains = context.getBean(FilterChainProxy).filterChains
then:
filterChains[0].requestMatcher.pattern == "/ignore1"
filterChains[0].filters.empty
filterChains[1].requestMatcher.pattern == "/ignore2"
filterChains[1].filters.empty
filterChains[2].requestMatcher.pattern == "/role1/**"
filterChains[3].requestMatcher.pattern == "/role2/**"
filterChains[4].requestMatcher.pattern == "/role3/**"
filterChains[5].requestMatcher.class == AnyRequestMatcher
}
filterChains[2].requestMatcher.pattern == "/role1/**"
filterChains[3].requestMatcher.pattern == "/role2/**"
filterChains[4].requestMatcher.pattern == "/role3/**"
filterChains[5].requestMatcher.class == AnyRequestMatcher
}
@EnableWebSecurity
static class SortedWebSecurityConfigurerAdaptersConfig {
public AuthenticationManager authenticationManager() throws Exception {
return new AuthenticationManagerBuilder()
.inMemoryAuthentication()
.withUser("marissa").password("koala").roles("USER").and()
.withUser("paul").password("emu").roles("USER").and()
.and()
.build();
}
@EnableWebSecurity
static class SortedWebSecurityConfigurerAdaptersConfig {
public AuthenticationManager authenticationManager() throws Exception {
return new AuthenticationManagerBuilder()
.inMemoryAuthentication()
.withUser("marissa").password("koala").roles("USER").and()
.withUser("paul").password("emu").roles("USER").and()
.and()
.build();
}
@Configuration
@Order(1)
public static class WebConfigurer1 extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/ignore1","/ignore2");
}
@Configuration
@Order(1)
public static class WebConfigurer1 extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/ignore1","/ignore2");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/role1/**")
.authorizeRequests()
.anyRequest().hasRole("1");
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/role1/**")
.authorizeRequests()
.anyRequest().hasRole("1");
}
}
@Configuration
@Order(2)
public static class WebConfigurer2 extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/role2/**")
.authorizeRequests()
.anyRequest().hasRole("2");
}
}
@Configuration
@Order(2)
public static class WebConfigurer2 extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/role2/**")
.authorizeRequests()
.anyRequest().hasRole("2");
}
}
@Configuration
@Order(3)
public static class WebConfigurer3 extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/role3/**")
.authorizeRequests()
.anyRequest().hasRole("3");
}
}
@Configuration
@Order(3)
public static class WebConfigurer3 extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/role3/**")
.authorizeRequests()
.anyRequest().hasRole("3");
}
}
@Configuration
public static class WebConfigurer4 extends WebSecurityConfigurerAdapter {
@Configuration
public static class WebConfigurer4 extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().hasRole("4");
}
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().hasRole("4");
}
}
}
def "WebSecurityConfigurers fails with duplicate order"() {
when:
loadConfig(DuplicateOrderConfig);
then:
BeanCreationException e = thrown()
e.message.contains "@Order on WebSecurityConfigurers must be unique"
}
def "WebSecurityConfigurers fails with duplicate order"() {
when:
loadConfig(DuplicateOrderConfig);
then:
BeanCreationException e = thrown()
e.message.contains "@Order on WebSecurityConfigurers must be unique"
}
@EnableWebSecurity
static class DuplicateOrderConfig {
public AuthenticationManager authenticationManager() throws Exception {
return new AuthenticationManagerBuilder()
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.and()
.build();
}
@EnableWebSecurity
static class DuplicateOrderConfig {
public AuthenticationManager authenticationManager() throws Exception {
return new AuthenticationManagerBuilder()
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.and()
.build();
}
@Configuration
public static class WebConfigurer1 extends WebSecurityConfigurerAdapter {
@Configuration
public static class WebConfigurer1 extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/role1/**")
.authorizeRequests()
.anyRequest().hasRole("1");
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/role1/**")
.authorizeRequests()
.anyRequest().hasRole("1");
}
}
@Configuration
public static class WebConfigurer2 extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/role2/**")
.authorizeRequests()
.anyRequest().hasRole("2");
}
}
}
@Configuration
public static class WebConfigurer2 extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/role2/**")
.authorizeRequests()
.anyRequest().hasRole("2");
}
}
}
def "Override privilegeEvaluator"() {
setup:
WebInvocationPrivilegeEvaluator privilegeEvaluator = Mock()
PrivilegeEvaluatorConfigurerAdapterConfig.PE = privilegeEvaluator
when:
loadConfig(PrivilegeEvaluatorConfigurerAdapterConfig)
then:
context.getBean(WebInvocationPrivilegeEvaluator) == privilegeEvaluator
}
def "Override privilegeEvaluator"() {
setup:
WebInvocationPrivilegeEvaluator privilegeEvaluator = Mock()
PrivilegeEvaluatorConfigurerAdapterConfig.PE = privilegeEvaluator
when:
loadConfig(PrivilegeEvaluatorConfigurerAdapterConfig)
then:
context.getBean(WebInvocationPrivilegeEvaluator) == privilegeEvaluator
}
@EnableWebSecurity
static class PrivilegeEvaluatorConfigurerAdapterConfig extends WebSecurityConfigurerAdapter {
static WebInvocationPrivilegeEvaluator PE
@EnableWebSecurity
static class PrivilegeEvaluatorConfigurerAdapterConfig extends WebSecurityConfigurerAdapter {
static WebInvocationPrivilegeEvaluator PE
@Override
public void configure(WebSecurity web) throws Exception {
web
.privilegeEvaluator(PE)
}
}
@Override
public void configure(WebSecurity web) throws Exception {
web
.privilegeEvaluator(PE)
}
}
def "Override webSecurityExpressionHandler"() {
setup:
SecurityExpressionHandler expressionHandler = Mock()
ExpressionParser parser = Mock()
WebSecurityExpressionHandlerConfig.EH = expressionHandler
when:
loadConfig(WebSecurityExpressionHandlerConfig)
then:
context.getBean(SecurityExpressionHandler) == expressionHandler
1 * expressionHandler.getExpressionParser() >> parser
}
def "Override webSecurityExpressionHandler"() {
setup:
SecurityExpressionHandler expressionHandler = Mock()
ExpressionParser parser = Mock()
WebSecurityExpressionHandlerConfig.EH = expressionHandler
when:
loadConfig(WebSecurityExpressionHandlerConfig)
then:
context.getBean(SecurityExpressionHandler) == expressionHandler
1 * expressionHandler.getExpressionParser() >> parser
}
@EnableWebSecurity
static class WebSecurityExpressionHandlerConfig extends WebSecurityConfigurerAdapter {
static SecurityExpressionHandler EH
@EnableWebSecurity
static class WebSecurityExpressionHandlerConfig extends WebSecurityConfigurerAdapter {
static SecurityExpressionHandler EH
@Override
public void configure(WebSecurity web) throws Exception {
web
.expressionHandler(EH)
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.expressionHandler(EH)
.anyRequest().authenticated()
}
}
@Override
public void configure(WebSecurity web) throws Exception {
web
.expressionHandler(EH)
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.expressionHandler(EH)
.anyRequest().authenticated()
}
}
def "#138 webSecurityExpressionHandler defaults"() {
when:
loadConfig(WebSecurityExpressionHandlerDefaultsConfig)
then:
SecurityExpressionHandler wseh = context.getBean(SecurityExpressionHandler)
wseh instanceof DefaultWebSecurityExpressionHandler
}
def "#138 webSecurityExpressionHandler defaults"() {
when:
loadConfig(WebSecurityExpressionHandlerDefaultsConfig)
then:
SecurityExpressionHandler wseh = context.getBean(SecurityExpressionHandler)
wseh instanceof DefaultWebSecurityExpressionHandler
}
@EnableWebSecurity
static class WebSecurityExpressionHandlerDefaultsConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class WebSecurityExpressionHandlerDefaultsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
}
}
def "#138 WebInvocationPrivilegeEvaluator defaults"() {
when:
loadConfig(WebInvocationPrivilegeEvaluatorDefaultsConfig)
then:
WebInvocationPrivilegeEvaluator wipe = context.getBean(WebInvocationPrivilegeEvaluator)
wipe instanceof DefaultWebInvocationPrivilegeEvaluator
wipe.securityInterceptor != null
}
def "#138 WebInvocationPrivilegeEvaluator defaults"() {
when:
loadConfig(WebInvocationPrivilegeEvaluatorDefaultsConfig)
then:
WebInvocationPrivilegeEvaluator wipe = context.getBean(WebInvocationPrivilegeEvaluator)
wipe instanceof DefaultWebInvocationPrivilegeEvaluator
wipe.securityInterceptor != null
}
@EnableWebSecurity
static class WebInvocationPrivilegeEvaluatorDefaultsConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class WebInvocationPrivilegeEvaluatorDefaultsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
}
}
def "SEC-2303: DefaultExpressionHandler has bean resolver set"() {
when:
loadConfig(DefaultExpressionHandlerSetsBeanResolverConfig)
then: "the exposed bean has a BeanResolver set"
ReflectionTestUtils.getField(context.getBean(SecurityExpressionHandler),"br")
when:
springSecurityFilterChain.doFilter(request, response, chain)
then: "we can use the BeanResolver with a grant"
noExceptionThrown()
when: "we can use the Beanresolver with a deny"
springSecurityFilterChain.doFilter(new MockHttpServletRequest(method:'POST'), response, chain)
then:
noExceptionThrown()
}
def "SEC-2303: DefaultExpressionHandler has bean resolver set"() {
when:
loadConfig(DefaultExpressionHandlerSetsBeanResolverConfig)
then: "the exposed bean has a BeanResolver set"
ReflectionTestUtils.getField(context.getBean(SecurityExpressionHandler),"br")
when:
springSecurityFilterChain.doFilter(request, response, chain)
then: "we can use the BeanResolver with a grant"
noExceptionThrown()
when: "we can use the Beanresolver with a deny"
springSecurityFilterChain.doFilter(new MockHttpServletRequest(method:'POST'), response, chain)
then:
noExceptionThrown()
}
@EnableWebSecurity
static class DefaultExpressionHandlerSetsBeanResolverConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class DefaultExpressionHandlerSetsBeanResolverConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().access("request.method == 'GET' ? @b.grant() : @b.deny()")
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().access("request.method == 'GET' ? @b.grant() : @b.deny()")
}
@Bean
public MyBean b() {
new MyBean()
}
@Bean
public MyBean b() {
new MyBean()
}
static class MyBean {
boolean deny() {
false
}
static class MyBean {
boolean deny() {
false
}
boolean grant() {
true
}
}
}
boolean grant() {
true
}
}
}
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
}
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
static class ParentConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.inMemoryAuthentication()
}
}
@EnableWebSecurity
static class ParentConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.inMemoryAuthentication()
}
}
@EnableWebSecurity
static class ChildConfig extends WebSecurityConfigurerAdapter { }
@EnableWebSecurity
static class ChildConfig extends WebSecurityConfigurerAdapter { }
def "SEC-2773: delegatingApplicationListener is static method"() {
expect: 'delegatingApplicationListener to prevent premature instantiation of WebSecurityConfiguration'
Modifier.isStatic(WebSecurityConfiguration.metaClass.methods.find { it.name == 'delegatingApplicationListener'}.modifiers)
}
def "SEC-2773: delegatingApplicationListener is static method"() {
expect: 'delegatingApplicationListener to prevent premature instantiation of WebSecurityConfiguration'
Modifier.isStatic(WebSecurityConfiguration.metaClass.methods.find { it.name == 'delegatingApplicationListener'}.modifiers)
}
}
@@ -22,17 +22,17 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon
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()
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();
}
AnnotationConfigWebApplicationContext child = new AnnotationConfigWebApplicationContext()
child.register(Sec2377BConfig)
child.parent = parent
child.refresh()
then:
noExceptionThrown();
}
}
@@ -29,43 +29,43 @@ import spock.lang.Specification
*
*/
class AbstractConfigAttributeRequestMatcherRegistryTests extends Specification {
ConcreteAbstractRequestMatcherMappingConfigurer registry = new ConcreteAbstractRequestMatcherMappingConfigurer()
ConcreteAbstractRequestMatcherMappingConfigurer registry = new ConcreteAbstractRequestMatcherMappingConfigurer()
def "regexMatchers(GET,'/a.*') uses RegexRequestMatcher"() {
when:
def matchers = registry.regexMatchers(HttpMethod.GET,"/a.*")
then: 'matcher is a RegexRequestMatcher'
matchers.collect {it.class } == [RegexRequestMatcher]
}
def "regexMatchers(GET,'/a.*') uses RegexRequestMatcher"() {
when:
def matchers = registry.regexMatchers(HttpMethod.GET,"/a.*")
then: 'matcher is a RegexRequestMatcher'
matchers.collect {it.class } == [RegexRequestMatcher]
}
def "regexMatchers('/a.*') uses RegexRequestMatcher"() {
when:
def matchers = registry.regexMatchers("/a.*")
then: 'matcher is a RegexRequestMatcher'
matchers.collect {it.class } == [RegexRequestMatcher]
}
def "regexMatchers('/a.*') uses RegexRequestMatcher"() {
when:
def matchers = registry.regexMatchers("/a.*")
then: 'matcher is a RegexRequestMatcher'
matchers.collect {it.class } == [RegexRequestMatcher]
}
def "antMatchers(GET,'/a.*') uses AntPathRequestMatcher"() {
when:
def matchers = registry.antMatchers(HttpMethod.GET, "/a.*")
then: 'matcher is a RegexRequestMatcher'
matchers.collect {it.class } == [AntPathRequestMatcher]
}
def "antMatchers(GET,'/a.*') uses AntPathRequestMatcher"() {
when:
def matchers = registry.antMatchers(HttpMethod.GET, "/a.*")
then: 'matcher is a RegexRequestMatcher'
matchers.collect {it.class } == [AntPathRequestMatcher]
}
def "antMatchers('/a.*') uses AntPathRequestMatcher"() {
when:
def matchers = registry.antMatchers("/a.*")
then: 'matcher is a AntPathRequestMatcher'
matchers.collect {it.class } == [AntPathRequestMatcher]
}
def "antMatchers('/a.*') uses AntPathRequestMatcher"() {
when:
def matchers = registry.antMatchers("/a.*")
then: 'matcher is a AntPathRequestMatcher'
matchers.collect {it.class } == [AntPathRequestMatcher]
}
static class ConcreteAbstractRequestMatcherMappingConfigurer extends AbstractConfigAttributeRequestMatcherRegistry<List<RequestMatcher>> {
List<AccessDecisionVoter> decisionVoters() {
return null;
}
static class ConcreteAbstractRequestMatcherMappingConfigurer extends AbstractConfigAttributeRequestMatcherRegistry<List<RequestMatcher>> {
List<AccessDecisionVoter> decisionVoters() {
return null;
}
List<RequestMatcher> chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
return requestMatchers;
}
}
List<RequestMatcher> chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
return requestMatchers;
}
}
}
@@ -31,23 +31,23 @@ import org.springframework.security.web.authentication.logout.LogoutFilter
*/
class AnonymousConfigurerTests extends BaseSpringSpec {
def "invoke logout twice does not override"() {
when:
loadConfig(InvokeTwiceDoesNotOverride)
then:
findFilter(AnonymousAuthenticationFilter).key == "custom"
}
def "invoke logout twice does not override"() {
when:
loadConfig(InvokeTwiceDoesNotOverride)
then:
findFilter(AnonymousAuthenticationFilter).key == "custom"
}
@EnableWebSecurity
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.anonymous()
.key("custom")
.and()
.anonymous()
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.anonymous()
.key("custom")
.and()
.anonymous()
}
}
}
@@ -33,46 +33,46 @@ import org.springframework.security.web.access.channel.SecureChannelProcessor
*/
class ChannelSecurityConfigurerTests extends BaseSpringSpec {
def "requiresChannel ObjectPostProcessor"() {
setup: "initialize the AUTH_FILTER as a mock"
AnyObjectPostProcessor objectPostProcessor = Mock()
when:
HttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBldr, [:])
http
.requiresChannel()
.anyRequest().requiresSecure()
.and()
.build()
def "requiresChannel ObjectPostProcessor"() {
setup: "initialize the AUTH_FILTER as a mock"
AnyObjectPostProcessor objectPostProcessor = Mock()
when:
HttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBldr, [:])
http
.requiresChannel()
.anyRequest().requiresSecure()
.and()
.build()
then: "InsecureChannelProcessor is registered with LifecycleManager"
1 * objectPostProcessor.postProcess(_ as InsecureChannelProcessor) >> {InsecureChannelProcessor o -> o}
and: "SecureChannelProcessor is registered with LifecycleManager"
1 * objectPostProcessor.postProcess(_ as SecureChannelProcessor) >> {SecureChannelProcessor o -> o}
and: "ChannelDecisionManagerImpl is registered with LifecycleManager"
1 * objectPostProcessor.postProcess(_ as ChannelDecisionManagerImpl) >> {ChannelDecisionManagerImpl o -> o}
and: "ChannelProcessingFilter is registered with LifecycleManager"
1 * objectPostProcessor.postProcess(_ as ChannelProcessingFilter) >> {ChannelProcessingFilter o -> o}
}
then: "InsecureChannelProcessor is registered with LifecycleManager"
1 * objectPostProcessor.postProcess(_ as InsecureChannelProcessor) >> {InsecureChannelProcessor o -> o}
and: "SecureChannelProcessor is registered with LifecycleManager"
1 * objectPostProcessor.postProcess(_ as SecureChannelProcessor) >> {SecureChannelProcessor o -> o}
and: "ChannelDecisionManagerImpl is registered with LifecycleManager"
1 * objectPostProcessor.postProcess(_ as ChannelDecisionManagerImpl) >> {ChannelDecisionManagerImpl o -> o}
and: "ChannelProcessingFilter is registered with LifecycleManager"
1 * objectPostProcessor.postProcess(_ as ChannelProcessingFilter) >> {ChannelProcessingFilter o -> o}
}
def "invoke requiresChannel twice does not override"() {
setup:
loadConfig(DuplicateInvocationsDoesNotOverrideConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.redirectedUrl == "https://localhost"
}
def "invoke requiresChannel twice does not override"() {
setup:
loadConfig(DuplicateInvocationsDoesNotOverrideConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.redirectedUrl == "https://localhost"
}
@EnableWebSecurity
static class DuplicateInvocationsDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class DuplicateInvocationsDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requiresChannel()
.anyRequest().requiresSecure()
.and()
.requiresChannel()
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requiresChannel()
.anyRequest().requiresSecure()
.and()
.requiresChannel()
}
}
}
@@ -42,428 +42,428 @@ import spock.lang.Unroll
*/
class CsrfConfigurerTests extends BaseSpringSpec {
@Unroll
def "csrf applied by default"() {
setup:
loadConfig(CsrfAppliedDefaultConfig)
request.method = httpMethod
clearCsrfToken()
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == httpStatus
where:
httpMethod | httpStatus
'POST' | HttpServletResponse.SC_FORBIDDEN
'PUT' | HttpServletResponse.SC_FORBIDDEN
'PATCH' | HttpServletResponse.SC_FORBIDDEN
'DELETE' | HttpServletResponse.SC_FORBIDDEN
'INVALID' | HttpServletResponse.SC_FORBIDDEN
'GET' | HttpServletResponse.SC_OK
'HEAD' | HttpServletResponse.SC_OK
'TRACE' | HttpServletResponse.SC_OK
'OPTIONS' | HttpServletResponse.SC_OK
}
@Unroll
def "csrf applied by default"() {
setup:
loadConfig(CsrfAppliedDefaultConfig)
request.method = httpMethod
clearCsrfToken()
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == httpStatus
where:
httpMethod | httpStatus
'POST' | HttpServletResponse.SC_FORBIDDEN
'PUT' | HttpServletResponse.SC_FORBIDDEN
'PATCH' | HttpServletResponse.SC_FORBIDDEN
'DELETE' | HttpServletResponse.SC_FORBIDDEN
'INVALID' | HttpServletResponse.SC_FORBIDDEN
'GET' | HttpServletResponse.SC_OK
'HEAD' | HttpServletResponse.SC_OK
'TRACE' | HttpServletResponse.SC_OK
'OPTIONS' | HttpServletResponse.SC_OK
}
def "csrf default creates CsrfRequestDataValueProcessor"() {
when:
loadConfig(CsrfAppliedDefaultConfig)
then:
context.getBean(RequestDataValueProcessor)
}
def "csrf default creates CsrfRequestDataValueProcessor"() {
when:
loadConfig(CsrfAppliedDefaultConfig)
then:
context.getBean(RequestDataValueProcessor)
}
@EnableWebSecurity
static class CsrfAppliedDefaultConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class CsrfAppliedDefaultConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
}
}
def "csrf disable"() {
setup:
loadConfig(DisableCsrfConfig)
request.method = "POST"
clearCsrfToken()
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
!findFilter(CsrfFilter)
response.status == HttpServletResponse.SC_OK
}
def "csrf disable"() {
setup:
loadConfig(DisableCsrfConfig)
request.method = "POST"
clearCsrfToken()
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
!findFilter(CsrfFilter)
response.status == HttpServletResponse.SC_OK
}
@EnableWebSecurity
static class DisableCsrfConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class DisableCsrfConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
}
}
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'
}
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'
}
@EnableWebSecurity
static class DisableCsrfEnablesRequestCacheConfig extends WebSecurityConfigurerAdapter {
@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(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")
}
}
}
@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
}
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
}
@EnableWebSecurity
static class InvalidSessionUrlConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().and()
.sessionManagement()
.invalidSessionUrl("/error/sessionError")
}
}
@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)
RequireCsrfProtectionMatcherConfig.matcher.matches(_) >>> [false,true]
loadConfig(RequireCsrfProtectionMatcherConfig)
clearCsrfToken()
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == HttpServletResponse.SC_OK
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == HttpServletResponse.SC_FORBIDDEN
}
def "csrf requireCsrfProtectionMatcher"() {
setup:
RequireCsrfProtectionMatcherConfig.matcher = Mock(RequestMatcher)
RequireCsrfProtectionMatcherConfig.matcher.matches(_) >>> [false,true]
loadConfig(RequireCsrfProtectionMatcherConfig)
clearCsrfToken()
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == HttpServletResponse.SC_OK
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == HttpServletResponse.SC_FORBIDDEN
}
@EnableWebSecurity
static class RequireCsrfProtectionMatcherConfig extends WebSecurityConfigurerAdapter {
static RequestMatcher matcher
@EnableWebSecurity
static class RequireCsrfProtectionMatcherConfig extends WebSecurityConfigurerAdapter {
static RequestMatcher matcher
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.requireCsrfProtectionMatcher(matcher)
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.requireCsrfProtectionMatcher(matcher)
}
}
def "csrf csrfTokenRepository"() {
setup:
CsrfTokenRepositoryConfig.repo = Mock(CsrfTokenRepository)
loadConfig(CsrfTokenRepositoryConfig)
clearCsrfToken()
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
1 * CsrfTokenRepositoryConfig.repo.loadToken(_) >> csrfToken
response.status == HttpServletResponse.SC_OK
}
def "csrf csrfTokenRepository"() {
setup:
CsrfTokenRepositoryConfig.repo = Mock(CsrfTokenRepository)
loadConfig(CsrfTokenRepositoryConfig)
clearCsrfToken()
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
1 * CsrfTokenRepositoryConfig.repo.loadToken(_) >> csrfToken
response.status == HttpServletResponse.SC_OK
}
def "csrf clears on logout"() {
setup:
CsrfTokenRepositoryConfig.repo = Mock(CsrfTokenRepository)
1 * CsrfTokenRepositoryConfig.repo.loadToken(_) >> csrfToken
loadConfig(CsrfTokenRepositoryConfig)
login()
request.method = "POST"
request.servletPath = "/logout"
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
1 * CsrfTokenRepositoryConfig.repo.saveToken(null, _, _)
}
def "csrf clears on logout"() {
setup:
CsrfTokenRepositoryConfig.repo = Mock(CsrfTokenRepository)
1 * CsrfTokenRepositoryConfig.repo.loadToken(_) >> csrfToken
loadConfig(CsrfTokenRepositoryConfig)
login()
request.method = "POST"
request.servletPath = "/logout"
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
1 * CsrfTokenRepositoryConfig.repo.saveToken(null, _, _)
}
def "csrf clears on login"() {
setup:
CsrfTokenRepositoryConfig.repo = Mock(CsrfTokenRepository)
(1.._) * CsrfTokenRepositoryConfig.repo.loadToken(_) >> csrfToken
(1.._) * CsrfTokenRepositoryConfig.repo.generateToken(_) >> csrfToken
loadConfig(CsrfTokenRepositoryConfig)
request.method = "POST"
request.getSession()
request.servletPath = "/login"
request.setParameter("username", "user")
request.setParameter("password", "password")
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.redirectedUrl == "/"
(1.._) * CsrfTokenRepositoryConfig.repo.saveToken(null, _, _)
}
def "csrf clears on login"() {
setup:
CsrfTokenRepositoryConfig.repo = Mock(CsrfTokenRepository)
(1.._) * CsrfTokenRepositoryConfig.repo.loadToken(_) >> csrfToken
(1.._) * CsrfTokenRepositoryConfig.repo.generateToken(_) >> csrfToken
loadConfig(CsrfTokenRepositoryConfig)
request.method = "POST"
request.getSession()
request.servletPath = "/login"
request.setParameter("username", "user")
request.setParameter("password", "password")
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.redirectedUrl == "/"
(1.._) * CsrfTokenRepositoryConfig.repo.saveToken(null, _, _)
}
@EnableWebSecurity
static class CsrfTokenRepositoryConfig extends WebSecurityConfigurerAdapter {
static CsrfTokenRepository repo
@EnableWebSecurity
static class CsrfTokenRepositoryConfig extends WebSecurityConfigurerAdapter {
static CsrfTokenRepository repo
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.and()
.csrf()
.csrfTokenRepository(repo)
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.and()
.csrf()
.csrfTokenRepository(repo)
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
}
def "csrf access denied handler"() {
setup:
AccessDeniedHandlerConfig.deniedHandler = Mock(AccessDeniedHandler)
1 * AccessDeniedHandlerConfig.deniedHandler.handle(_, _, _)
loadConfig(AccessDeniedHandlerConfig)
clearCsrfToken()
request.method = "POST"
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == HttpServletResponse.SC_OK
}
def "csrf access denied handler"() {
setup:
AccessDeniedHandlerConfig.deniedHandler = Mock(AccessDeniedHandler)
1 * AccessDeniedHandlerConfig.deniedHandler.handle(_, _, _)
loadConfig(AccessDeniedHandlerConfig)
clearCsrfToken()
request.method = "POST"
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == HttpServletResponse.SC_OK
}
@EnableWebSecurity
static class AccessDeniedHandlerConfig extends WebSecurityConfigurerAdapter {
static AccessDeniedHandler deniedHandler
@EnableWebSecurity
static class AccessDeniedHandlerConfig extends WebSecurityConfigurerAdapter {
static AccessDeniedHandler deniedHandler
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.accessDeniedHandler(deniedHandler)
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.accessDeniedHandler(deniedHandler)
}
}
def "formLogin requires CSRF token"() {
setup:
loadConfig(FormLoginConfig)
clearCsrfToken()
request.setParameter("username", "user")
request.setParameter("password", "password")
request.servletPath = "/login"
request.method = "POST"
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == HttpServletResponse.SC_FORBIDDEN
currentAuthentication == null
}
def "formLogin requires CSRF token"() {
setup:
loadConfig(FormLoginConfig)
clearCsrfToken()
request.setParameter("username", "user")
request.setParameter("password", "password")
request.servletPath = "/login"
request.method = "POST"
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == HttpServletResponse.SC_FORBIDDEN
currentAuthentication == null
}
@EnableWebSecurity
static class FormLoginConfig extends WebSecurityConfigurerAdapter {
static AccessDeniedHandler deniedHandler
@EnableWebSecurity
static class FormLoginConfig extends WebSecurityConfigurerAdapter {
static AccessDeniedHandler deniedHandler
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
}
}
def "logout requires CSRF token"() {
setup:
loadConfig(LogoutConfig)
clearCsrfToken()
login()
request.servletPath = "/logout"
request.method = "POST"
when:
springSecurityFilterChain.doFilter(request,response,chain)
then: "logout is not allowed and user is still authenticated"
response.status == HttpServletResponse.SC_FORBIDDEN
currentAuthentication != null
}
def "logout requires CSRF token"() {
setup:
loadConfig(LogoutConfig)
clearCsrfToken()
login()
request.servletPath = "/logout"
request.method = "POST"
when:
springSecurityFilterChain.doFilter(request,response,chain)
then: "logout is not allowed and user is still authenticated"
response.status == HttpServletResponse.SC_FORBIDDEN
currentAuthentication != null
}
def "SEC-2543: CSRF means logout requires POST"() {
setup:
loadConfig(LogoutConfig)
login()
request.servletPath = "/logout"
request.method = "GET"
when:
springSecurityFilterChain.doFilter(request,response,chain)
then: "logout with GET is not performed"
currentAuthentication != null
}
def "SEC-2543: CSRF means logout requires POST"() {
setup:
loadConfig(LogoutConfig)
login()
request.servletPath = "/logout"
request.method = "GET"
when:
springSecurityFilterChain.doFilter(request,response,chain)
then: "logout with GET is not performed"
currentAuthentication != null
}
@EnableWebSecurity
static class LogoutConfig extends WebSecurityConfigurerAdapter {
static AccessDeniedHandler deniedHandler
@EnableWebSecurity
static class LogoutConfig extends WebSecurityConfigurerAdapter {
static AccessDeniedHandler deniedHandler
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
}
}
def "CSRF can explicitly enable GET for logout"() {
setup:
loadConfig(LogoutAllowsGetConfig)
login()
request.servletPath = "/logout"
request.method = "GET"
when:
springSecurityFilterChain.doFilter(request,response,chain)
then: "logout with GET is not performed"
currentAuthentication == null
}
def "CSRF can explicitly enable GET for logout"() {
setup:
loadConfig(LogoutAllowsGetConfig)
login()
request.servletPath = "/logout"
request.method = "GET"
when:
springSecurityFilterChain.doFilter(request,response,chain)
then: "logout with GET is not performed"
currentAuthentication == null
}
@EnableWebSecurity
static class LogoutAllowsGetConfig extends WebSecurityConfigurerAdapter {
static AccessDeniedHandler deniedHandler
@EnableWebSecurity
static class LogoutAllowsGetConfig extends WebSecurityConfigurerAdapter {
static AccessDeniedHandler deniedHandler
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin().and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin().and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
}
}
def "csrf disables POST requests from RequestCache"() {
setup:
CsrfDisablesPostRequestFromRequestCacheConfig.repo = Mock(CsrfTokenRepository)
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.generateToken(_) >> csrfToken
loadConfig(CsrfDisablesPostRequestFromRequestCacheConfig)
request.servletPath = "/some-url"
request.requestURI = "/some-url"
request.method = "POST"
when: "CSRF passes and our session times out"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to the login page"
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "http://localhost/login"
when: "authenticate successfully"
super.setupWeb(request.session)
request.servletPath = "/login"
request.setParameter("username","user")
request.setParameter("password","password")
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
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "/"
}
def "csrf disables POST requests from RequestCache"() {
setup:
CsrfDisablesPostRequestFromRequestCacheConfig.repo = Mock(CsrfTokenRepository)
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.generateToken(_) >> csrfToken
loadConfig(CsrfDisablesPostRequestFromRequestCacheConfig)
request.servletPath = "/some-url"
request.requestURI = "/some-url"
request.method = "POST"
when: "CSRF passes and our session times out"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to the login page"
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "http://localhost/login"
when: "authenticate successfully"
super.setupWeb(request.session)
request.servletPath = "/login"
request.setParameter("username","user")
request.setParameter("password","password")
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
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "/"
}
def "csrf enables GET requests with RequestCache"() {
setup:
CsrfDisablesPostRequestFromRequestCacheConfig.repo = Mock(CsrfTokenRepository)
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.generateToken(_) >> csrfToken
loadConfig(CsrfDisablesPostRequestFromRequestCacheConfig)
request.servletPath = "/some-url"
request.requestURI = "/some-url"
request.method = "GET"
when: "CSRF passes and our session times out"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to the login page"
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "http://localhost/login"
when: "authenticate successfully"
super.setupWeb(request.session)
request.servletPath = "/login"
request.setParameter("username","user")
request.setParameter("password","password")
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to original URL since it was a GET"
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "http://localhost/some-url"
}
def "csrf enables GET requests with RequestCache"() {
setup:
CsrfDisablesPostRequestFromRequestCacheConfig.repo = Mock(CsrfTokenRepository)
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.generateToken(_) >> csrfToken
loadConfig(CsrfDisablesPostRequestFromRequestCacheConfig)
request.servletPath = "/some-url"
request.requestURI = "/some-url"
request.method = "GET"
when: "CSRF passes and our session times out"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to the login page"
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "http://localhost/login"
when: "authenticate successfully"
super.setupWeb(request.session)
request.servletPath = "/login"
request.setParameter("username","user")
request.setParameter("password","password")
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to original URL since it was a GET"
(1.._) * CsrfDisablesPostRequestFromRequestCacheConfig.repo.loadToken(_) >> csrfToken
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "http://localhost/some-url"
}
@EnableWebSecurity
static class CsrfDisablesPostRequestFromRequestCacheConfig extends WebSecurityConfigurerAdapter {
static CsrfTokenRepository repo
@EnableWebSecurity
static class CsrfDisablesPostRequestFromRequestCacheConfig extends WebSecurityConfigurerAdapter {
static CsrfTokenRepository repo
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.csrf()
.csrfTokenRepository(repo)
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.csrf()
.csrfTokenRepository(repo)
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
}
def 'SEC-2749: requireCsrfProtectionMatcher null'() {
when:
new CsrfConfigurer<>().requireCsrfProtectionMatcher(null)
then:
thrown(IllegalArgumentException)
}
def 'SEC-2749: requireCsrfProtectionMatcher null'() {
when:
new CsrfConfigurer<>().requireCsrfProtectionMatcher(null)
then:
thrown(IllegalArgumentException)
}
def clearCsrfToken() {
request.removeAllParameters()
}
def clearCsrfToken() {
request.removeAllParameters()
}
}
@@ -54,103 +54,103 @@ import org.springframework.security.web.util.matcher.AnyRequestMatcher
*/
class DefaultFiltersTests extends BaseSpringSpec {
def "Default the WebSecurityConfigurerAdapter"() {
when:
context = new AnnotationConfigApplicationContext(FilterChainProxyBuilderMissingConfig)
then:
context.getBean(FilterChainProxy) != null
}
def "Default the WebSecurityConfigurerAdapter"() {
when:
context = new AnnotationConfigApplicationContext(FilterChainProxyBuilderMissingConfig)
then:
context.getBean(FilterChainProxy) != null
}
@EnableWebSecurity
static class FilterChainProxyBuilderMissingConfig {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
}
@EnableWebSecurity
static class FilterChainProxyBuilderMissingConfig {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
}
@EnableWebSecurity
static class FilterChainProxyBuilderNoSecurityFilterBuildersConfig {
@Bean
public WebSecurity filterChainProxyBuilder(ObjectPostProcessor<Object> opp) {
new WebSecurity(opp)
.ignoring()
.antMatchers("/resources/**")
}
}
@EnableWebSecurity
static class FilterChainProxyBuilderNoSecurityFilterBuildersConfig {
@Bean
public WebSecurity filterChainProxyBuilder(ObjectPostProcessor<Object> opp) {
new WebSecurity(opp)
.ignoring()
.antMatchers("/resources/**")
}
}
def "null WebInvocationPrivilegeEvaluator"() {
when:
context = new AnnotationConfigApplicationContext(NullWebInvocationPrivilegeEvaluatorConfig)
then:
List<DefaultSecurityFilterChain> filterChains = context.getBean(FilterChainProxy).filterChains
filterChains.size() == 1
filterChains[0].requestMatcher instanceof AnyRequestMatcher
filterChains[0].filters.size() == 1
filterChains[0].filters.find { it instanceof UsernamePasswordAuthenticationFilter }
}
def "null WebInvocationPrivilegeEvaluator"() {
when:
context = new AnnotationConfigApplicationContext(NullWebInvocationPrivilegeEvaluatorConfig)
then:
List<DefaultSecurityFilterChain> filterChains = context.getBean(FilterChainProxy).filterChains
filterChains.size() == 1
filterChains[0].requestMatcher instanceof AnyRequestMatcher
filterChains[0].filters.size() == 1
filterChains[0].filters.find { it instanceof UsernamePasswordAuthenticationFilter }
}
@EnableWebSecurity
static class NullWebInvocationPrivilegeEvaluatorConfig extends BaseWebConfig {
NullWebInvocationPrivilegeEvaluatorConfig() {
super(true)
}
@EnableWebSecurity
static class NullWebInvocationPrivilegeEvaluatorConfig extends BaseWebConfig {
NullWebInvocationPrivilegeEvaluatorConfig() {
super(true)
}
protected void configure(HttpSecurity http) {
http.formLogin()
}
}
protected void configure(HttpSecurity http) {
http.formLogin()
}
}
def "FilterChainProxyBuilder ignoring resources"() {
when:
loadConfig(FilterChainProxyBuilderIgnoringConfig)
then:
List<DefaultSecurityFilterChain> filterChains = context.getBean(FilterChainProxy).filterChains
filterChains.size() == 2
filterChains[0].requestMatcher.pattern == '/resources/**'
filterChains[0].filters.empty
filterChains[1].requestMatcher instanceof AnyRequestMatcher
filterChains[1].filters.collect { it.class } ==
[WebAsyncManagerIntegrationFilter, SecurityContextPersistenceFilter, HeaderWriterFilter, CsrfFilter, LogoutFilter, RequestCacheAwareFilter,
SecurityContextHolderAwareRequestFilter, AnonymousAuthenticationFilter, SessionManagementFilter,
ExceptionTranslationFilter, FilterSecurityInterceptor ]
}
def "FilterChainProxyBuilder ignoring resources"() {
when:
loadConfig(FilterChainProxyBuilderIgnoringConfig)
then:
List<DefaultSecurityFilterChain> filterChains = context.getBean(FilterChainProxy).filterChains
filterChains.size() == 2
filterChains[0].requestMatcher.pattern == '/resources/**'
filterChains[0].filters.empty
filterChains[1].requestMatcher instanceof AnyRequestMatcher
filterChains[1].filters.collect { it.class } ==
[WebAsyncManagerIntegrationFilter, SecurityContextPersistenceFilter, HeaderWriterFilter, CsrfFilter, LogoutFilter, RequestCacheAwareFilter,
SecurityContextHolderAwareRequestFilter, AnonymousAuthenticationFilter, SessionManagementFilter,
ExceptionTranslationFilter, FilterSecurityInterceptor ]
}
@EnableWebSecurity
static class FilterChainProxyBuilderIgnoringConfig extends BaseWebConfig {
@Override
public void configure(WebSecurity builder) throws Exception {
builder
.ignoring()
.antMatchers("/resources/**");
}
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER");
}
}
@EnableWebSecurity
static class FilterChainProxyBuilderIgnoringConfig extends BaseWebConfig {
@Override
public void configure(WebSecurity builder) throws Exception {
builder
.ignoring()
.antMatchers("/resources/**");
}
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER");
}
}
def "DefaultFilters.permitAll()"() {
when:
loadConfig(DefaultFiltersConfigPermitAll)
MockHttpServletResponse response = new MockHttpServletResponse()
request = new MockHttpServletRequest(servletPath : uri, queryString: query, method:"POST")
setupCsrf()
springSecurityFilterChain.doFilter(request, response, new MockFilterChain())
then:
response.redirectedUrl == "/login?logout"
where:
uri | query
"/logout" | null
}
when:
loadConfig(DefaultFiltersConfigPermitAll)
MockHttpServletResponse response = new MockHttpServletResponse()
request = new MockHttpServletRequest(servletPath : uri, queryString: query, method:"POST")
setupCsrf()
springSecurityFilterChain.doFilter(request, response, new MockFilterChain())
then:
response.redirectedUrl == "/login?logout"
where:
uri | query
"/logout" | null
}
@EnableWebSecurity
static class DefaultFiltersConfigPermitAll extends BaseWebConfig {
protected void configure(HttpSecurity http) {
}
}
@EnableWebSecurity
static class DefaultFiltersConfigPermitAll extends BaseWebConfig {
protected void configure(HttpSecurity http) {
}
}
}
@@ -1,5 +1,3 @@
/*
* Copyright 2002-2013 the original author or authors.
*
@@ -42,295 +40,295 @@ import org.springframework.security.web.authentication.ui.DefaultLoginPageGenera
*
*/
public class DefaultLoginPageConfigurerTests extends BaseSpringSpec {
def "http/form-login default login generating page"() {
setup:
loadConfig(DefaultLoginPageConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
findFilter(DefaultLoginPageGeneratingFilter)
response.getRedirectedUrl() == "http://localhost/login"
when: "request the login page"
super.setup()
request.requestURI = "/login"
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
def "http/form-login default login generating page"() {
setup:
loadConfig(DefaultLoginPageConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
findFilter(DefaultLoginPageGeneratingFilter)
response.getRedirectedUrl() == "http://localhost/login"
when: "request the login page"
super.setup()
request.requestURI = "/login"
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
<h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
<table>
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
</table>
<table>
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
</table>
</form></body></html>"""
when: "fail to log in"
super.setup()
request.servletPath = "/login"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/login?error"
when: "request the error page"
HttpSession session = request.session
super.setup()
request.session = session
request.requestURI = "/login"
request.queryString = "error"
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
when: "fail to log in"
super.setup()
request.servletPath = "/login"
request.method = "POST"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to login error page"
response.getRedirectedUrl() == "/login?error"
when: "request the error page"
HttpSession session = request.session
super.setup()
request.session = session
request.requestURI = "/login"
request.queryString = "error"
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
<p><font color='red'>Your login attempt was not successful, try again.<br/><br/>Reason: Bad credentials</font></p><h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
<table>
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
</table>
<table>
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
</table>
</form></body></html>"""
when: "login success"
super.setup()
request.servletPath = "/login"
request.method = "POST"
request.parameters.username = ["user"] as String[]
request.parameters.password = ["password"] as String[]
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default succes page"
response.getRedirectedUrl() == "/"
}
when: "login success"
super.setup()
request.servletPath = "/login"
request.method = "POST"
request.parameters.username = ["user"] as String[]
request.parameters.password = ["password"] as String[]
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default succes page"
response.getRedirectedUrl() == "/"
}
def "logout success renders"() {
setup:
loadConfig(DefaultLoginPageConfig)
when: "logout success"
request.requestURI = "/login"
request.queryString = "logout"
request.method = "GET"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default success page"
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
def "logout success renders"() {
setup:
loadConfig(DefaultLoginPageConfig)
when: "logout success"
request.requestURI = "/login"
request.queryString = "logout"
request.method = "GET"
springSecurityFilterChain.doFilter(request,response,chain)
then: "sent to default success page"
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
<p><font color='green'>You have been logged out</font></p><h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
<table>
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
</table>
<table>
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
</table>
</form></body></html>"""
}
}
@Configuration
static class DefaultLoginPageConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
}
}
@Configuration
static class DefaultLoginPageConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
}
}
def "custom logout success handler prevents rendering"() {
setup:
loadConfig(DefaultLoginPageCustomLogoutSuccessHandlerConfig)
when: "logout success"
request.requestURI = "/login"
request.queryString = "logout"
request.method = "GET"
springSecurityFilterChain.doFilter(request,response,chain)
then: "default success page is NOT rendered (application is in charge of it)"
response.getContentAsString() == ""
}
def "custom logout success handler prevents rendering"() {
setup:
loadConfig(DefaultLoginPageCustomLogoutSuccessHandlerConfig)
when: "logout success"
request.requestURI = "/login"
request.queryString = "logout"
request.method = "GET"
springSecurityFilterChain.doFilter(request,response,chain)
then: "default success page is NOT rendered (application is in charge of it)"
response.getContentAsString() == ""
}
@Configuration
static class DefaultLoginPageCustomLogoutSuccessHandlerConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.logout()
.logoutSuccessHandler(new SimpleUrlLogoutSuccessHandler())
.and()
.formLogin()
}
}
@Configuration
static class DefaultLoginPageCustomLogoutSuccessHandlerConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.logout()
.logoutSuccessHandler(new SimpleUrlLogoutSuccessHandler())
.and()
.formLogin()
}
}
def "custom logout success url prevents rendering"() {
setup:
loadConfig(DefaultLoginPageCustomLogoutConfig)
when: "logout success"
request.requestURI = "/login"
request.queryString = "logout"
request.method = "GET"
springSecurityFilterChain.doFilter(request,response,chain)
then: "default success page is NOT rendered (application is in charge of it)"
response.getContentAsString() == ""
}
def "custom logout success url prevents rendering"() {
setup:
loadConfig(DefaultLoginPageCustomLogoutConfig)
when: "logout success"
request.requestURI = "/login"
request.queryString = "logout"
request.method = "GET"
springSecurityFilterChain.doFilter(request,response,chain)
then: "default success page is NOT rendered (application is in charge of it)"
response.getContentAsString() == ""
}
@Configuration
static class DefaultLoginPageCustomLogoutConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.logout()
.logoutSuccessUrl("/login?logout")
.and()
.formLogin()
}
}
@Configuration
static class DefaultLoginPageCustomLogoutConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.logout()
.logoutSuccessUrl("/login?logout")
.and()
.formLogin()
}
}
def "http/form-login default login with remember me"() {
setup:
loadConfig(DefaultLoginPageWithRememberMeConfig)
when: "request the login page"
super.setup()
request.requestURI = "/login"
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
def "http/form-login default login with remember me"() {
setup:
loadConfig(DefaultLoginPageWithRememberMeConfig)
when: "request the login page"
super.setup()
request.requestURI = "/login"
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
<h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
<table>
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
<tr><td><input type='checkbox' name='remember-me'/></td><td>Remember me on this computer.</td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
</table>
<table>
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
<tr><td><input type='checkbox' name='remember-me'/></td><td>Remember me on this computer.</td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
</table>
</form></body></html>"""
}
}
@Configuration
static class DefaultLoginPageWithRememberMeConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.and()
.rememberMe()
}
}
@Configuration
static class DefaultLoginPageWithRememberMeConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.and()
.rememberMe()
}
}
def "http/form-login default login with openid"() {
setup:
loadConfig(DefaultLoginPageWithOpenIDConfig)
when: "request the login page"
request.requestURI = "/login"
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><h3>Login with OpenID Identity</h3><form name='oidf' action='/login/openid' 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>
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
def "http/form-login default login with openid"() {
setup:
loadConfig(DefaultLoginPageWithOpenIDConfig)
when: "request the login page"
request.requestURI = "/login"
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><h3>Login with OpenID Identity</h3><form name='oidf' action='/login/openid' 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>
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
</form></body></html>"""
}
}
@Configuration
static class DefaultLoginPageWithOpenIDConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.openidLogin()
}
}
@Configuration
static class DefaultLoginPageWithOpenIDConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.openidLogin()
}
}
def "http/form-login default login with openid, form login, and rememberme"() {
setup:
loadConfig(DefaultLoginPageWithFormLoginOpenIDRememberMeConfig)
when: "request the login page"
request.requestURI = "/login"
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
def "http/form-login default login with openid, form login, and rememberme"() {
setup:
loadConfig(DefaultLoginPageWithFormLoginOpenIDRememberMeConfig)
when: "request the login page"
request.requestURI = "/login"
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
<h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
<table>
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
<tr><td><input type='checkbox' name='remember-me'/></td><td>Remember me on this computer.</td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
</table>
<table>
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
<tr><td><input type='checkbox' name='remember-me'/></td><td>Remember me on this computer.</td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
</table>
</form><h3>Login with OpenID Identity</h3><form name='oidf' action='/login/openid' method='POST'>
<table>
<tr><td>Identity:</td><td><input type='text' size='30' name='openid_identifier'/></td></tr>
<tr><td><input type='checkbox' name='remember-me'></td><td>Remember me on this computer.</td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
</table>
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
<table>
<tr><td>Identity:</td><td><input type='text' size='30' name='openid_identifier'/></td></tr>
<tr><td><input type='checkbox' name='remember-me'></td><td>Remember me on this computer.</td></tr>
<tr><td colspan='2'><input name="submit" type="submit" value="Login"/></td></tr>
</table>
<input name="${csrfToken.parameterName}" type="hidden" value="${csrfToken.token}" />
</form></body></html>"""
}
}
@Configuration
static class DefaultLoginPageWithFormLoginOpenIDRememberMeConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.rememberMe()
.and()
.formLogin()
.and()
.openidLogin()
}
}
@Configuration
static class DefaultLoginPageWithFormLoginOpenIDRememberMeConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.rememberMe()
.and()
.formLogin()
.and()
.openidLogin()
}
}
def "default login with custom AuthenticationEntryPoint"() {
when:
loadConfig(DefaultLoginWithCustomAuthenticationEntryPointConfig)
then:
!findFilter(DefaultLoginPageGeneratingFilter)
}
def "default login with custom AuthenticationEntryPoint"() {
when:
loadConfig(DefaultLoginWithCustomAuthenticationEntryPointConfig)
then:
!findFilter(DefaultLoginPageGeneratingFilter)
}
@Configuration
static class DefaultLoginWithCustomAuthenticationEntryPointConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
.and()
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
}
}
@Configuration
static class DefaultLoginWithCustomAuthenticationEntryPointConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
.and()
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
}
}
def "DefaultLoginPage ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor objectPostProcessor = Mock()
when:
HttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBldr, [:])
DefaultLoginPageConfigurer defaultLoginConfig = new DefaultLoginPageConfigurer([builder:http])
defaultLoginConfig.addObjectPostProcessor(objectPostProcessor)
http
// must set builder manually due to groovy not selecting correct method
.apply(defaultLoginConfig).and()
.exceptionHandling()
.and()
.formLogin()
.and()
.build()
def "DefaultLoginPage ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor objectPostProcessor = Mock()
when:
HttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBldr, [:])
DefaultLoginPageConfigurer defaultLoginConfig = new DefaultLoginPageConfigurer([builder:http])
defaultLoginConfig.addObjectPostProcessor(objectPostProcessor)
http
// must set builder manually due to groovy not selecting correct method
.apply(defaultLoginConfig).and()
.exceptionHandling()
.and()
.formLogin()
.and()
.build()
then: "DefaultLoginPageGeneratingFilter is registered with LifecycleManager"
1 * objectPostProcessor.postProcess(_ as DefaultLoginPageGeneratingFilter) >> {DefaultLoginPageGeneratingFilter o -> o}
1 * objectPostProcessor.postProcess(_ as UsernamePasswordAuthenticationFilter) >> {UsernamePasswordAuthenticationFilter o -> o}
1 * objectPostProcessor.postProcess(_ as LoginUrlAuthenticationEntryPoint) >> {LoginUrlAuthenticationEntryPoint o -> o}
1 * objectPostProcessor.postProcess(_ as ExceptionTranslationFilter) >> {ExceptionTranslationFilter o -> o}
}
then: "DefaultLoginPageGeneratingFilter is registered with LifecycleManager"
1 * objectPostProcessor.postProcess(_ as DefaultLoginPageGeneratingFilter) >> {DefaultLoginPageGeneratingFilter o -> o}
1 * objectPostProcessor.postProcess(_ as UsernamePasswordAuthenticationFilter) >> {UsernamePasswordAuthenticationFilter o -> o}
1 * objectPostProcessor.postProcess(_ as LoginUrlAuthenticationEntryPoint) >> {LoginUrlAuthenticationEntryPoint o -> o}
1 * objectPostProcessor.postProcess(_ as ExceptionTranslationFilter) >> {ExceptionTranslationFilter o -> o}
}
}
@@ -46,153 +46,153 @@ import spock.lang.Unroll
*/
class ExceptionHandlingConfigurerTests extends BaseSpringSpec {
def "exception ObjectPostProcessor"() {
setup: "initialize the AUTH_FILTER as a mock"
AnyObjectPostProcessor opp = Mock()
when:
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
http
.exceptionHandling()
.and()
.build()
def "exception ObjectPostProcessor"() {
setup: "initialize the AUTH_FILTER as a mock"
AnyObjectPostProcessor opp = Mock()
when:
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
http
.exceptionHandling()
.and()
.build()
then: "ExceptionTranslationFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as ExceptionTranslationFilter) >> {ExceptionTranslationFilter o -> o}
}
then: "ExceptionTranslationFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as ExceptionTranslationFilter) >> {ExceptionTranslationFilter o -> o}
}
@Unroll
def "SEC-2199: defaultEntryPoint for httpBasic and formLogin"(String acceptHeader, int httpStatus) {
setup:
loadConfig(HttpBasicAndFormLoginEntryPointsConfig)
when:
request.addHeader("Accept", acceptHeader)
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == httpStatus
where:
acceptHeader | httpStatus
MediaType.APPLICATION_XHTML_XML_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
MediaType.IMAGE_GIF_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
MediaType.IMAGE_JPEG_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
MediaType.IMAGE_PNG_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
MediaType.TEXT_HTML_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
MediaType.TEXT_PLAIN_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
MediaType.APPLICATION_ATOM_XML_VALUE | HttpServletResponse.SC_UNAUTHORIZED
MediaType.APPLICATION_FORM_URLENCODED_VALUE | HttpServletResponse.SC_UNAUTHORIZED
MediaType.APPLICATION_JSON_VALUE | HttpServletResponse.SC_UNAUTHORIZED
MediaType.APPLICATION_OCTET_STREAM_VALUE | HttpServletResponse.SC_UNAUTHORIZED
MediaType.APPLICATION_XML_VALUE | HttpServletResponse.SC_UNAUTHORIZED
MediaType.MULTIPART_FORM_DATA_VALUE | HttpServletResponse.SC_UNAUTHORIZED
MediaType.TEXT_XML_VALUE | HttpServletResponse.SC_UNAUTHORIZED
}
@Unroll
def "SEC-2199: defaultEntryPoint for httpBasic and formLogin"(String acceptHeader, int httpStatus) {
setup:
loadConfig(HttpBasicAndFormLoginEntryPointsConfig)
when:
request.addHeader("Accept", acceptHeader)
springSecurityFilterChain.doFilter(request,response,chain)
then:
response.status == httpStatus
where:
acceptHeader | httpStatus
MediaType.APPLICATION_XHTML_XML_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
MediaType.IMAGE_GIF_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
MediaType.IMAGE_JPEG_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
MediaType.IMAGE_PNG_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
MediaType.TEXT_HTML_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
MediaType.TEXT_PLAIN_VALUE | HttpServletResponse.SC_MOVED_TEMPORARILY
MediaType.APPLICATION_ATOM_XML_VALUE | HttpServletResponse.SC_UNAUTHORIZED
MediaType.APPLICATION_FORM_URLENCODED_VALUE | HttpServletResponse.SC_UNAUTHORIZED
MediaType.APPLICATION_JSON_VALUE | HttpServletResponse.SC_UNAUTHORIZED
MediaType.APPLICATION_OCTET_STREAM_VALUE | HttpServletResponse.SC_UNAUTHORIZED
MediaType.APPLICATION_XML_VALUE | HttpServletResponse.SC_UNAUTHORIZED
MediaType.MULTIPART_FORM_DATA_VALUE | HttpServletResponse.SC_UNAUTHORIZED
MediaType.TEXT_XML_VALUE | HttpServletResponse.SC_UNAUTHORIZED
}
def "ContentNegotiationStrategy defaults to HeaderContentNegotiationStrategy"() {
when:
loadConfig(HttpBasicAndFormLoginEntryPointsConfig)
DelegatingAuthenticationEntryPoint delegateEntryPoint = findFilter(ExceptionTranslationFilter).authenticationEntryPoint
then:
delegateEntryPoint.entryPoints.keySet().collect {it.contentNegotiationStrategy.class} == [HeaderContentNegotiationStrategy,HeaderContentNegotiationStrategy]
}
def "ContentNegotiationStrategy defaults to HeaderContentNegotiationStrategy"() {
when:
loadConfig(HttpBasicAndFormLoginEntryPointsConfig)
DelegatingAuthenticationEntryPoint delegateEntryPoint = findFilter(ExceptionTranslationFilter).authenticationEntryPoint
then:
delegateEntryPoint.entryPoints.keySet().collect {it.contentNegotiationStrategy.class} == [HeaderContentNegotiationStrategy,HeaderContentNegotiationStrategy]
}
@EnableWebSecurity
static class HttpBasicAndFormLoginEntryPointsConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class HttpBasicAndFormLoginEntryPointsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.formLogin()
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.formLogin()
}
}
def "ContentNegotiationStrategy overrides with @Bean"() {
setup:
OverrideContentNegotiationStrategySharedObjectConfig.CNS = Mock(ContentNegotiationStrategy)
when:
loadConfig(OverrideContentNegotiationStrategySharedObjectConfig)
DelegatingAuthenticationEntryPoint delegateEntryPoint = findFilter(ExceptionTranslationFilter).authenticationEntryPoint
then:
delegateEntryPoint.entryPoints.keySet().collect {it.contentNegotiationStrategy} == [OverrideContentNegotiationStrategySharedObjectConfig.CNS,OverrideContentNegotiationStrategySharedObjectConfig.CNS]
}
def "ContentNegotiationStrategy overrides with @Bean"() {
setup:
OverrideContentNegotiationStrategySharedObjectConfig.CNS = Mock(ContentNegotiationStrategy)
when:
loadConfig(OverrideContentNegotiationStrategySharedObjectConfig)
DelegatingAuthenticationEntryPoint delegateEntryPoint = findFilter(ExceptionTranslationFilter).authenticationEntryPoint
then:
delegateEntryPoint.entryPoints.keySet().collect {it.contentNegotiationStrategy} == [OverrideContentNegotiationStrategySharedObjectConfig.CNS,OverrideContentNegotiationStrategySharedObjectConfig.CNS]
}
def "Override ContentNegotiationStrategy with @Bean"() {
setup:
OverrideContentNegotiationStrategySharedObjectConfig.CNS = Mock(ContentNegotiationStrategy)
when:
loadConfig(OverrideContentNegotiationStrategySharedObjectConfig)
then:
context.getBean(OverrideContentNegotiationStrategySharedObjectConfig).http.getSharedObject(ContentNegotiationStrategy) == OverrideContentNegotiationStrategySharedObjectConfig.CNS
}
def "Override ContentNegotiationStrategy with @Bean"() {
setup:
OverrideContentNegotiationStrategySharedObjectConfig.CNS = Mock(ContentNegotiationStrategy)
when:
loadConfig(OverrideContentNegotiationStrategySharedObjectConfig)
then:
context.getBean(OverrideContentNegotiationStrategySharedObjectConfig).http.getSharedObject(ContentNegotiationStrategy) == OverrideContentNegotiationStrategySharedObjectConfig.CNS
}
@EnableWebSecurity
static class OverrideContentNegotiationStrategySharedObjectConfig extends WebSecurityConfigurerAdapter {
static ContentNegotiationStrategy CNS
@EnableWebSecurity
static class OverrideContentNegotiationStrategySharedObjectConfig extends WebSecurityConfigurerAdapter {
static ContentNegotiationStrategy CNS
@Bean
public ContentNegotiationStrategy cns() {
return CNS
}
}
@Bean
public ContentNegotiationStrategy cns() {
return CNS
}
}
def "delegatingAuthenticationEntryPoint.defaultEntryPoint is LoginUrlAuthenticationEntryPoint when using DefaultHttpConf"() {
when:
loadConfig(DefaultHttpConf)
then:
findFilter(ExceptionTranslationFilter).authenticationEntryPoint.defaultEntryPoint.class == LoginUrlAuthenticationEntryPoint
}
def "delegatingAuthenticationEntryPoint.defaultEntryPoint is LoginUrlAuthenticationEntryPoint when using DefaultHttpConf"() {
when:
loadConfig(DefaultHttpConf)
then:
findFilter(ExceptionTranslationFilter).authenticationEntryPoint.defaultEntryPoint.class == LoginUrlAuthenticationEntryPoint
}
@EnableWebSecurity
static class DefaultHttpConf extends WebSecurityConfigurerAdapter {
}
@EnableWebSecurity
static class DefaultHttpConf extends WebSecurityConfigurerAdapter {
}
def "delegatingAuthenticationEntryPoint.defaultEntryPoint is BasicAuthenticationEntryPoint when httpBasic before formLogin"() {
when:
loadConfig(BasicAuthenticationEntryPointBeforeFormLoginConf)
then:
findFilter(ExceptionTranslationFilter).authenticationEntryPoint.defaultEntryPoint.defaultEntryPoint.class == BasicAuthenticationEntryPoint
}
def "delegatingAuthenticationEntryPoint.defaultEntryPoint is BasicAuthenticationEntryPoint when httpBasic before formLogin"() {
when:
loadConfig(BasicAuthenticationEntryPointBeforeFormLoginConf)
then:
findFilter(ExceptionTranslationFilter).authenticationEntryPoint.defaultEntryPoint.defaultEntryPoint.class == BasicAuthenticationEntryPoint
}
@EnableWebSecurity
static class BasicAuthenticationEntryPointBeforeFormLoginConf extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.formLogin()
}
}
@EnableWebSecurity
static class BasicAuthenticationEntryPointBeforeFormLoginConf extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.formLogin()
}
}
def "invoke exceptionHandling twice does not override"() {
setup:
InvokeTwiceDoesNotOverrideConfig.AEP = Mock(AuthenticationEntryPoint)
when:
loadConfig(InvokeTwiceDoesNotOverrideConfig)
then:
findFilter(ExceptionTranslationFilter).authenticationEntryPoint == InvokeTwiceDoesNotOverrideConfig.AEP
}
def "invoke exceptionHandling twice does not override"() {
setup:
InvokeTwiceDoesNotOverrideConfig.AEP = Mock(AuthenticationEntryPoint)
when:
loadConfig(InvokeTwiceDoesNotOverrideConfig)
then:
findFilter(ExceptionTranslationFilter).authenticationEntryPoint == InvokeTwiceDoesNotOverrideConfig.AEP
}
@EnableWebSecurity
static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
static AuthenticationEntryPoint AEP
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(AEP)
.and()
.exceptionHandling()
}
}
@EnableWebSecurity
static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
static AuthenticationEntryPoint AEP
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(AEP)
.and()
.exceptionHandling()
}
}
}
@@ -56,266 +56,262 @@ import spock.lang.Unroll
* @author Rob Winch
*/
class FormLoginConfigurerTests extends BaseSpringSpec {
def "Form Login"() {
when: "load formLogin()"
context = new AnnotationConfigApplicationContext(FormLoginConfig)
def "Form Login"() {
when: "load formLogin()"
context = new AnnotationConfigApplicationContext(FormLoginConfig)
then: "FilterChains configured correctly"
def filterChains = filterChains()
filterChains.size() == 2
filterChains[0].requestMatcher.pattern == '/resources/**'
filterChains[0].filters.empty
filterChains[1].requestMatcher instanceof AnyRequestMatcher
filterChains[1].filters.collect { it.class.name.contains('$') ? it.class.superclass : it.class } ==
[WebAsyncManagerIntegrationFilter, SecurityContextPersistenceFilter, HeaderWriterFilter, CsrfFilter, LogoutFilter, UsernamePasswordAuthenticationFilter,
RequestCacheAwareFilter, SecurityContextHolderAwareRequestFilter,
AnonymousAuthenticationFilter, SessionManagementFilter, ExceptionTranslationFilter, FilterSecurityInterceptor ]
then: "FilterChains configured correctly"
def filterChains = filterChains()
filterChains.size() == 2
filterChains[0].requestMatcher.pattern == '/resources/**'
filterChains[0].filters.empty
filterChains[1].requestMatcher instanceof AnyRequestMatcher
filterChains[1].filters.collect { it.class.name.contains('$') ? it.class.superclass : it.class } ==
[WebAsyncManagerIntegrationFilter, SecurityContextPersistenceFilter, HeaderWriterFilter, CsrfFilter, LogoutFilter, UsernamePasswordAuthenticationFilter,
RequestCacheAwareFilter, SecurityContextHolderAwareRequestFilter,
AnonymousAuthenticationFilter, SessionManagementFilter, ExceptionTranslationFilter, FilterSecurityInterceptor ]
and: "UsernamePasswordAuthentictionFilter is configured correctly"
UsernamePasswordAuthenticationFilter authFilter = findFilter(UsernamePasswordAuthenticationFilter,1)
authFilter.usernameParameter == "username"
authFilter.passwordParameter == "password"
authFilter.failureHandler.defaultFailureUrl == "/login?error"
authFilter.successHandler.defaultTargetUrl == "/"
authFilter.requiresAuthentication(new MockHttpServletRequest(servletPath : "/login", method: "POST"), new MockHttpServletResponse())
!authFilter.requiresAuthentication(new MockHttpServletRequest(servletPath : "/login", method: "GET"), new MockHttpServletResponse())
and: "UsernamePasswordAuthentictionFilter is configured correctly"
UsernamePasswordAuthenticationFilter authFilter = findFilter(UsernamePasswordAuthenticationFilter,1)
authFilter.usernameParameter == "username"
authFilter.passwordParameter == "password"
authFilter.failureHandler.defaultFailureUrl == "/login?error"
authFilter.successHandler.defaultTargetUrl == "/"
authFilter.requiresAuthentication(new MockHttpServletRequest(servletPath : "/login", method: "POST"), new MockHttpServletResponse())
!authFilter.requiresAuthentication(new MockHttpServletRequest(servletPath : "/login", method: "GET"), new MockHttpServletResponse())
and: "SessionFixationProtectionStrategy is configured correctly"
SessionFixationProtectionStrategy sessionStrategy = ReflectionTestUtils.getField(authFilter,"sessionStrategy").delegateStrategies.find { SessionFixationProtectionStrategy }
sessionStrategy.migrateSessionAttributes
and: "Exception handling is configured correctly"
AuthenticationEntryPoint authEntryPoint = filterChains[1].filters.find { it instanceof ExceptionTranslationFilter}.authenticationEntryPoint
MockHttpServletResponse response = new MockHttpServletResponse()
authEntryPoint.commence(new MockHttpServletRequest(servletPath: "/private/"), response, new BadCredentialsException(""))
response.redirectedUrl == "http://localhost/login"
}
and: "Exception handling is configured correctly"
AuthenticationEntryPoint authEntryPoint = filterChains[1].filters.find { it instanceof ExceptionTranslationFilter}.authenticationEntryPoint
MockHttpServletResponse response = new MockHttpServletResponse()
authEntryPoint.commence(new MockHttpServletRequest(servletPath: "/private/"), response, new BadCredentialsException(""))
response.redirectedUrl == "http://localhost/login"
}
@EnableWebSecurity
static class FormLoginConfig extends BaseWebConfig {
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
@EnableWebSecurity
static class FormLoginConfig extends BaseWebConfig {
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.loginPage("/login")
}
}
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.loginPage("/login")
}
}
def "FormLogin.permitAll()"() {
when: "load formLogin() with permitAll"
context = new AnnotationConfigApplicationContext(FormLoginConfigPermitAll)
FilterChainProxy filterChain = context.getBean(FilterChainProxy)
MockHttpServletResponse response = new MockHttpServletResponse()
request = new MockHttpServletRequest(servletPath : servletPath, requestURI: servletPath, queryString: query, method: method)
setupCsrf()
def "FormLogin.permitAll()"() {
when: "load formLogin() with permitAll"
context = new AnnotationConfigApplicationContext(FormLoginConfigPermitAll)
FilterChainProxy filterChain = context.getBean(FilterChainProxy)
MockHttpServletResponse response = new MockHttpServletResponse()
request = new MockHttpServletRequest(servletPath : servletPath, requestURI: servletPath, queryString: query, method: method)
setupCsrf()
then: "the formLogin URLs are granted access"
filterChain.doFilter(request, response, new MockFilterChain())
response.redirectedUrl == redirectUrl
then: "the formLogin URLs are granted access"
filterChain.doFilter(request, response, new MockFilterChain())
response.redirectedUrl == redirectUrl
where:
servletPath | method | query | redirectUrl
"/login" | "GET" | null | null
"/login" | "POST" | null | "/login?error"
"/login" | "GET" | "error" | null
}
where:
servletPath | method | query | redirectUrl
"/login" | "GET" | null | null
"/login" | "POST" | null | "/login?error"
"/login" | "GET" | "error" | null
}
@EnableWebSecurity
static class FormLoginConfigPermitAll extends BaseWebConfig {
@EnableWebSecurity
static class FormLoginConfigPermitAll extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.permitAll()
}
}
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.permitAll()
}
}
@Unroll
def "FormLogin loginConventions changes defaults"() {
when: "load formLogin() with permitAll"
loadConfig(FormLoginDefaultsConfig)
MockHttpServletResponse response = new MockHttpServletResponse()
request = new MockHttpServletRequest(servletPath : servletPath, requestURI: servletPath, queryString: query, method: method)
setupCsrf()
@Unroll
def "FormLogin loginConventions changes defaults"() {
when: "load formLogin() with permitAll"
loadConfig(FormLoginDefaultsConfig)
MockHttpServletResponse response = new MockHttpServletResponse()
request = new MockHttpServletRequest(servletPath : servletPath, requestURI: servletPath, queryString: query, method: method)
setupCsrf()
then: "the other default login/logout URLs are updated and granted access"
springSecurityFilterChain.doFilter(request, response, new MockFilterChain())
response.redirectedUrl == redirectUrl
then: "the other default login/logout URLs are updated and granted access"
springSecurityFilterChain.doFilter(request, response, new MockFilterChain())
response.redirectedUrl == redirectUrl
where:
servletPath | method | query | redirectUrl
"/authenticate" | "GET" | null | null
"/authenticate" | "POST" | null | "/authenticate?error"
"/authenticate" | "GET" | "error" | null
"/logout" | "POST" | null | "/authenticate?logout"
"/authenticate" | "GET" | "logout"| null
}
where:
servletPath | method | query | redirectUrl
"/authenticate" | "GET" | null | null
"/authenticate" | "POST" | null | "/authenticate?error"
"/authenticate" | "GET" | "error" | null
"/logout" | "POST" | null | "/authenticate?logout"
"/authenticate" | "GET" | "logout"| null
}
@EnableWebSecurity
static class FormLoginDefaultsConfig extends BaseWebConfig {
@EnableWebSecurity
static class FormLoginDefaultsConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.loginPage("/authenticate")
.permitAll()
.and()
.logout()
.permitAll()
}
}
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.loginPage("/authenticate")
.permitAll()
.and()
.logout()
.permitAll()
}
}
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 == "/"
}
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 == "/"
}
@EnableWebSecurity
static class FormLoginLoginProcessingUrlConfig extends BaseWebConfig {
@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")
}
}
@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)
loadConfig(FormLoginUsesPortMapperConfig)
then: "the formLogin URLs are granted access"
findFilter(ExceptionTranslationFilter).authenticationEntryPoint.portMapper == FormLoginUsesPortMapperConfig.PORT_MAPPER
}
def "FormLogin uses PortMapper"() {
when: "load formLogin() with permitAll"
FormLoginUsesPortMapperConfig.PORT_MAPPER = Mock(PortMapper)
loadConfig(FormLoginUsesPortMapperConfig)
then: "the formLogin URLs are granted access"
findFilter(ExceptionTranslationFilter).authenticationEntryPoint.portMapper == FormLoginUsesPortMapperConfig.PORT_MAPPER
}
@EnableWebSecurity
static class FormLoginUsesPortMapperConfig extends BaseWebConfig {
static PortMapper PORT_MAPPER
@EnableWebSecurity
static class FormLoginUsesPortMapperConfig extends BaseWebConfig {
static PortMapper PORT_MAPPER
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.permitAll()
.and()
.portMapper()
.portMapper(PORT_MAPPER)
}
}
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.permitAll()
.and()
.portMapper()
.portMapper(PORT_MAPPER)
}
}
def "FormLogin permitAll ignores failureUrl when failureHandler set"() {
setup:
PermitAllIgnoresFailureHandlerConfig.FAILURE_HANDLER = Mock(AuthenticationFailureHandler)
loadConfig(PermitAllIgnoresFailureHandlerConfig)
FilterChainProxy springSecurityFilterChain = context.getBean(FilterChainProxy)
when: "access default failureUrl and configured explicit FailureHandler"
MockHttpServletRequest request = new MockHttpServletRequest(servletPath:"/login",requestURI:"/login",queryString:"error",method:"GET")
MockHttpServletResponse response = new MockHttpServletResponse()
springSecurityFilterChain.doFilter(request,response,new MockFilterChain())
then: "access is not granted to the failure handler (sent to login page)"
response.status == 302
}
def "FormLogin permitAll ignores failureUrl when failureHandler set"() {
setup:
PermitAllIgnoresFailureHandlerConfig.FAILURE_HANDLER = Mock(AuthenticationFailureHandler)
loadConfig(PermitAllIgnoresFailureHandlerConfig)
FilterChainProxy springSecurityFilterChain = context.getBean(FilterChainProxy)
when: "access default failureUrl and configured explicit FailureHandler"
MockHttpServletRequest request = new MockHttpServletRequest(servletPath:"/login",requestURI:"/login",queryString:"error",method:"GET")
MockHttpServletResponse response = new MockHttpServletResponse()
springSecurityFilterChain.doFilter(request,response,new MockFilterChain())
then: "access is not granted to the failure handler (sent to login page)"
response.status == 302
}
@EnableWebSecurity
static class PermitAllIgnoresFailureHandlerConfig extends BaseWebConfig {
static AuthenticationFailureHandler FAILURE_HANDLER
@EnableWebSecurity
static class PermitAllIgnoresFailureHandlerConfig extends BaseWebConfig {
static AuthenticationFailureHandler FAILURE_HANDLER
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.failureHandler(FAILURE_HANDLER)
.permitAll()
}
}
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.failureHandler(FAILURE_HANDLER)
.permitAll()
}
}
def "duplicate formLogin does not override"() {
setup:
DuplicateInvocationsDoesNotOverrideConfig.FAILURE_HANDLER = Mock(AuthenticationFailureHandler)
when:
loadConfig(DuplicateInvocationsDoesNotOverrideConfig)
then:
findFilter(UsernamePasswordAuthenticationFilter).usernameParameter == "custom-username"
}
def "duplicate formLogin does not override"() {
setup:
DuplicateInvocationsDoesNotOverrideConfig.FAILURE_HANDLER = Mock(AuthenticationFailureHandler)
when:
loadConfig(DuplicateInvocationsDoesNotOverrideConfig)
then:
findFilter(UsernamePasswordAuthenticationFilter).usernameParameter == "custom-username"
}
@EnableWebSecurity
static class DuplicateInvocationsDoesNotOverrideConfig extends BaseWebConfig {
static AuthenticationFailureHandler FAILURE_HANDLER
@EnableWebSecurity
static class DuplicateInvocationsDoesNotOverrideConfig extends BaseWebConfig {
static AuthenticationFailureHandler FAILURE_HANDLER
@Override
protected void configure(HttpSecurity http) {
http
.formLogin()
.usernameParameter("custom-username")
.and()
.formLogin()
}
}
@Override
protected void configure(HttpSecurity http) {
http
.formLogin()
.usernameParameter("custom-username")
.and()
.formLogin()
}
}
def "formLogin ObjectPostProcessor"() {
setup: "initialize the AUTH_FILTER as a mock"
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.exceptionHandling()
.and()
.formLogin()
.and()
.build()
def "formLogin ObjectPostProcessor"() {
setup: "initialize the AUTH_FILTER as a mock"
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.exceptionHandling()
.and()
.formLogin()
.and()
.build()
then: "UsernamePasswordAuthenticationFilter is registered with ObjectPostProcessor"
1 * opp.postProcess(_ as UsernamePasswordAuthenticationFilter) >> {UsernamePasswordAuthenticationFilter o -> o}
and: "LoginUrlAuthenticationEntryPoint is registered with ObjectPostProcessor"
1 * opp.postProcess(_ as LoginUrlAuthenticationEntryPoint) >> {LoginUrlAuthenticationEntryPoint o -> o}
and: "ExceptionTranslationFilter is registered with ObjectPostProcessor"
1 * opp.postProcess(_ as ExceptionTranslationFilter) >> {ExceptionTranslationFilter o -> o}
}
then: "UsernamePasswordAuthenticationFilter is registered with ObjectPostProcessor"
1 * opp.postProcess(_ as UsernamePasswordAuthenticationFilter) >> {UsernamePasswordAuthenticationFilter o -> o}
and: "LoginUrlAuthenticationEntryPoint is registered with ObjectPostProcessor"
1 * opp.postProcess(_ as LoginUrlAuthenticationEntryPoint) >> {LoginUrlAuthenticationEntryPoint o -> o}
and: "ExceptionTranslationFilter is registered with ObjectPostProcessor"
1 * opp.postProcess(_ as ExceptionTranslationFilter) >> {ExceptionTranslationFilter o -> o}
}
}
@@ -39,163 +39,163 @@ import spock.lang.Unroll;
*/
class HeadersConfigurerTests extends BaseSpringSpec {
def "headers"() {
setup:
loadConfig(HeadersConfig)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-Content-Type-Options':'nosniff',
'X-Frame-Options':'DENY',
'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
'Expires' : '0',
'Pragma':'no-cache',
'X-XSS-Protection' : '1; mode=block']
}
def "headers"() {
setup:
loadConfig(HeadersConfig)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-Content-Type-Options':'nosniff',
'X-Frame-Options':'DENY',
'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
'Expires' : '0',
'Pragma':'no-cache',
'X-XSS-Protection' : '1; mode=block']
}
@EnableWebSecurity
static class HeadersConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class HeadersConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers()
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers()
}
}
def "headers.contentType"() {
setup:
loadConfig(ContentTypeOptionsConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-Content-Type-Options':'nosniff']
}
def "headers.contentType"() {
setup:
loadConfig(ContentTypeOptionsConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-Content-Type-Options':'nosniff']
}
@EnableWebSecurity
static class ContentTypeOptionsConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class ContentTypeOptionsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.contentTypeOptions()
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.contentTypeOptions()
}
}
def "headers.frameOptions"() {
setup:
loadConfig(FrameOptionsConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-Frame-Options':'DENY']
}
def "headers.frameOptions"() {
setup:
loadConfig(FrameOptionsConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-Frame-Options':'DENY']
}
@EnableWebSecurity
static class FrameOptionsConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class FrameOptionsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.frameOptions()
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.frameOptions()
}
}
def "headers.hsts"() {
setup:
loadConfig(HstsConfig)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains']
}
def "headers.hsts"() {
setup:
loadConfig(HstsConfig)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains']
}
@EnableWebSecurity
static class HstsConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class HstsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.httpStrictTransportSecurity()
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.httpStrictTransportSecurity()
}
}
def "headers.cacheControl"() {
setup:
loadConfig(CacheControlConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
'Expires' : '0',
'Pragma':'no-cache']
}
def "headers.cacheControl"() {
setup:
loadConfig(CacheControlConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
'Expires' : '0',
'Pragma':'no-cache']
}
@EnableWebSecurity
static class CacheControlConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class CacheControlConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.cacheControl()
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.cacheControl()
}
}
def "headers.xssProtection"() {
setup:
loadConfig(XssProtectionConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-XSS-Protection' : '1; mode=block']
}
def "headers.xssProtection"() {
setup:
loadConfig(XssProtectionConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-XSS-Protection' : '1; mode=block']
}
@EnableWebSecurity
static class XssProtectionConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class XssProtectionConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.xssProtection()
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.xssProtection()
}
}
def "headers custom x-frame-options"() {
setup:
loadConfig(HeadersCustomSameOriginConfig)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-Content-Type-Options':'nosniff',
'X-Frame-Options':'SAMEORIGIN',
'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
'Expires' : '0',
'Pragma':'no-cache',
'X-XSS-Protection' : '1; mode=block']
}
def "headers custom x-frame-options"() {
setup:
loadConfig(HeadersCustomSameOriginConfig)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-Content-Type-Options':'nosniff',
'X-Frame-Options':'SAMEORIGIN',
'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
'Expires' : '0',
'Pragma':'no-cache',
'X-XSS-Protection' : '1; mode=block']
}
@EnableWebSecurity
static class HeadersCustomSameOriginConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class HeadersCustomSameOriginConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.frameOptions().sameOrigin()
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.frameOptions().sameOrigin()
}
}
}
@@ -24,6 +24,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.web.AuthenticationEntryPoint
import org.springframework.security.web.access.ExceptionTranslationFilter
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter
@@ -33,101 +34,126 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationFi
*/
class HttpBasicConfigurerTests extends BaseSpringSpec {
def "httBasic ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.httpBasic()
.and()
.build()
def "httBasic ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.httpBasic()
.and()
.build()
then: "ExceptionTranslationFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as BasicAuthenticationFilter) >> {BasicAuthenticationFilter o -> o}
}
then: "ExceptionTranslationFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as BasicAuthenticationFilter) >> {BasicAuthenticationFilter o -> o}
}
def "SEC-2198: http.httpBasic() defaults AuthenticationEntryPoint"() {
setup:
loadConfig(DefaultsEntryPointConfig)
when:
springSecurityFilterChain.doFilter(request, response, chain)
then:
response.status == 401
response.getHeader("WWW-Authenticate") == 'Basic realm="Realm"'
}
def "SEC-2198: http.httpBasic() defaults AuthenticationEntryPoint"() {
setup:
loadConfig(DefaultsEntryPointConfig)
when:
springSecurityFilterChain.doFilter(request, response, chain)
then:
response.status == 401
response.getHeader("WWW-Authenticate") == 'Basic realm="Realm"'
}
@EnableWebSecurity
static class DefaultsEntryPointConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
}
@EnableWebSecurity
static class DefaultsEntryPointConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
}
def "http.httpBasic().authenticationEntryPoint used for AuthenticationEntryPoint"() {
setup:
CustomAuthenticationEntryPointConfig.ENTRY_POINT = Mock(AuthenticationEntryPoint)
when:
loadConfig(CustomAuthenticationEntryPointConfig)
then:
findFilter(ExceptionTranslationFilter).authenticationEntryPoint == CustomAuthenticationEntryPointConfig.ENTRY_POINT
}
def "http.httpBasic().authenticationEntryPoint used for AuthenticationEntryPoint"() {
setup:
CustomAuthenticationEntryPointConfig.ENTRY_POINT = Mock(AuthenticationEntryPoint)
when:
loadConfig(CustomAuthenticationEntryPointConfig)
then:
findFilter(ExceptionTranslationFilter).authenticationEntryPoint == CustomAuthenticationEntryPointConfig.ENTRY_POINT
}
@EnableWebSecurity
static class CustomAuthenticationEntryPointConfig extends WebSecurityConfigurerAdapter {
static AuthenticationEntryPoint ENTRY_POINT
@EnableWebSecurity
static class CustomAuthenticationEntryPointConfig extends WebSecurityConfigurerAdapter {
static AuthenticationEntryPoint ENTRY_POINT
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.authenticationEntryPoint(ENTRY_POINT)
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.authenticationEntryPoint(ENTRY_POINT)
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
}
def "duplicate httpBasic invocations does not override"() {
setup:
DuplicateDoesNotOverrideConfig.ENTRY_POINT = Mock(AuthenticationEntryPoint)
when:
loadConfig(DuplicateDoesNotOverrideConfig)
then:
findFilter(ExceptionTranslationFilter).authenticationEntryPoint == DuplicateDoesNotOverrideConfig.ENTRY_POINT
}
def "duplicate httpBasic invocations does not override"() {
setup:
DuplicateDoesNotOverrideConfig.ENTRY_POINT = Mock(AuthenticationEntryPoint)
when:
loadConfig(DuplicateDoesNotOverrideConfig)
then:
findFilter(ExceptionTranslationFilter).authenticationEntryPoint == DuplicateDoesNotOverrideConfig.ENTRY_POINT
}
@EnableWebSecurity
static class DuplicateDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
static AuthenticationEntryPoint ENTRY_POINT
@EnableWebSecurity
static class DuplicateDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
static AuthenticationEntryPoint ENTRY_POINT
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.authenticationEntryPoint(ENTRY_POINT)
.and()
.httpBasic()
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.authenticationEntryPoint(ENTRY_POINT)
.and()
.httpBasic()
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
}
def "SEC-3019: Basic Authentication uses RememberMe Config"() {
when:
loadConfig(BasicUsesRememberMeConfig)
then:
findFilter(BasicAuthenticationFilter).rememberMeServices == findFilter(RememberMeAuthenticationFilter).rememberMeServices
}
@EnableWebSecurity
@Configuration
static class BasicUsesRememberMeConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().and()
.rememberMe()
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
}
}
@@ -31,38 +31,38 @@ import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthe
*/
class JeeConfigurerTests extends BaseSpringSpec {
def "jee ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.jee()
.and()
.build()
def "jee ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.jee()
.and()
.build()
then: "J2eePreAuthenticatedProcessingFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as J2eePreAuthenticatedProcessingFilter) >> {J2eePreAuthenticatedProcessingFilter o -> o}
and: "J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource is registered with LifecycleManager"
1 * opp.postProcess(_ as J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource) >> {J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource o -> o}
}
then: "J2eePreAuthenticatedProcessingFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as J2eePreAuthenticatedProcessingFilter) >> {J2eePreAuthenticatedProcessingFilter o -> o}
and: "J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource is registered with LifecycleManager"
1 * opp.postProcess(_ as J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource) >> {J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource o -> o}
}
def "invoke jee twice does not override"() {
when:
loadConfig(InvokeTwiceDoesNotOverride)
then:
findFilter(J2eePreAuthenticatedProcessingFilter).authenticationDetailsSource.j2eeMappableRoles == ["ROLE_USER"] as Set
}
def "invoke jee twice does not override"() {
when:
loadConfig(InvokeTwiceDoesNotOverride)
then:
findFilter(J2eePreAuthenticatedProcessingFilter).authenticationDetailsSource.j2eeMappableRoles == ["ROLE_USER"] as Set
}
@EnableWebSecurity
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.jee()
.mappableRoles("USER")
.and()
.jee()
}
}
@EnableWebSecurity
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.jee()
.mappableRoles("USER")
.and()
.jee()
}
}
}
@@ -30,85 +30,85 @@ import org.springframework.security.web.authentication.logout.LogoutFilter
*/
class LogoutConfigurerTests extends BaseSpringSpec {
def "logout ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.logout()
.and()
.build()
def "logout ObjectPostProcessor"() {
setup:
AnyObjectPostProcessor opp = Mock()
HttpSecurity http = new HttpSecurity(opp, authenticationBldr, [:])
when:
http
.logout()
.and()
.build()
then: "LogoutFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as LogoutFilter) >> {LogoutFilter o -> o}
}
then: "LogoutFilter is registered with LifecycleManager"
1 * opp.postProcess(_ as LogoutFilter) >> {LogoutFilter o -> o}
}
def "invoke logout twice does not override"() {
when:
loadConfig(InvokeTwiceDoesNotOverride)
request.method = "POST"
request.servletPath = "/custom/logout"
findFilter(LogoutFilter).doFilter(request,response,chain)
then:
response.redirectedUrl == "/login?logout"
}
def "invoke logout twice does not override"() {
when:
loadConfig(InvokeTwiceDoesNotOverride)
request.method = "POST"
request.servletPath = "/custom/logout"
findFilter(LogoutFilter).doFilter(request,response,chain)
then:
response.redirectedUrl == "/login?logout"
}
@EnableWebSecurity
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.logout()
.logoutUrl("/custom/logout")
.and()
.logout()
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.logout()
.logoutUrl("/custom/logout")
.and()
.logout()
}
}
def "SEC-2311: Logout allows other methods if CSRF is disabled"() {
when:
loadConfig(CsrfDisabledConfig)
request.method = "GET"
request.servletPath = "/logout"
findFilter(LogoutFilter).doFilter(request,response,chain)
then:
response.redirectedUrl == "/login?logout"
}
def "SEC-2311: Logout allows other methods if CSRF is disabled"() {
when:
loadConfig(CsrfDisabledConfig)
request.method = "GET"
request.servletPath = "/logout"
findFilter(LogoutFilter).doFilter(request,response,chain)
then:
response.redirectedUrl == "/login?logout"
}
@EnableWebSecurity
static class CsrfDisabledConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class CsrfDisabledConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.logout()
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.logout()
}
}
def "SEC-2311: Logout allows other methods if CSRF is disabled with custom logout URL"() {
when:
loadConfig(CsrfDisabledCustomLogoutUrlConfig)
request.method = "GET"
request.servletPath = "/custom/logout"
findFilter(LogoutFilter).doFilter(request,response,chain)
then:
response.redirectedUrl == "/login?logout"
}
def "SEC-2311: Logout allows other methods if CSRF is disabled with custom logout URL"() {
when:
loadConfig(CsrfDisabledCustomLogoutUrlConfig)
request.method = "GET"
request.servletPath = "/custom/logout"
findFilter(LogoutFilter).doFilter(request,response,chain)
then:
response.redirectedUrl == "/login?logout"
}
@EnableWebSecurity
static class CsrfDisabledCustomLogoutUrlConfig extends WebSecurityConfigurerAdapter {
@EnableWebSecurity
static class CsrfDisabledCustomLogoutUrlConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.logout()
.logoutUrl("/custom/logout")
.and()
.csrf().disable()
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.logout()
.logoutUrl("/custom/logout")
.and()
.csrf().disable()
}
}
}
@@ -64,14 +64,14 @@ import spock.lang.Ignore;
*
*/
public class NamespaceDebugTests extends BaseSpringSpec {
def "debug=true"() {
when: "Load configuraiton with debug enabled"
loadConfig(DebugWebSecurity)
then: "The DebugFilter is present"
context.getBean("springSecurityFilterChain").class == DebugFilter
}
def "debug=true"() {
when: "Load configuraiton with debug enabled"
loadConfig(DebugWebSecurity)
then: "The DebugFilter is present"
context.getBean("springSecurityFilterChain").class == DebugFilter
}
@EnableWebSecurity(debug=true)
static class DebugWebSecurity extends WebSecurityConfigurerAdapter {
}
@EnableWebSecurity(debug=true)
static class DebugWebSecurity extends WebSecurityConfigurerAdapter {
}
}
@@ -37,44 +37,44 @@ import org.springframework.security.web.access.ExceptionTranslationFilter;
*
*/
public class NamespaceHttpAccessDeniedHandlerTests extends BaseSpringSpec {
def "http/access-denied-handler@error-page"() {
when:
loadConfig(AccessDeniedPageConfig)
then:
findFilter(ExceptionTranslationFilter).accessDeniedHandler.errorPage == "/AccessDeniedPageConfig"
}
def "http/access-denied-handler@error-page"() {
when:
loadConfig(AccessDeniedPageConfig)
then:
findFilter(ExceptionTranslationFilter).accessDeniedHandler.errorPage == "/AccessDeniedPageConfig"
}
@Configuration
static class AccessDeniedPageConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http.
exceptionHandling()
.accessDeniedPage("/AccessDeniedPageConfig")
}
}
@Configuration
static class AccessDeniedPageConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http.
exceptionHandling()
.accessDeniedPage("/AccessDeniedPageConfig")
}
}
def "http/access-denied-handler@ref"() {
when:
loadConfig(AccessDeniedHandlerRefConfig)
then:
findFilter(ExceptionTranslationFilter).accessDeniedHandler.class == AccessDeniedHandlerRefConfig.CustomAccessDeniedHandler
}
def "http/access-denied-handler@ref"() {
when:
loadConfig(AccessDeniedHandlerRefConfig)
then:
findFilter(ExceptionTranslationFilter).accessDeniedHandler.class == AccessDeniedHandlerRefConfig.CustomAccessDeniedHandler
}
@Configuration
static class AccessDeniedHandlerRefConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
CustomAccessDeniedHandler accessDeniedHandler = new CustomAccessDeniedHandler()
http.
exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
}
@Configuration
static class AccessDeniedHandlerRefConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
CustomAccessDeniedHandler accessDeniedHandler = new CustomAccessDeniedHandler()
http.
exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
}
static class CustomAccessDeniedHandler implements AccessDeniedHandler {
public void handle(HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException accessDeniedException)
throws IOException, ServletException {
}
}
}
static class CustomAccessDeniedHandler implements AccessDeniedHandler {
public void handle(HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException accessDeniedException)
throws IOException, ServletException {
}
}
}
}
@@ -32,98 +32,98 @@ import org.springframework.security.web.authentication.AnonymousAuthenticationFi
*
*/
public class NamespaceHttpAnonymousTests extends BaseSpringSpec {
def "http/anonymous@enabled = true (default)"() {
when:
loadConfig(AnonymousConfig)
then:
def filter = findFilter(AnonymousAuthenticationFilter)
filter != null
def authManager = findFilter(FilterSecurityInterceptor).authenticationManager
authManager.authenticate(new AnonymousAuthenticationToken(filter.key, filter.principal, filter.authorities)).authenticated
}
def "http/anonymous@enabled = true (default)"() {
when:
loadConfig(AnonymousConfig)
then:
def filter = findFilter(AnonymousAuthenticationFilter)
filter != null
def authManager = findFilter(FilterSecurityInterceptor).authenticationManager
authManager.authenticate(new AnonymousAuthenticationToken(filter.key, filter.principal, filter.authorities)).authenticated
}
@Configuration
static class AnonymousConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER");
}
}
@Configuration
static class AnonymousConfig extends BaseWebConfig {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER");
}
}
def "http/anonymous@enabled = false"() {
when:
loadConfig(AnonymousDisabledConfig)
then:
findFilter(AnonymousAuthenticationFilter) == null
}
def "http/anonymous@enabled = false"() {
when:
loadConfig(AnonymousDisabledConfig)
then:
findFilter(AnonymousAuthenticationFilter) == null
}
@Configuration
static class AnonymousDisabledConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http.anonymous().disable()
}
}
@Configuration
static class AnonymousDisabledConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http.anonymous().disable()
}
}
def "http/anonymous@granted-authority"() {
when:
loadConfig(AnonymousGrantedAuthorityConfig)
then:
findFilter(AnonymousAuthenticationFilter).authorities == AuthorityUtils.createAuthorityList("ROLE_ANON")
}
def "http/anonymous@granted-authority"() {
when:
loadConfig(AnonymousGrantedAuthorityConfig)
then:
findFilter(AnonymousAuthenticationFilter).authorities == AuthorityUtils.createAuthorityList("ROLE_ANON")
}
@Configuration
static class AnonymousGrantedAuthorityConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http
.anonymous()
.authorities("ROLE_ANON")
}
}
@Configuration
static class AnonymousGrantedAuthorityConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http
.anonymous()
.authorities("ROLE_ANON")
}
}
def "http/anonymous@key"() {
when:
loadConfig(AnonymousKeyConfig)
then:
def filter = findFilter(AnonymousAuthenticationFilter)
filter != null
filter.key == "AnonymousKeyConfig"
def authManager = findFilter(FilterSecurityInterceptor).authenticationManager
authManager.authenticate(new AnonymousAuthenticationToken(filter.key, filter.principal, filter.authorities)).authenticated
}
def "http/anonymous@key"() {
when:
loadConfig(AnonymousKeyConfig)
then:
def filter = findFilter(AnonymousAuthenticationFilter)
filter != null
filter.key == "AnonymousKeyConfig"
def authManager = findFilter(FilterSecurityInterceptor).authenticationManager
authManager.authenticate(new AnonymousAuthenticationToken(filter.key, filter.principal, filter.authorities)).authenticated
}
@Configuration
static class AnonymousKeyConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.anonymous().key("AnonymousKeyConfig")
}
}
@Configuration
static class AnonymousKeyConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.anonymous().key("AnonymousKeyConfig")
}
}
def "http/anonymous@username"() {
when:
loadConfig(AnonymousUsernameConfig)
then:
def filter = findFilter(AnonymousAuthenticationFilter)
filter != null
filter.principal == "AnonymousUsernameConfig"
def authManager = findFilter(FilterSecurityInterceptor).authenticationManager
authManager.authenticate(new AnonymousAuthenticationToken(filter.key, filter.principal, filter.authorities)).principal == "AnonymousUsernameConfig"
}
def "http/anonymous@username"() {
when:
loadConfig(AnonymousUsernameConfig)
then:
def filter = findFilter(AnonymousAuthenticationFilter)
filter != null
filter.principal == "AnonymousUsernameConfig"
def authManager = findFilter(FilterSecurityInterceptor).authenticationManager
authManager.authenticate(new AnonymousAuthenticationToken(filter.key, filter.principal, filter.authorities)).principal == "AnonymousUsernameConfig"
}
@Configuration
static class AnonymousUsernameConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.anonymous().principal("AnonymousUsernameConfig")
}
}
@Configuration
static class AnonymousUsernameConfig extends BaseWebConfig {
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.anonymous().principal("AnonymousUsernameConfig")
}
}
}

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