Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b0651b97fd | |||
| 7cce996ebe | |||
| 2aa09d11e2 | |||
| 8ab8376b9c | |||
| 5699a36627 | |||
| 0f0e973c1e | |||
| 9c76f54958 | |||
| 14e4a812a1 | |||
| be0759302f | |||
| ff25799f36 | |||
| 54b28873ee | |||
| 692ac213f9 | |||
| e4e7363196 | |||
| 75e248344b | |||
| 3ae6cdf05f | |||
| a9c8b350b8 | |||
| da9eca223b | |||
| c7e18db138 | |||
| 9c181c58cb | |||
| 7b61962915 | |||
| a302106082 | |||
| fe737cc67d | |||
| d4508858f3 | |||
| 76432029c5 | |||
| 0d0afb992e | |||
| b35d7e229d | |||
| 3c81e122bd | |||
| 929a5de163 | |||
| ecac6cdfc1 | |||
| 2ad73af130 | |||
| 0aaefa2bb9 | |||
| 21c70155a3 | |||
| 7ca913dadf | |||
| 7eb87b19b3 | |||
| 1683d30c2e | |||
| adfb3ddf77 | |||
| 1ba1fb61a7 | |||
| e3a1fa2f86 | |||
| ac657a32a6 | |||
| 6c98a49010 | |||
| f2db4b6cdb | |||
| 9156d3bce3 | |||
| 327c52d650 | |||
| d98d23e5ef | |||
| f892746c00 | |||
| b95ccc211b | |||
| 820b2046fb | |||
| bde423524b | |||
| 78d8b9fa71 | |||
| 35bbccad3c | |||
| 04cc0d486b |
@@ -0,0 +1,22 @@
|
||||
name: PR Build
|
||||
|
||||
on: pull_request
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: '8'
|
||||
- name: Cache Gradle packages
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew test --refresh-dependencies --no-daemon
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
language: java
|
||||
|
||||
jdk:
|
||||
- openjdk8
|
||||
|
||||
os:
|
||||
- linux
|
||||
|
||||
before_cache:
|
||||
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.gradle/caches/
|
||||
- $HOME/.gradle/wrapper/
|
||||
|
||||
script: ./gradlew build
|
||||
@@ -1,7 +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]
|
||||
|
||||
image:https://travis-ci.org/spring-projects/spring-security.svg?branch=master["Build Status", link="https://travis-ci.org/spring-security/spring-security"]
|
||||
|
||||
= Spring Security
|
||||
|
||||
Spring Security provides security services for the https://docs.spring.io[Spring IO Platform]. Spring Security 3.1 requires Spring 3.0.3 as
|
||||
|
||||
+7
-4
@@ -6,12 +6,12 @@ buildscript {
|
||||
dependencies {
|
||||
classpath "com.github.ben-manes:gradle-versions-plugin:0.17.0"
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.7")
|
||||
classpath("io.spring.gradle:spring-io-plugin:0.0.6.RELEASE")
|
||||
classpath("io.spring.gradle:spring-io-plugin:0.0.8.RELEASE")
|
||||
classpath("com.bmuschko:gradle-tomcat-plugin:2.2.4")
|
||||
classpath('me.champeau.gradle:gradle-javadoc-hotfix-plugin:0.1')
|
||||
classpath('org.asciidoctor:asciidoctor-gradle-plugin:1.5.1')
|
||||
classpath('org.asciidoctor:asciidoctor-gradle-plugin:1.5.7')
|
||||
classpath("io.spring.gradle:docbook-reference-plugin:0.3.1")
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.19.RELEASE")
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.22.RELEASE")
|
||||
classpath "org.jfrog.buildinfo:build-info-extractor-gradle:4.12.0"
|
||||
classpath 'org.hidetake:gradle-ssh-plugin:2.10.1'
|
||||
classpath 'io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.10.0'
|
||||
@@ -34,7 +34,7 @@ allprojects {
|
||||
|
||||
ext.releaseBuild = version.endsWith('RELEASE')
|
||||
ext.snapshotBuild = version.endsWith('SNAPSHOT')
|
||||
ext.springVersion = '4.3.26.RELEASE'
|
||||
ext.springVersion = '4.3.28.RELEASE'
|
||||
ext.springLdapVersion = '2.3.2.RELEASE'
|
||||
|
||||
group = 'org.springframework.security'
|
||||
@@ -122,6 +122,9 @@ configure(coreModuleProjects) {
|
||||
}
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom("org.springframework:spring-framework-bom:${springVersion}")
|
||||
}
|
||||
springIoTestRuntime {
|
||||
imports {
|
||||
mavenBom("io.spring.platform:platform-bom:${springIoVersion}") {
|
||||
|
||||
@@ -15,5 +15,6 @@ public class MavenBomPlugin implements Plugin<Project> {
|
||||
project.plugins.apply(MavenPlugin)
|
||||
project.task(MAVEN_BOM_TASK_NAME, type: MavenBomTask, group: 'Generate', description: 'Configures the pom as a Maven Build of Materials (BOM)')
|
||||
project.install.dependsOn project.mavenBom
|
||||
project.uploadArchives.dependsOn project.mavenBom
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ public class MavenBomTask extends DefaultTask {
|
||||
|
||||
@TaskAction
|
||||
public void configureBom() {
|
||||
project.configurations.archives.artifacts.clear()
|
||||
// project.configurations.archives.artifacts.clear()
|
||||
|
||||
bomFile.parentFile.mkdirs()
|
||||
bomFile.write("Maven Build of Materials (BOM). See https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Importing_Dependencies")
|
||||
@@ -30,20 +30,30 @@ public class MavenBomTask extends DefaultTask {
|
||||
}
|
||||
project.install {
|
||||
repositories.mavenInstaller {
|
||||
pom.whenConfigured {
|
||||
packaging = "pom"
|
||||
withXml {
|
||||
asNode().children().last() + {
|
||||
delegate.dependencyManagement {
|
||||
delegate.dependencies {
|
||||
projects.sort { dep -> "$dep.group:$dep.name" }.each { p ->
|
||||
customizePom(pom)
|
||||
}
|
||||
}
|
||||
|
||||
delegate.dependency {
|
||||
delegate.groupId(p.group)
|
||||
delegate.artifactId(p.name)
|
||||
delegate.version(p.version)
|
||||
}
|
||||
}
|
||||
project.uploadArchives {
|
||||
repositories.mavenDeployer {
|
||||
customizePom(pom)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void customizePom(pom) {
|
||||
pom.whenConfigured {
|
||||
packaging = "pom"
|
||||
withXml {
|
||||
asNode().children().last() + {
|
||||
delegate.dependencyManagement {
|
||||
delegate.dependencies {
|
||||
projects.sort { dep -> "$dep.group:$dep.name" }.each { p ->
|
||||
|
||||
delegate.dependency {
|
||||
delegate.groupId(p.group)
|
||||
delegate.artifactId(p.name)
|
||||
delegate.version(p.version)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,4 +62,4 @@ public class MavenBomTask extends DefaultTask {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ public class ServiceAuthenticationDetailsSource implements
|
||||
// ===================================================================================================
|
||||
|
||||
/**
|
||||
* Creates an implementation that uses the specified ServiceProperites and the default
|
||||
* Creates an implementation that uses the specified ServiceProperties and the default
|
||||
* CAS artifactParameterName.
|
||||
*
|
||||
* @param serviceProperties The ServiceProperties to use to construct the serviceUrl.
|
||||
|
||||
+4
@@ -16,8 +16,10 @@
|
||||
package org.springframework.security.config.annotation.configuration;
|
||||
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
@@ -34,9 +36,11 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
||||
* @since 3.2
|
||||
*/
|
||||
@Configuration
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public class ObjectPostProcessorConfiguration {
|
||||
|
||||
@Bean
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public ObjectPostProcessor<Object> objectPostProcessor(
|
||||
AutowireCapableBeanFactory beanFactory) {
|
||||
return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
|
||||
|
||||
+3
@@ -28,8 +28,10 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.AdviceMode;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
@@ -80,6 +82,7 @@ import org.springframework.util.Assert;
|
||||
* @see EnableGlobalMethodSecurity
|
||||
*/
|
||||
@Configuration
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public class GlobalMethodSecurityConfiguration
|
||||
implements ImportAware, SmartInitializingSingleton {
|
||||
private static final Log logger = LogFactory
|
||||
|
||||
+4
@@ -15,14 +15,18 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.method.configuration;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource;
|
||||
|
||||
@Configuration
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
class Jsr250MetadataSourceConfiguration {
|
||||
|
||||
@Bean
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public Jsr250MethodSecurityMetadataSource jsr250MethodSecurityMetadataSource() {
|
||||
return new Jsr250MethodSecurityMetadataSource();
|
||||
}
|
||||
|
||||
+11
@@ -325,6 +325,13 @@ public abstract class WebSecurityConfigurerAdapter implements
|
||||
/**
|
||||
* Override this method to configure {@link WebSecurity}. For example, if you wish to
|
||||
* ignore certain requests.
|
||||
*
|
||||
* Endpoints specified in this method will be ignored by Spring Security, meaning it
|
||||
* will not protect them from CSRF, XSS, Clickjacking, and so on.
|
||||
*
|
||||
* Instead, if you want to protect endpoints against common vulnerabilities, then see
|
||||
* {@link #configure(HttpSecurity)} and the {@link HttpSecurity#authorizeRequests}
|
||||
* configuration method.
|
||||
*/
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
}
|
||||
@@ -338,6 +345,10 @@ public abstract class WebSecurityConfigurerAdapter implements
|
||||
* http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic();
|
||||
* </pre>
|
||||
*
|
||||
* Any endpoint that requires defense against common vulnerabilities can be specified here, including public ones.
|
||||
* See {@link HttpSecurity#authorizeRequests} and the `permitAll()` authorization rule
|
||||
* for more details on public endpoints.
|
||||
*
|
||||
* @param http the {@link HttpSecurity} to modify
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
|
||||
+1
-1
@@ -162,7 +162,7 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
|
||||
|
||||
/**
|
||||
* Specifies the {@link AuthenticationSuccessHandler} to be used. The default is
|
||||
* {@link SavedRequestAwareAuthenticationSuccessHandler} with no additional properites
|
||||
* {@link SavedRequestAwareAuthenticationSuccessHandler} with no additional properties
|
||||
* set.
|
||||
*
|
||||
* @param successHandler the {@link AuthenticationSuccessHandler}.
|
||||
|
||||
+1
-1
@@ -160,7 +160,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
*
|
||||
* <p>
|
||||
* Allows customizing the {@link XXssProtectionHeaderWriter} which adds the <a href=
|
||||
* "https://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx"
|
||||
* "https://web.archive.org/web/20160201174302/https://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx"
|
||||
* >X-XSS-Protection header</a>
|
||||
* </p>
|
||||
*
|
||||
|
||||
+1
-1
@@ -129,7 +129,7 @@ import org.springframework.util.Assert;
|
||||
* </property>
|
||||
* </pre>
|
||||
*
|
||||
* A configuration note: The JaasAuthenticationProvider uses the security properites
|
||||
* A configuration note: The JaasAuthenticationProvider uses the security properties
|
||||
* "login.config.url.X" to configure jaas. If you would like to customize the way Jaas
|
||||
* gets configured, create a subclass of this and override the
|
||||
* {@link #configureJaas(Resource)} method.
|
||||
|
||||
@@ -40,7 +40,7 @@ public class SpringSecurityCoreVersion {
|
||||
*/
|
||||
public static final long SERIAL_VERSION_UID = 420L;
|
||||
|
||||
static final String MIN_SPRING_VERSION = "4.3.26.RELEASE";
|
||||
static final String MIN_SPRING_VERSION = "4.3.28.RELEASE";
|
||||
|
||||
static {
|
||||
performVersionChecks();
|
||||
|
||||
@@ -31,6 +31,7 @@ DigestAuthenticationFilter.usernameNotFound=Username {0} not found
|
||||
JdbcDaoImpl.noAuthority=User {0} has no GrantedAuthority
|
||||
JdbcDaoImpl.notFound=User {0} not found
|
||||
LdapAuthenticationProvider.badCredentials=Bad credentials
|
||||
LdapAuthenticationProvider.badLdapConnection=Connection to LDAP server failed
|
||||
LdapAuthenticationProvider.credentialsExpired=User credentials have expired
|
||||
LdapAuthenticationProvider.disabled=User is disabled
|
||||
LdapAuthenticationProvider.expired=User account has expired
|
||||
|
||||
+8
@@ -65,6 +65,10 @@ public class BCryptPasswordEncoder implements PasswordEncoder {
|
||||
}
|
||||
|
||||
public String encode(CharSequence rawPassword) {
|
||||
if (rawPassword == null) {
|
||||
throw new IllegalArgumentException("rawPassword cannot be null");
|
||||
}
|
||||
|
||||
String salt;
|
||||
if (strength > 0) {
|
||||
if (random != null) {
|
||||
@@ -81,6 +85,10 @@ public class BCryptPasswordEncoder implements PasswordEncoder {
|
||||
}
|
||||
|
||||
public boolean matches(CharSequence rawPassword, String encodedPassword) {
|
||||
if (rawPassword == null) {
|
||||
throw new IllegalArgumentException("rawPassword cannot be null");
|
||||
}
|
||||
|
||||
if (encodedPassword == null || encodedPassword.length() == 0) {
|
||||
logger.warn("Empty encoded password");
|
||||
return false;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2016 the original author or authors.
|
||||
* Copyright 2011-2020 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.
|
||||
@@ -32,16 +32,13 @@ public class Encryptors {
|
||||
* (Password-Based Key Derivation Function #2). Salts the password to prevent
|
||||
* dictionary attacks against the key. The provided salt is expected to be
|
||||
* hex-encoded; it should be random and at least 8 bytes in length. Also applies a
|
||||
* random 16 byte initialization vector to ensure each encrypted message will be
|
||||
* random 16-byte initialization vector to ensure each encrypted message will be
|
||||
* unique. Requires Java 6.
|
||||
*
|
||||
* @param password the password used to generate the encryptor's secret key; should
|
||||
* not be shared
|
||||
* @param salt a hex-encoded, random, site-global salt value to use to generate the
|
||||
* key
|
||||
*
|
||||
* @see #standard(CharSequence, CharSequence) which uses the slightly weaker CBC mode
|
||||
* (instead of GCM)
|
||||
*/
|
||||
public static BytesEncryptor stronger(CharSequence password, CharSequence salt) {
|
||||
return new AesBytesEncryptor(password.toString(), salt,
|
||||
@@ -53,13 +50,21 @@ public class Encryptors {
|
||||
* Derives the secret key using PKCS #5's PBKDF2 (Password-Based Key Derivation
|
||||
* Function #2). Salts the password to prevent dictionary attacks against the key. The
|
||||
* provided salt is expected to be hex-encoded; it should be random and at least 8
|
||||
* bytes in length. Also applies a random 16 byte initialization vector to ensure each
|
||||
* bytes in length. Also applies a random 16-byte initialization vector to ensure each
|
||||
* encrypted message will be unique. Requires Java 6.
|
||||
* NOTE: This mode is not
|
||||
* <a href="https://en.wikipedia.org/wiki/Authenticated_encryption">authenticated</a>
|
||||
* and does not provide any guarantees about the authenticity of the data.
|
||||
* For a more secure alternative, users should prefer
|
||||
* {@link #stronger(CharSequence, CharSequence)}.
|
||||
*
|
||||
* @param password the password used to generate the encryptor's secret key; should
|
||||
* not be shared
|
||||
* @param salt a hex-encoded, random, site-global salt value to use to generate the
|
||||
* key
|
||||
*
|
||||
* @see #stronger(CharSequence, CharSequence), which uses the significatly more secure
|
||||
* GCM (instead of CBC)
|
||||
*/
|
||||
public static BytesEncryptor standard(CharSequence password, CharSequence salt) {
|
||||
return new AesBytesEncryptor(password.toString(), salt,
|
||||
@@ -100,7 +105,10 @@ public class Encryptors {
|
||||
* not be shared
|
||||
* @param salt a hex-encoded, random, site-global salt value to use to generate the
|
||||
* secret key
|
||||
* @deprecated This encryptor is not secure. Instead, look to your data store for a
|
||||
* mechanism to query encrypted data.
|
||||
*/
|
||||
@Deprecated
|
||||
public static TextEncryptor queryableText(CharSequence password, CharSequence salt) {
|
||||
return new HexEncodingTextEncryptor(new AesBytesEncryptor(password.toString(),
|
||||
salt));
|
||||
|
||||
+2
-1
@@ -26,7 +26,8 @@ package org.springframework.security.crypto.password;
|
||||
* @deprecated This PasswordEncoder is not secure. Instead use an
|
||||
* adaptive one way function like BCryptPasswordEncoder, Pbkdf2PasswordEncoder, or
|
||||
* SCryptPasswordEncoder. Even better use {@link DelegatingPasswordEncoder} which supports
|
||||
* password upgrades.
|
||||
* password upgrades. There are no plans to remove this support. It is deprecated to indicate that
|
||||
* this is a legacy implementation and using it is considered insecure.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class NoOpPasswordEncoder implements PasswordEncoder {
|
||||
|
||||
+11
@@ -92,4 +92,15 @@ public class BCryptPasswordEncoderTests {
|
||||
assertThat(encoder.matches("password", "012345678901234567890123456789")).isFalse();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void encodeNullRawPassword() {
|
||||
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
|
||||
encoder.encode(null);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void matchNullRawPassword() {
|
||||
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
|
||||
encoder.matches(null, "does-not-matter");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6671,14 +6671,17 @@ The Encryptors class provides factory methods for constructing symmetric encrypt
|
||||
|
||||
[[spring-security-crypto-encryption-bytes]]
|
||||
==== BytesEncryptor
|
||||
Use the Encryptors.standard factory method to construct a "standard" BytesEncryptor:
|
||||
Use the `Encryptors.stronger` factory method to construct a BytesEncryptor:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
Encryptors.standard("password", "salt");
|
||||
Encryptors.stronger("password", "salt");
|
||||
----
|
||||
|
||||
The "standard" encryption method is 256-bit AES using PKCS #5's PBKDF2 (Password-Based Key Derivation Function #2). This method requires Java 6. The password used to generate the SecretKey should be kept in a secure place and not be shared. The salt is used to prevent dictionary attacks against the key in the event your encrypted data is compromised. A 16-byte random initialization vector is also applied so each encrypted message is unique.
|
||||
The "stronger" encryption method creates an encryptor using 256 bit AES encryption with
|
||||
Galois Counter Mode (GCM).
|
||||
It derives the secret key using PKCS #5's PBKDF2 (Password-Based Key Derivation Function #2).
|
||||
This method requires Java 6. The password used to generate the SecretKey should be kept in a secure place and not be shared. The salt is used to prevent dictionary attacks against the key in the event your encrypted data is compromised. A 16-byte random initialization vector is also applied so each encrypted message is unique.
|
||||
|
||||
The provided salt should be in hex-encoded String form, be random, and be at least 8 bytes in length. Such a salt may be generated using a KeyGenerator:
|
||||
|
||||
@@ -6687,6 +6690,11 @@ The provided salt should be in hex-encoded String form, be random, and be at lea
|
||||
String salt = KeyGenerators.string().generateKey(); // generates a random 8-byte salt that is then hex-encoded
|
||||
----
|
||||
|
||||
Users may also use the `standard` encryption method, which is 256-bit AES in Cipher Block Chaining (CBC) Mode.
|
||||
This mode is not https://en.wikipedia.org/wiki/Authenticated_encryption[authenticated] and does not provide any
|
||||
guarantees about the authenticity of the data.
|
||||
For a more secure alternative, users should prefer `Encryptors.stronger`.
|
||||
|
||||
[[spring-security-crypto-encryption-text]]
|
||||
==== TextEncryptor
|
||||
Use the Encryptors.text factory method to construct a standard TextEncryptor:
|
||||
|
||||
+3
-1
@@ -1 +1,3 @@
|
||||
version=4.2.14.RELEASE
|
||||
version=4.2.19.RELEASE
|
||||
|
||||
|
||||
|
||||
@@ -17,11 +17,11 @@ ext.commonsCollectionsVersion = '3.2.2'
|
||||
ext.commonsLoggingVersion = '1.2'
|
||||
ext.ehcacheVersion = '2.10.6'
|
||||
ext.gebVersion = '0.10.0'
|
||||
ext.groovyVersion = '2.4.4'
|
||||
ext.groovyVersion = '2.4.19'
|
||||
ext.hsqlVersion = '2.3.6'
|
||||
ext.hibernateVersion = '5.0.12.Final'
|
||||
ext.hibernateValidatorVersion = '5.3.6.Final'
|
||||
ext.jacksonDatabindVersion = '2.8.11.3'
|
||||
ext.jacksonDatabindVersion = '2.8.11.6'
|
||||
ext.javaPersistenceVersion = '2.1.1'
|
||||
ext.jettyVersion = '6.1.26'
|
||||
ext.jstlVersion = '1.2.2'
|
||||
@@ -77,7 +77,7 @@ ext.springCoreDependency = [
|
||||
|
||||
ext.jstlDependencies = [
|
||||
"javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:$jstlVersion",
|
||||
"org.apache.taglibs:taglibs-standard-jstlel:1.2.1"
|
||||
"org.apache.taglibs:taglibs-standard-jstlel:1.2.5"
|
||||
]
|
||||
|
||||
ext.apachedsDependencies = [
|
||||
|
||||
@@ -77,19 +77,6 @@ def customizePom(pom, gradleProject) {
|
||||
}
|
||||
}
|
||||
// Exclude spring-framework-bom for sample Boot projects since spring-boot-starter-parent imports spring-framework-bom
|
||||
if(!gradleProject.name.endsWith('-bom') && !sampleBootProjects.contains(gradleProject)) {
|
||||
dependencyManagement {
|
||||
dependencies {
|
||||
dependency {
|
||||
groupId 'org.springframework'
|
||||
artifactId 'spring-framework-bom'
|
||||
version project.springVersion
|
||||
type 'pom'
|
||||
scope 'import'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(isWar) {
|
||||
properties {
|
||||
'm2eclipse.wtp.contextRoot' '/' + project.war.baseName
|
||||
|
||||
@@ -10,7 +10,7 @@ buildscript {
|
||||
apply plugin: 'com.bmuschko.tomcat'
|
||||
|
||||
dependencies {
|
||||
def tomcatVersion = '7.0.90'
|
||||
def tomcatVersion = '7.0.103'
|
||||
tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
|
||||
"org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}",
|
||||
"org.apache.tomcat.embed:tomcat-embed-websocket:${tomcatVersion}",
|
||||
|
||||
+17
-4
@@ -16,6 +16,7 @@
|
||||
package org.springframework.security.ldap.authentication.ad;
|
||||
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.ldap.CommunicationException;
|
||||
import org.springframework.ldap.core.DirContextOperations;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.ldap.core.support.DefaultDirObjectFactory;
|
||||
@@ -24,6 +25,7 @@ import org.springframework.security.authentication.AccountExpiredException;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.CredentialsExpiredException;
|
||||
import org.springframework.security.authentication.DisabledException;
|
||||
import org.springframework.security.authentication.InternalAuthenticationServiceException;
|
||||
import org.springframework.security.authentication.LockedException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
@@ -140,12 +142,15 @@ public final class ActiveDirectoryLdapAuthenticationProvider extends
|
||||
UsernamePasswordAuthenticationToken auth) {
|
||||
String username = auth.getName();
|
||||
String password = (String) auth.getCredentials();
|
||||
|
||||
DirContext ctx = bindAsUser(username, password);
|
||||
DirContext ctx = null;
|
||||
|
||||
try {
|
||||
ctx = bindAsUser(username, password);
|
||||
return searchForUser(ctx, username);
|
||||
}
|
||||
catch (CommunicationException e) {
|
||||
throw badLdapConnection(e);
|
||||
}
|
||||
catch (NamingException e) {
|
||||
logger.error("Failed to locate directory entry for authenticated user: "
|
||||
+ username, e);
|
||||
@@ -207,8 +212,7 @@ public final class ActiveDirectoryLdapAuthenticationProvider extends
|
||||
|| (e instanceof OperationNotSupportedException)) {
|
||||
handleBindException(bindPrincipal, e);
|
||||
throw badCredentials(e);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
throw LdapUtils.convertLdapException(e);
|
||||
}
|
||||
}
|
||||
@@ -300,6 +304,12 @@ public final class ActiveDirectoryLdapAuthenticationProvider extends
|
||||
return (BadCredentialsException) badCredentials().initCause(cause);
|
||||
}
|
||||
|
||||
private InternalAuthenticationServiceException badLdapConnection(Throwable cause) {
|
||||
return new InternalAuthenticationServiceException(messages.getMessage(
|
||||
"LdapAuthenticationProvider.badLdapConnection",
|
||||
"Connection to LDAP server failed."), cause);
|
||||
}
|
||||
|
||||
private DirContextOperations searchForUser(DirContext context, String username)
|
||||
throws NamingException {
|
||||
SearchControls searchControls = new SearchControls();
|
||||
@@ -314,6 +324,9 @@ public final class ActiveDirectoryLdapAuthenticationProvider extends
|
||||
searchControls, searchRoot, searchFilter,
|
||||
new Object[] { bindPrincipal, username });
|
||||
}
|
||||
catch (CommunicationException ldapCommunicationException) {
|
||||
throw badLdapConnection(ldapCommunicationException);
|
||||
}
|
||||
catch (IncorrectResultSizeDataAccessException incorrectResults) {
|
||||
// Search should never return multiple results if properly configured - just
|
||||
// rethrow
|
||||
|
||||
+22
-6
@@ -32,6 +32,7 @@ import org.springframework.security.authentication.AccountExpiredException;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.CredentialsExpiredException;
|
||||
import org.springframework.security.authentication.DisabledException;
|
||||
import org.springframework.security.authentication.InternalAuthenticationServiceException;
|
||||
import org.springframework.security.authentication.LockedException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
@@ -58,6 +59,9 @@ import static org.springframework.security.ldap.authentication.ad.ActiveDirector
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class ActiveDirectoryLdapAuthenticationProviderTests {
|
||||
public static final String EXISTING_LDAP_PROVIDER = "ldap://192.168.1.200/";
|
||||
public static final String NON_EXISTING_LDAP_PROVIDER = "ldap://192.168.1.201/";
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@@ -378,17 +382,29 @@ public class ActiveDirectoryLdapAuthenticationProviderTests {
|
||||
}
|
||||
|
||||
@Test(expected = org.springframework.ldap.CommunicationException.class)
|
||||
public void nonAuthenticationExceptionIsConvertedToSpringLdapException()
|
||||
throws Exception {
|
||||
provider.contextFactory = createContextFactoryThrowing(new CommunicationException(
|
||||
msg));
|
||||
provider.authenticate(joe);
|
||||
public void nonAuthenticationExceptionIsConvertedToSpringLdapException() throws Throwable {
|
||||
try {
|
||||
provider.contextFactory = createContextFactoryThrowing(new CommunicationException(
|
||||
msg));
|
||||
provider.authenticate(joe);
|
||||
} catch (InternalAuthenticationServiceException e) {
|
||||
// Since GH-8418 ldap communication exception is wrapped into InternalAuthenticationServiceException.
|
||||
// This test is about the wrapped exception, so we throw it.
|
||||
throw e.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = org.springframework.security.authentication.InternalAuthenticationServiceException.class )
|
||||
public void connectionExceptionIsWrappedInInternalException() throws Exception {
|
||||
ActiveDirectoryLdapAuthenticationProvider noneReachableProvider = new ActiveDirectoryLdapAuthenticationProvider(
|
||||
"mydomain.eu", NON_EXISTING_LDAP_PROVIDER, "dc=ad,dc=eu,dc=mydomain");
|
||||
noneReachableProvider.doAuthentication(joe);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rootDnProvidedSeparatelyFromDomainAlsoWorks() throws Exception {
|
||||
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(
|
||||
"mydomain.eu", "ldap://192.168.1.200/", "dc=ad,dc=eu,dc=mydomain");
|
||||
"mydomain.eu", EXISTING_LDAP_PROVIDER, "dc=ad,dc=eu,dc=mydomain");
|
||||
checkAuthentication("dc=ad,dc=eu,dc=mydomain", provider);
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,6 @@ dependencies {
|
||||
|
||||
provided "javax.servlet:javax.servlet-api:$servletApiVersion"
|
||||
|
||||
runtime 'org.apache.httpcomponents:httpclient:4.2.5',
|
||||
'net.sourceforge.nekohtml:nekohtml:1.9.20'
|
||||
runtime 'org.apache.httpcomponents:httpclient:4.2.6',
|
||||
'net.sourceforge.nekohtml:nekohtml:1.9.22'
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ dependencies {
|
||||
"org.springframework:spring-core:$springVersion",
|
||||
"org.springframework:spring-aspects:$springVersion",
|
||||
"org.thymeleaf:thymeleaf-spring4:$thymeleafVersion",
|
||||
"nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:2.0.4",
|
||||
"nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:2.0.5",
|
||||
"org.eclipse.persistence:javax.persistence:$javaPersistenceVersion"
|
||||
compile("org.hibernate:hibernate-entitymanager:$hibernateVersion") {
|
||||
exclude group:'javassist', module: 'javassist'
|
||||
|
||||
@@ -23,5 +23,5 @@ dependencies {
|
||||
runtime "opensymphony:sitemesh:2.4.2",
|
||||
"cglib:cglib-nodep:$cglibVersion",
|
||||
'ch.qos.logback:logback-classic:0.9.30',
|
||||
"net.sourceforge.nekohtml:nekohtml:1.9.10"
|
||||
}
|
||||
"net.sourceforge.nekohtml:nekohtml:1.9.22"
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ apply plugin: 'jetty'
|
||||
apply plugin: 'groovy'
|
||||
|
||||
def excludeModules = ['spring-security-acl', 'jsr250-api', 'spring-jdbc', 'spring-tx']
|
||||
def jettyVersion = '8.1.9.v20130131'
|
||||
def jettyVersion = '8.1.22.v20160922'
|
||||
def keystore = "$rootDir/samples/certificates/server.jks"
|
||||
def password = 'password'
|
||||
|
||||
|
||||
@@ -2,14 +2,14 @@ apply plugin: 'war'
|
||||
apply plugin: 'jetty'
|
||||
apply plugin: 'appengine'
|
||||
|
||||
def gaeVersion="1.9.23"
|
||||
def gaeVersion="1.9.79"
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.google.appengine:gradle-appengine-plugin:1.9.23'
|
||||
classpath 'com.google.appengine:gradle-appengine-plugin:1.9.59'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,4 +49,4 @@ dependencies {
|
||||
|
||||
}
|
||||
|
||||
appengineRun.onlyIf { !gradle.taskGraph.hasTask(appengineFunctionalTest) }
|
||||
appengineRun.onlyIf { !gradle.taskGraph.hasTask(appengineFunctionalTest) }
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
releasenotes:
|
||||
sections:
|
||||
- title: "New Features"
|
||||
emoji: ":star:"
|
||||
labels: ["enhancement"]
|
||||
- title: "Bug Fixes"
|
||||
emoji: ":beetle:"
|
||||
labels: ["bug", "regression"]
|
||||
- title: "Dependency Upgrades"
|
||||
emoji: ":hammer:"
|
||||
labels: ["dependency-upgrade"]
|
||||
- title: "Non-passive"
|
||||
emoji: ":rewind:"
|
||||
labels: ["breaks-passivity"]
|
||||
+1
-1
@@ -43,7 +43,7 @@ final class WithMockUserSecurityContextFactory implements
|
||||
.username() : withUser.value();
|
||||
if (username == null) {
|
||||
throw new IllegalArgumentException(withUser
|
||||
+ " cannot have null username on both username and value properites");
|
||||
+ " cannot have null username on both username and value properties");
|
||||
}
|
||||
|
||||
List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
|
||||
|
||||
@@ -60,7 +60,7 @@ import java.util.*;
|
||||
* requests which match the pattern. An example configuration might look like this:
|
||||
*
|
||||
* <pre>
|
||||
* <bean id="myfilterChainProxy" class="org.springframework.security.util.FilterChainProxy">
|
||||
* <bean id="myfilterChainProxy" class="org.springframework.security.web.FilterChainProxy">
|
||||
* <constructor-arg>
|
||||
* <util:list>
|
||||
* <security:filter-chain pattern="/do/not/filter*" filters="none"/>
|
||||
|
||||
@@ -228,10 +228,15 @@ class DummyRequest extends HttpServletRequestWrapper {
|
||||
public void setQueryString(String queryString) {
|
||||
this.queryString = queryString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerName() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
final class UnsupportedOperationExceptionInvocationHandler implements InvocationHandler {
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
throw new UnsupportedOperationException(method + " is not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -563,6 +563,6 @@ public class SwitchUserFilter extends GenericFilterBean
|
||||
}
|
||||
|
||||
private static RequestMatcher createMatcher(String pattern) {
|
||||
return new AntPathRequestMatcher(pattern, null, true, new UrlPathHelper());
|
||||
return new AntPathRequestMatcher(pattern, "POST", true, new UrlPathHelper());
|
||||
}
|
||||
}
|
||||
|
||||
+39
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
@@ -16,14 +16,14 @@
|
||||
|
||||
package org.springframework.security.web.firewall;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -59,10 +59,15 @@ import java.util.Set;
|
||||
* Rejects URLs that contain a URL encoded percent. See
|
||||
* {@link #setAllowUrlEncodedPercent(boolean)}
|
||||
* </li>
|
||||
* <li>
|
||||
* Rejects hosts that are not allowed. See
|
||||
* {@link #setAllowedHostnames(Collection)}
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @see DefaultHttpFirewall
|
||||
* @author Rob Winch
|
||||
* @author Eddú Meléndez
|
||||
* @since 4.2.4
|
||||
*/
|
||||
public class StrictHttpFirewall implements HttpFirewall {
|
||||
@@ -82,6 +87,8 @@ public class StrictHttpFirewall implements HttpFirewall {
|
||||
|
||||
private Set<String> decodedUrlBlacklist = new HashSet<String>();
|
||||
|
||||
private Collection<String> allowedHostnames;
|
||||
|
||||
public StrictHttpFirewall() {
|
||||
urlBlacklistsAddAll(FORBIDDEN_SEMICOLON);
|
||||
urlBlacklistsAddAll(FORBIDDEN_FORWARDSLASH);
|
||||
@@ -230,6 +237,21 @@ public class StrictHttpFirewall implements HttpFirewall {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Determines which hostnames should be allowed. The default is to allow any hostname.
|
||||
* </p>
|
||||
*
|
||||
* @param allowedHostnames the set of allowed hostnames
|
||||
* @since 4.2.17
|
||||
*/
|
||||
public void setAllowedHostnames(Collection<String> allowedHostnames) {
|
||||
if (allowedHostnames == null) {
|
||||
throw new IllegalArgumentException("allowedHostnames cannot be null");
|
||||
}
|
||||
this.allowedHostnames = allowedHostnames;
|
||||
}
|
||||
|
||||
private void urlBlacklistsAddAll(Collection<String> values) {
|
||||
this.encodedUrlBlacklist.addAll(values);
|
||||
this.decodedUrlBlacklist.addAll(values);
|
||||
@@ -243,6 +265,7 @@ public class StrictHttpFirewall implements HttpFirewall {
|
||||
@Override
|
||||
public FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException {
|
||||
rejectedBlacklistedUrls(request);
|
||||
rejectedUntrustedHosts(request);
|
||||
|
||||
if (!isNormalized(request)) {
|
||||
throw new RequestRejectedException("The request was rejected because the URL was not normalized.");
|
||||
@@ -272,6 +295,19 @@ public class StrictHttpFirewall implements HttpFirewall {
|
||||
}
|
||||
}
|
||||
|
||||
private void rejectedUntrustedHosts(HttpServletRequest request) {
|
||||
String serverName = request.getServerName();
|
||||
if (serverName == null) {
|
||||
return;
|
||||
}
|
||||
if (this.allowedHostnames == null) {
|
||||
return;
|
||||
}
|
||||
if (!this.allowedHostnames.contains(serverName)) {
|
||||
throw new RequestRejectedException("The request was rejected because the domain " + serverName + " is untrusted.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpServletResponse getFirewalledResponse(HttpServletResponse response) {
|
||||
return new FirewalledResponse(response);
|
||||
|
||||
+7
-6
@@ -42,7 +42,6 @@ import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.logout.CompositeLogoutHandler;
|
||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@@ -82,7 +81,7 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory {
|
||||
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
|
||||
private AuthenticationEntryPoint authenticationEntryPoint;
|
||||
private AuthenticationManager authenticationManager;
|
||||
private LogoutHandler logoutHandler;
|
||||
private List<LogoutHandler> logoutHandlers;
|
||||
|
||||
HttpServlet3RequestFactory(String rolePrefix) {
|
||||
this.rolePrefix = rolePrefix;
|
||||
@@ -146,7 +145,7 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory {
|
||||
* {@link HttpServletRequest#logout()}.
|
||||
*/
|
||||
public void setLogoutHandlers(List<LogoutHandler> logoutHandlers) {
|
||||
this.logoutHandler = CollectionUtils.isEmpty(logoutHandlers) ? null : new CompositeLogoutHandler(logoutHandlers);
|
||||
this.logoutHandlers = logoutHandlers;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,8 +245,8 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory {
|
||||
|
||||
@Override
|
||||
public void logout() throws ServletException {
|
||||
LogoutHandler handler = HttpServlet3RequestFactory.this.logoutHandler;
|
||||
if (handler == null) {
|
||||
List<LogoutHandler> handlers = HttpServlet3RequestFactory.this.logoutHandlers;
|
||||
if (CollectionUtils.isEmpty(handlers)) {
|
||||
HttpServlet3RequestFactory.this.logger.debug(
|
||||
"logoutHandlers is null, so allowing original HttpServletRequest to handle logout");
|
||||
super.logout();
|
||||
@@ -255,7 +254,9 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory {
|
||||
}
|
||||
Authentication authentication = SecurityContextHolder.getContext()
|
||||
.getAuthentication();
|
||||
handler.logout(this, this.response, authentication);
|
||||
for (LogoutHandler handler : handlers) {
|
||||
handler.logout(this, this.response, authentication);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAuthenticated() {
|
||||
|
||||
+2
-2
@@ -67,7 +67,7 @@ public final class AntPathRequestMatcher
|
||||
|
||||
/**
|
||||
* Creates a matcher with the specific pattern which will match all HTTP methods in a
|
||||
* case insensitive manner.
|
||||
* case sensitive manner.
|
||||
*
|
||||
* @param pattern the ant pattern to use for matching
|
||||
*/
|
||||
@@ -76,7 +76,7 @@ public final class AntPathRequestMatcher
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a matcher with the supplied pattern and HTTP method in a case insensitive
|
||||
* Creates a matcher with the supplied pattern and HTTP method in a case sensitive
|
||||
* manner.
|
||||
*
|
||||
* @param pattern the ant pattern to use for matching
|
||||
|
||||
+42
-5
@@ -16,11 +16,17 @@
|
||||
|
||||
package org.springframework.security.web.authentication.switchuser;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import javax.servlet.FilterChain;
|
||||
|
||||
import org.junit.*;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.authentication.AccountExpiredException;
|
||||
@@ -42,8 +48,10 @@ import org.springframework.security.web.DefaultRedirectStrategy;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import java.util.*;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests
|
||||
@@ -75,6 +83,7 @@ public class SwitchUserFilterTests {
|
||||
request.setScheme("http");
|
||||
request.setServerName("localhost");
|
||||
request.setRequestURI("/login/impersonate");
|
||||
request.setMethod("POST");
|
||||
|
||||
return request;
|
||||
}
|
||||
@@ -125,6 +134,20 @@ public class SwitchUserFilterTests {
|
||||
assertThat(filter.requiresExitUser(request)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
// gh-4183
|
||||
public void requiresExitUserWhenGetThenDoesNotMatch() {
|
||||
SwitchUserFilter filter = new SwitchUserFilter();
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setScheme("http");
|
||||
request.setServerName("localhost");
|
||||
request.setRequestURI("/login/impersonate");
|
||||
request.setMethod("GET");
|
||||
|
||||
assertThat(filter.requiresExitUser(request)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requiresExitUserWhenMatcherThenWorks() {
|
||||
SwitchUserFilter filter = new SwitchUserFilter();
|
||||
@@ -159,6 +182,20 @@ public class SwitchUserFilterTests {
|
||||
assertThat(filter.requiresSwitchUser(request)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
// gh-4183
|
||||
public void requiresSwitchUserWhenGetThenDoesNotMatch() {
|
||||
SwitchUserFilter filter = new SwitchUserFilter();
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setScheme("http");
|
||||
request.setServerName("localhost");
|
||||
request.setRequestURI("/login/impersonate");
|
||||
request.setMethod("GET");
|
||||
|
||||
assertThat(filter.requiresSwitchUser(request)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requiresSwitchUserWhenMatcherThenWorks() {
|
||||
SwitchUserFilter filter = new SwitchUserFilter();
|
||||
|
||||
+42
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2020 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.
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.security.web.firewall;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
@@ -23,6 +25,7 @@ import static org.assertj.core.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
public class StrictHttpFirewallTests {
|
||||
public String[] unnormalizedPaths = { "/..", "/./path/", "/path/path/.", "/path/path//.", "./path/../path//.",
|
||||
@@ -373,4 +376,42 @@ public class StrictHttpFirewallTests {
|
||||
|
||||
this.firewall.getFirewalledRequest(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFirewalledRequestWhenTrustedDomainThenNoException() {
|
||||
String host = "example.org";
|
||||
this.request.addHeader("Host", host);
|
||||
this.firewall.setAllowedHostnames(Arrays.asList(host));
|
||||
|
||||
try {
|
||||
this.firewall.getFirewalledRequest(this.request);
|
||||
} catch (RequestRejectedException fail) {
|
||||
fail("Host " + host + " was rejected");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFirewalledRequestWhenUntrustedDomainThenException() {
|
||||
String host = "example.org";
|
||||
this.request.addHeader("Host", host);
|
||||
this.firewall.setAllowedHostnames(Arrays.asList("myexample.org"));
|
||||
|
||||
try {
|
||||
this.firewall.getFirewalledRequest(this.request);
|
||||
fail("Host " + host + " was accepted");
|
||||
} catch (RequestRejectedException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFirewalledRequestWhenDefaultsThenNoException() {
|
||||
String host = "example.org";
|
||||
this.request.addHeader("Host", host);
|
||||
|
||||
try {
|
||||
this.firewall.getFirewalledRequest(this.request);
|
||||
} catch (RequestRejectedException fail) {
|
||||
fail("Host " + host + " was rejected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user