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

Compare commits

..

51 Commits

Author SHA1 Message Date
Rob Winch b0651b97fd Release 4.2.19.RELEASE 2020-10-07 14:17:57 -05:00
Rob Winch 7cce996ebe Fix SpringSecurityCoreVersion
Issue gh-9103
2020-10-07 13:49:25 -05:00
Rob Winch 2aa09d11e2 Update to Spring 4.3.28.RELEASE
Closes gh-9103
2020-10-07 13:41:54 -05:00
Artem Grankin 8ab8376b9c Replace expired msdn link with latest web archive copy
Initial link expired in March, 2016. Latest copy found in web archive is from February, 2016
2020-09-28 17:49:27 -06:00
Rob Winch 5699a36627 Next Development Version 2020-08-04 16:26:54 -05:00
Rob Winch 0f0e973c1e Release 4.2.18.RELEASE 2020-08-04 16:26:16 -05:00
Josh Cummings 9c76f54958 Polish WebSecurityConfigurerAdapter JavaDoc
Issue gh-8784
2020-07-20 15:26:40 -06:00
Romil Patel 14e4a812a1 WebSecurityConfigurerAdapter JavaDoc
Closes gh-8784
2020-07-20 15:26:36 -06:00
Ellie Bahadori be0759302f Use Github Actions PR pipeline and remove Travis for 4.2.x
Closes gh-8715
2020-07-02 04:15:52 -04:00
Rob Winch ff25799f36 Next Development Version 2020-06-03 11:46:10 -05:00
Rob Winch 54b28873ee Release 4.2.17.RELEASE 2020-06-03 11:34:37 -05:00
Josh Cummings 692ac213f9 Polish setAllowedHostnames
Added JavaDoc to method, including @since attribute

Issue gh-4310
2020-06-03 07:52:26 -06:00
Eddú Meléndez e4e7363196 Add support for allowedHostnames in StrictHttpFirewall
Introduce a new method `setAllowedHostnames` which perform the validation
against untrusted hostnames.

Fixes gh-4310
2020-06-03 07:52:26 -06:00
Rob Winch 75e248344b uploadArchives dependsOn mavenBom
Closes gh-7975
2020-06-02 16:27:00 -05:00
Artyom Tarynin 3ae6cdf05f Update AntPathRequestMatcher.java
Fixes gh-8512
2020-05-14 11:00:04 -04:00
Dávid Kovács a9c8b350b8 Document NoOpPasswordEncoder will not be removed
This commit adds extension to deprecation notice.

Fixes gh-8506
2020-05-13 12:57:23 -05:00
Rob Winch da9eca223b Next Development Version 2020-05-06 13:01:59 -05:00
Rob Winch c7e18db138 Stop clearing artifacts
Getting a NoSuchElement when signing releases
2020-05-06 11:51:27 -05:00
Rob Winch 9c181c58cb Revert "uploadArchives.dependsOn mavenBom"
This reverts commit a302106082.
2020-05-06 11:34:45 -05:00
Rob Winch 7b61962915 Release 4.2.16.RELEASE 2020-05-06 11:03:38 -05:00
Rob Winch a302106082 uploadArchives.dependsOn mavenBom
Closes gh-7975
2020-05-06 10:41:55 -05:00
Eleftheria Stein fe737cc67d Clean up Javadoc
Fixes gh-8480
2020-05-05 17:35:06 -04:00
Rob Winch d4508858f3 Add ROLE_INFRASTRUCTURE to infrastructure beans
Closes gh-8407
2020-04-27 09:27:06 -05:00
Dávid Kovács 76432029c5 ActiveDirectoryLdapAuthenticationProvider uses InternalAuthenticationServiceException
Closes gh-2884
2020-04-24 10:57:53 -05:00
Rob Winch 0d0afb992e Fix example in javadoc of FilterChainProxy
Closes gh-8344
2020-04-08 09:16:08 -05:00
Rob Winch b35d7e229d Next Development Version 2020-04-07 14:25:50 -05:00
Alan Czajkowski 3c81e122bd BCryptPasswordEncoder rawPassword cannot be null
Closes gh-8317
2020-04-07 13:48:29 -05:00
Josh Cummings 929a5de163 Release 4.2.15.RELEASE 2020-04-01 12:40:05 -06:00
Josh Cummings ecac6cdfc1 Remove spring-framework-bom Manual Insertion
spring-io-plugin can do this now

Issue gh-8271
2020-04-01 12:01:09 -06:00
Josh Cummings 2ad73af130 Revert "Release 4.2.15.RELEASE"
This reverts commit 0aaefa2bb9.
2020-04-01 09:19:36 -06:00
Josh Cummings 0aaefa2bb9 Release 4.2.15.RELEASE 2020-04-01 08:03:20 -06:00
Josh Cummings 21c70155a3 Update to spring-boot-gradle-plugin:1.5.22.RELEASE
Fixes gh-8262
2020-04-01 00:35:00 -06:00
Josh Cummings 7ca913dadf Update to Groovy 2.4.19
Fixes gh-8263
2020-04-01 00:34:55 -06:00
Josh Cummings 7eb87b19b3 Update to asciidoctor-gradle-plugin:1.5.7
Fixes gh-8264
2020-04-01 00:34:49 -06:00
Josh Cummings 1683d30c2e Update to Tomcat 7.0.103
Fixes gh-8265
2020-04-01 00:34:43 -06:00
Josh Cummings adfb3ddf77 Update to Jetty 8.1.22.v20160922
Fixes gh-8266
2020-04-01 00:34:30 -06:00
Josh Cummings 1ba1fb61a7 Update to taglibs-standard-jstlel:1.2.5
Fixes gh-8267
2020-04-01 00:34:21 -06:00
Josh Cummings e3a1fa2f86 Update to httpclient:4.2.6
Fixes gh-8268
2020-04-01 00:34:14 -06:00
Josh Cummings ac657a32a6 Update to thymeleaf-layout-dialect:2.0.5
Fixes gh-8269
2020-04-01 00:34:03 -06:00
Josh Cummings 6c98a49010 Update to nekohtml:1.9.22
Fixes gh-8270
2020-04-01 00:33:48 -06:00
Josh Cummings f2db4b6cdb Update to spring-io-plugin:0.0.8.RELEASE
Fixes gh-8271
2020-04-01 00:33:41 -06:00
Josh Cummings 9156d3bce3 Update to appengine:1.9.79
Fixes gh-8272
2020-04-01 00:33:21 -06:00
Josh Cummings 327c52d650 Update to jackson-databind:2.8.11.6
Fixes gh-8273
2020-04-01 00:31:51 -06:00
Rob Winch d98d23e5ef Fix HttpServlet3RequestFactory Logout Handlers
Previously there was a problem with Servlet API logout integration
when Servlet API was configured before log out.

This ensures that logout handlers is a reference to the logout handlers
vs copying the logout handlers. This ensures that the ordering does not
matter.

Closes gh-4760
2020-03-30 22:20:20 -05:00
Rob Winch f892746c00 uploadArchives customizePom for bom
Previously the bom was not being customized for the uploadArchives task.

This commit enhances the bom plugin to support uploadArchives.

Closes gh-7975
2020-03-30 09:47:52 -05:00
Josh Cummings b95ccc211b Add Missing Import
Restored an import that was lost during a backport

Issue gh-4183
2020-03-27 15:07:57 -06:00
Josh Cummings 820b2046fb SwitchUserFilter Defaults to POST
Fixes gh-4183
2020-03-27 14:44:00 -06:00
Eleftheria Stein bde423524b Update Encryptors documentation
Fixes gh-8208
2020-03-27 11:24:53 -04:00
Markus Engelbrecht 78d8b9fa71 Fix typo 'properites' in documentation
Fixes gh-8095
2020-03-11 11:06:30 -06:00
Rob Winch 35bbccad3c Add release-notes-sections.yml 2020-02-06 07:54:37 -06:00
Rob Winch 04cc0d486b Next Development Version 2020-02-06 07:28:00 -06:00
42 changed files with 339 additions and 110 deletions
+22
View File
@@ -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
View File
@@ -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
-2
View File
@@ -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
View File
@@ -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
}
}
+25 -15
View File
@@ -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 {
}
}
}
}
}
@@ -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.
@@ -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);
@@ -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
@@ -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();
}
@@ -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
*/
@@ -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}.
@@ -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>
*
@@ -129,7 +129,7 @@ import org.springframework.util.Assert;
* &lt;/property&gt;
* </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
@@ -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));
@@ -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 {
@@ -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");
}
}
+11 -3
View File
@@ -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
View File
@@ -1 +1,3 @@
version=4.2.14.RELEASE
version=4.2.19.RELEASE
+3 -3
View File
@@ -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 = [
-13
View File
@@ -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
+1 -1
View File
@@ -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}",
@@ -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
@@ -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);
}
+2 -2
View File
@@ -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'
}
+1 -1
View File
@@ -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'
+2 -2
View File
@@ -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"
}
+1 -1
View File
@@ -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'
+3 -3
View File
@@ -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"]
@@ -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>
* &lt;bean id="myfilterChainProxy" class="org.springframework.security.util.FilterChainProxy"&gt;
* &lt;bean id="myfilterChainProxy" class="org.springframework.security.web.FilterChainProxy"&gt;
* &lt;constructor-arg&gt;
* &lt;util:list&gt;
* &lt;security:filter-chain pattern="/do/not/filter*" filters="none"/&gt;
@@ -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");
}
}
}
@@ -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());
}
}
@@ -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);
@@ -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() {
@@ -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
@@ -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();
@@ -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");
}
}
}