Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1526c981aa | |||
| a9ddd363aa | |||
| 4edcac7651 | |||
| eecad9ee9a | |||
| 0191e1f11e | |||
| d73f0c5fb9 | |||
| 8d07698d94 | |||
| c9c9532447 | |||
| d2d9ce9e6b | |||
| df6e58ca1d | |||
| ffa1bc8083 | |||
| c91e456ae7 | |||
| 45d81ffc49 | |||
| 3a787e2c4f | |||
| b50e511745 | |||
| e3a11c98bd | |||
| d4ceabd7ac | |||
| 475a53233d | |||
| d245b0466a | |||
| d1162c39ce | |||
| 888aa15e20 | |||
| b92f105f35 | |||
| 8febecd43f | |||
| 425b7783b5 | |||
| b7ee7136b2 | |||
| 0d331b08b9 | |||
| c47d72fd12 | |||
| 248c956962 | |||
| 530def3af0 | |||
| e6049fce26 | |||
| 0105e95ba2 | |||
| ded544de14 | |||
| 7d845b6872 | |||
| 97818ebb22 | |||
| f2ee151d63 | |||
| 8da27b5f41 | |||
| 466b8a1d82 | |||
| 0532b6e665 | |||
| c94a79c3a9 | |||
| 09343eb240 | |||
| 90c509d3c5 | |||
| 3b79bff44d | |||
| 3d8819447f | |||
| 863e45ca6c | |||
| b520d36abb | |||
| b03fdd8e25 | |||
| 0f5e37172d | |||
| 7498248910 | |||
| f3a90df1ef | |||
| c3b4cabb9f | |||
| 8e3678c79d | |||
| facc7299e3 | |||
| b94e4c0197 |
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
language: java
|
language: java
|
||||||
|
|
||||||
jdk:
|
jdk:
|
||||||
- oraclejdk8
|
- openjdk8
|
||||||
|
|
||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
|
|||||||
Vendored
+18
-8
@@ -14,7 +14,9 @@ try {
|
|||||||
node {
|
node {
|
||||||
checkout scm
|
checkout scm
|
||||||
try {
|
try {
|
||||||
sh "./gradlew clean check --refresh-dependencies --no-daemon --stacktrace"
|
withEnv(["JAVA_HOME=${ tool 'jdk8' }"]) {
|
||||||
|
sh "./gradlew clean check --refresh-dependencies --no-daemon --stacktrace"
|
||||||
|
}
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
currentBuild.result = 'FAILED: check'
|
currentBuild.result = 'FAILED: check'
|
||||||
throw e
|
throw e
|
||||||
@@ -30,10 +32,12 @@ try {
|
|||||||
checkout scm
|
checkout scm
|
||||||
withCredentials([string(credentialsId: 'spring-sonar.login', variable: 'SONAR_LOGIN')]) {
|
withCredentials([string(credentialsId: 'spring-sonar.login', variable: 'SONAR_LOGIN')]) {
|
||||||
try {
|
try {
|
||||||
if ("master" == env.BRANCH_NAME) {
|
withEnv(["JAVA_HOME=${ tool 'jdk8' }"]) {
|
||||||
sh "./gradlew sonarqube -PexcludeProjects='**/samples/**' -Dsonar.host.url=$SPRING_SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN --refresh-dependencies --no-daemon --stacktrace"
|
if ("master" == env.BRANCH_NAME) {
|
||||||
} else {
|
sh "./gradlew sonarqube -PexcludeProjects='**/samples/**' -Dsonar.host.url=$SPRING_SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN --refresh-dependencies --no-daemon --stacktrace"
|
||||||
sh "./gradlew sonarqube -PexcludeProjects='**/samples/**' -Dsonar.projectKey='spring-security-${env.BRANCH_NAME}' -Dsonar.projectName='spring-security-${env.BRANCH_NAME}' -Dsonar.host.url=$SPRING_SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN --refresh-dependencies --no-daemon --stacktrace"
|
} else {
|
||||||
|
sh "./gradlew sonarqube -PexcludeProjects='**/samples/**' -Dsonar.projectKey='spring-security-${env.BRANCH_NAME}' -Dsonar.projectName='spring-security-${env.BRANCH_NAME}' -Dsonar.host.url=$SPRING_SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN --refresh-dependencies --no-daemon --stacktrace"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
currentBuild.result = 'FAILED: sonar'
|
currentBuild.result = 'FAILED: sonar'
|
||||||
@@ -53,7 +57,9 @@ try {
|
|||||||
withCredentials([string(credentialsId: 'spring-gpg-passphrase', variable: 'SIGNING_PASSWORD')]) {
|
withCredentials([string(credentialsId: 'spring-gpg-passphrase', variable: 'SIGNING_PASSWORD')]) {
|
||||||
withCredentials([usernamePassword(credentialsId: 'oss-token', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USERNAME')]) {
|
withCredentials([usernamePassword(credentialsId: 'oss-token', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USERNAME')]) {
|
||||||
withCredentials([usernamePassword(credentialsId: '02bd1690-b54f-4c9f-819d-a77cb7a9822c', usernameVariable: 'ARTIFACTORY_USERNAME', passwordVariable: 'ARTIFACTORY_PASSWORD')]) {
|
withCredentials([usernamePassword(credentialsId: '02bd1690-b54f-4c9f-819d-a77cb7a9822c', usernameVariable: 'ARTIFACTORY_USERNAME', passwordVariable: 'ARTIFACTORY_PASSWORD')]) {
|
||||||
sh "./gradlew deployArtifacts finalizeDeployArtifacts -Psigning.secretKeyRingFile=$SIGNING_KEYRING_FILE -Psigning.keyId=$SPRING_SIGNING_KEYID -Psigning.password='$SIGNING_PASSWORD' -PossrhUsername=$OSSRH_USERNAME -PossrhPassword=$OSSRH_PASSWORD -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --refresh-dependencies --no-daemon --stacktrace"
|
withEnv(["JAVA_HOME=${ tool 'jdk8' }"]) {
|
||||||
|
sh "./gradlew deployArtifacts finalizeDeployArtifacts -Psigning.secretKeyRingFile=$SIGNING_KEYRING_FILE -Psigning.keyId=$SPRING_SIGNING_KEYID -Psigning.password='$SIGNING_PASSWORD' -PossrhUsername=$OSSRH_USERNAME -PossrhPassword=$OSSRH_PASSWORD -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --refresh-dependencies --no-daemon --stacktrace"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,7 +72,9 @@ try {
|
|||||||
node {
|
node {
|
||||||
checkout scm
|
checkout scm
|
||||||
withCredentials([file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')]) {
|
withCredentials([file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')]) {
|
||||||
sh "./gradlew deployDocs -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --refresh-dependencies --no-daemon --stacktrace"
|
withEnv(["JAVA_HOME=${ tool 'jdk8' }"]) {
|
||||||
|
sh "./gradlew deployDocs -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --refresh-dependencies --no-daemon --stacktrace"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,7 +84,9 @@ try {
|
|||||||
node {
|
node {
|
||||||
checkout scm
|
checkout scm
|
||||||
withCredentials([file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')]) {
|
withCredentials([file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')]) {
|
||||||
sh "./gradlew deploySchema -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --refresh-dependencies --no-daemon --stacktrace"
|
withEnv(["JAVA_HOME=${ tool 'jdk8' }"]) {
|
||||||
|
sh "./gradlew deploySchema -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --refresh-dependencies --no-daemon --stacktrace"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+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.
|
* CAS artifactParameterName.
|
||||||
*
|
*
|
||||||
* @param serviceProperties The ServiceProperties to use to construct the serviceUrl.
|
* @param serviceProperties The ServiceProperties to use to construct the serviceUrl.
|
||||||
|
|||||||
+1
-1
@@ -721,7 +721,7 @@ public final class HttpSecurity extends
|
|||||||
* }
|
* }
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @return the {@link ServletApiConfigurer} for further customizations
|
* @return the {@link CsrfConfigurer} for further customizations
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public CsrfConfigurer<HttpSecurity> csrf() throws Exception {
|
public CsrfConfigurer<HttpSecurity> csrf() throws Exception {
|
||||||
|
|||||||
+1
-1
@@ -168,7 +168,7 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies the {@link AuthenticationSuccessHandler} to be used. The default is
|
* Specifies the {@link AuthenticationSuccessHandler} to be used. The default is
|
||||||
* {@link SavedRequestAwareAuthenticationSuccessHandler} with no additional properites
|
* {@link SavedRequestAwareAuthenticationSuccessHandler} with no additional properties
|
||||||
* set.
|
* set.
|
||||||
*
|
*
|
||||||
* @param successHandler the {@link AuthenticationSuccessHandler}.
|
* @param successHandler the {@link AuthenticationSuccessHandler}.
|
||||||
|
|||||||
-2
@@ -17,7 +17,6 @@ package org.springframework.security.access.expression;
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.springframework.security.access.PermissionEvaluator;
|
import org.springframework.security.access.PermissionEvaluator;
|
||||||
@@ -158,7 +157,6 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
|
|||||||
|
|
||||||
private Set<String> getAuthoritySet() {
|
private Set<String> getAuthoritySet() {
|
||||||
if (roles == null) {
|
if (roles == null) {
|
||||||
roles = new HashSet<>();
|
|
||||||
Collection<? extends GrantedAuthority> userAuthorities = authentication
|
Collection<? extends GrantedAuthority> userAuthorities = authentication
|
||||||
.getAuthorities();
|
.getAuthorities();
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -129,7 +129,7 @@ import org.springframework.util.Assert;
|
|||||||
* </property>
|
* </property>
|
||||||
* </pre>
|
* </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
|
* "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
|
* gets configured, create a subclass of this and override the
|
||||||
* {@link #configureJaas(Resource)} method.
|
* {@link #configureJaas(Resource)} method.
|
||||||
|
|||||||
+31
-29
@@ -132,13 +132,18 @@ public class SessionRegistryImpl implements SessionRegistry,
|
|||||||
sessionIds.put(sessionId,
|
sessionIds.put(sessionId,
|
||||||
new SessionInformation(principal, sessionId, new Date()));
|
new SessionInformation(principal, sessionId, new Date()));
|
||||||
|
|
||||||
Set<String> sessionsUsedByPrincipal = principals.computeIfAbsent(principal, key -> new CopyOnWriteArraySet<>());
|
principals.compute(principal, (key, sessionsUsedByPrincipal) -> {
|
||||||
sessionsUsedByPrincipal.add(sessionId);
|
if (sessionsUsedByPrincipal == null) {
|
||||||
|
sessionsUsedByPrincipal = new CopyOnWriteArraySet<>();
|
||||||
|
}
|
||||||
|
sessionsUsedByPrincipal.add(sessionId);
|
||||||
|
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace("Sessions used by '" + principal + "' : "
|
logger.trace("Sessions used by '" + principal + "' : "
|
||||||
+ sessionsUsedByPrincipal);
|
+ sessionsUsedByPrincipal);
|
||||||
}
|
}
|
||||||
|
return sessionsUsedByPrincipal;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeSessionInformation(String sessionId) {
|
public void removeSessionInformation(String sessionId) {
|
||||||
@@ -157,32 +162,29 @@ public class SessionRegistryImpl implements SessionRegistry,
|
|||||||
|
|
||||||
sessionIds.remove(sessionId);
|
sessionIds.remove(sessionId);
|
||||||
|
|
||||||
Set<String> sessionsUsedByPrincipal = principals.get(info.getPrincipal());
|
principals.computeIfPresent(info.getPrincipal(), (key, sessionsUsedByPrincipal) -> {
|
||||||
|
|
||||||
if (sessionsUsedByPrincipal == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Removing session " + sessionId
|
|
||||||
+ " from principal's set of registered sessions");
|
|
||||||
}
|
|
||||||
|
|
||||||
sessionsUsedByPrincipal.remove(sessionId);
|
|
||||||
|
|
||||||
if (sessionsUsedByPrincipal.isEmpty()) {
|
|
||||||
// No need to keep object in principals Map anymore
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Removing principal " + info.getPrincipal()
|
logger.debug("Removing session " + sessionId
|
||||||
+ " from registry");
|
+ " from principal's set of registered sessions");
|
||||||
}
|
}
|
||||||
principals.remove(info.getPrincipal());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logger.isTraceEnabled()) {
|
sessionsUsedByPrincipal.remove(sessionId);
|
||||||
logger.trace("Sessions used by '" + info.getPrincipal() + "' : "
|
|
||||||
+ sessionsUsedByPrincipal);
|
if (sessionsUsedByPrincipal.isEmpty()) {
|
||||||
}
|
// No need to keep object in principals Map anymore
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Removing principal " + info.getPrincipal()
|
||||||
|
+ " from registry");
|
||||||
|
}
|
||||||
|
sessionsUsedByPrincipal = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger.isTraceEnabled()) {
|
||||||
|
logger.trace("Sessions used by '" + info.getPrincipal() + "' : "
|
||||||
|
+ sessionsUsedByPrincipal);
|
||||||
|
}
|
||||||
|
return sessionsUsedByPrincipal;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,9 +39,6 @@ public class Encryptors {
|
|||||||
* not be shared
|
* not be shared
|
||||||
* @param salt a hex-encoded, random, site-global salt value to use to generate the
|
* @param salt a hex-encoded, random, site-global salt value to use to generate the
|
||||||
* key
|
* key
|
||||||
*
|
|
||||||
* @see #standard(CharSequence, CharSequence) which uses the slightly weaker CBC mode
|
|
||||||
* (instead of GCM)
|
|
||||||
*/
|
*/
|
||||||
public static BytesEncryptor stronger(CharSequence password, CharSequence salt) {
|
public static BytesEncryptor stronger(CharSequence password, CharSequence salt) {
|
||||||
return new AesBytesEncryptor(password.toString(), salt,
|
return new AesBytesEncryptor(password.toString(), salt,
|
||||||
@@ -55,11 +52,19 @@ public class Encryptors {
|
|||||||
* provided salt is expected to be hex-encoded; it should be random and at least 8
|
* 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.
|
* 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
|
* @param password the password used to generate the encryptor's secret key; should
|
||||||
* not be shared
|
* not be shared
|
||||||
* @param salt a hex-encoded, random, site-global salt value to use to generate the
|
* @param salt a hex-encoded, random, site-global salt value to use to generate the
|
||||||
* key
|
* key
|
||||||
|
*
|
||||||
|
* @see #stronger(CharSequence, CharSequence) which uses the significatly more secure
|
||||||
|
* GCM (instead of CBC)
|
||||||
*/
|
*/
|
||||||
public static BytesEncryptor standard(CharSequence password, CharSequence salt) {
|
public static BytesEncryptor standard(CharSequence password, CharSequence salt) {
|
||||||
return new AesBytesEncryptor(password.toString(), salt,
|
return new AesBytesEncryptor(password.toString(), salt,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ Finally, welcome to the Spring Security <<community,community>>.
|
|||||||
|
|
||||||
[[getting-started]]
|
[[getting-started]]
|
||||||
== Getting Started
|
== Getting Started
|
||||||
The later parts of this guide provide an in-depth discussion of the framework architecture and implementation classes, which you need to understand if you want to do any serious customization. In this part, we'll introduce Spring Security 4.0, give a brief overview of the project's history and take a slightly gentler look at how to get started using the framework. In particular, we'll look at namespace configuration which provides a much simpler way of securing your application compared to the traditional Spring bean approach where you have to wire up all the implementation classes individually.
|
The later parts of this guide provide an in-depth discussion of the framework architecture and implementation classes, which you need to understand if you want to do any serious customization. In this part, we'll introduce Spring Security 5.0, give a brief overview of the project's history and take a slightly gentler look at how to get started using the framework. In particular, we'll look at namespace configuration which provides a much simpler way of securing your application compared to the traditional Spring bean approach where you have to wire up all the implementation classes individually.
|
||||||
|
|
||||||
We'll also take a look at the sample applications that are available. It's worth trying to run these and experimenting with them a bit even before you read the later sections - you can dip back into them as your understanding of the framework increases. Please also check out the https://spring.io/spring-security[project website] as it has useful information on building the project, plus links to articles, videos and tutorials.
|
We'll also take a look at the sample applications that are available. It's worth trying to run these and experimenting with them a bit even before you read the later sections - you can dip back into them as your understanding of the framework increases. Please also check out the https://spring.io/spring-security[project website] as it has useful information on building the project, plus links to articles, videos and tutorials.
|
||||||
|
|
||||||
@@ -7980,14 +7980,17 @@ The Encryptors class provides factory methods for constructing symmetric encrypt
|
|||||||
|
|
||||||
[[spring-security-crypto-encryption-bytes]]
|
[[spring-security-crypto-encryption-bytes]]
|
||||||
==== BytesEncryptor
|
==== BytesEncryptor
|
||||||
Use the Encryptors.standard factory method to construct a "standard" BytesEncryptor:
|
Use the `Encryptors.stronger` factory method to construct a BytesEncryptor:
|
||||||
|
|
||||||
[source,java]
|
[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:
|
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:
|
||||||
|
|
||||||
@@ -7996,6 +7999,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
|
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]]
|
[[spring-security-crypto-encryption-text]]
|
||||||
==== TextEncryptor
|
==== TextEncryptor
|
||||||
Use the Encryptors.text factory method to construct a standard TextEncryptor:
|
Use the Encryptors.text factory method to construct a standard TextEncryptor:
|
||||||
|
|||||||
+3
-3
@@ -1,3 +1,3 @@
|
|||||||
gaeVersion=1.9.68
|
gaeVersion=1.9.79
|
||||||
springBootVersion=2.0.8.RELEASE
|
springBootVersion=2.0.9.RELEASE
|
||||||
version=5.0.12.RELEASE
|
version=5.0.15.RELEASE
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
dependencyManagement {
|
dependencyManagement {
|
||||||
imports {
|
imports {
|
||||||
mavenBom 'io.projectreactor:reactor-bom:Bismuth-SR17'
|
mavenBom 'io.projectreactor:reactor-bom:Bismuth-SR17'
|
||||||
mavenBom 'org.springframework:spring-framework-bom:5.0.13.RELEASE'
|
mavenBom 'org.springframework:spring-framework-bom:5.0.16.RELEASE'
|
||||||
mavenBom 'org.springframework.data:spring-data-releasetrain:Kay-SR14'
|
mavenBom 'org.springframework.data:spring-data-releasetrain:Kay-SR14'
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
dependency 'cglib:cglib-nodep:3.2.10'
|
dependency 'cglib:cglib-nodep:3.2.12'
|
||||||
dependency 'com.squareup.okhttp3:mockwebserver:3.12.2'
|
dependency 'com.squareup.okhttp3:mockwebserver:3.12.10'
|
||||||
dependency 'opensymphony:sitemesh:2.4.2'
|
dependency 'opensymphony:sitemesh:2.4.2'
|
||||||
dependency 'org.gebish:geb-spock:0.10.0'
|
dependency 'org.gebish:geb-spock:0.10.0'
|
||||||
dependency 'org.jasig.cas:cas-server-webapp:4.2.7'
|
dependency 'org.jasig.cas:cas-server-webapp:4.2.7'
|
||||||
dependency 'org.powermock:powermock-api-mockito2:2.0.0'
|
dependency 'org.powermock:powermock-api-mockito2:2.0.6'
|
||||||
dependency 'org.powermock:powermock-api-support:2.0.0'
|
dependency 'org.powermock:powermock-api-support:2.0.6'
|
||||||
dependency 'org.powermock:powermock-core:2.0.0'
|
dependency 'org.powermock:powermock-core:2.0.6'
|
||||||
dependency 'org.powermock:powermock-module-junit4-common:2.0.0'
|
dependency 'org.powermock:powermock-module-junit4-common:2.0.6'
|
||||||
dependency 'org.powermock:powermock-module-junit4:2.0.0'
|
dependency 'org.powermock:powermock-module-junit4:2.0.6'
|
||||||
dependency 'org.powermock:powermock-reflect:2.0.0'
|
dependency 'org.powermock:powermock-reflect:2.0.6'
|
||||||
dependency 'org.python:jython:2.5.0'
|
dependency 'org.python:jython:2.5.0'
|
||||||
dependency 'org.spockframework:spock-core:1.0-groovy-2.4'
|
dependency 'org.spockframework:spock-core:1.0-groovy-2.4'
|
||||||
dependency 'org.spockframework:spock-spring:1.0-groovy-2.4'
|
dependency 'org.spockframework:spock-spring:1.0-groovy-2.4'
|
||||||
@@ -28,27 +28,27 @@ dependencyManagement {
|
|||||||
dependency 'asm:asm:3.1'
|
dependency 'asm:asm:3.1'
|
||||||
dependency 'ch.qos.logback:logback-classic:1.2.3'
|
dependency 'ch.qos.logback:logback-classic:1.2.3'
|
||||||
dependency 'ch.qos.logback:logback-core:1.2.3'
|
dependency 'ch.qos.logback:logback-core:1.2.3'
|
||||||
dependency 'com.fasterxml.jackson.core:jackson-annotations:2.9.8'
|
dependency 'com.fasterxml.jackson.core:jackson-annotations:2.9.10'
|
||||||
dependency 'com.fasterxml.jackson.core:jackson-core:2.9.8'
|
dependency 'com.fasterxml.jackson.core:jackson-core:2.9.10'
|
||||||
dependency 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
|
dependency 'com.fasterxml.jackson.core:jackson-databind:2.9.10.2'
|
||||||
dependency 'com.fasterxml:classmate:1.3.4'
|
dependency 'com.fasterxml:classmate:1.3.4'
|
||||||
dependency 'com.github.stephenc.jcip:jcip-annotations:1.0-1'
|
dependency 'com.github.stephenc.jcip:jcip-annotations:1.0-1'
|
||||||
dependency 'com.google.appengine:appengine-api-1.0-sdk:1.9.64'
|
dependency 'com.google.appengine:appengine-api-1.0-sdk:1.9.76'
|
||||||
dependency 'com.google.appengine:appengine-api-labs:1.9.64'
|
dependency 'com.google.appengine:appengine-api-labs:1.9.76'
|
||||||
dependency 'com.google.appengine:appengine-api-stubs:1.9.64'
|
dependency 'com.google.appengine:appengine-api-stubs:1.9.76'
|
||||||
dependency 'com.google.appengine:appengine-testing:1.9.64'
|
dependency 'com.google.appengine:appengine-testing:1.9.76'
|
||||||
dependency 'com.google.appengine:appengine:1.9.63'
|
dependency 'com.google.appengine:appengine:1.9.76'
|
||||||
dependency 'com.google.code.gson:gson:2.8.2'
|
dependency 'com.google.code.gson:gson:2.8.2'
|
||||||
dependency 'com.google.guava:guava:20.0'
|
dependency 'com.google.guava:guava:20.0'
|
||||||
dependency 'com.google.inject:guice:3.0'
|
dependency 'com.google.inject:guice:3.0'
|
||||||
dependency 'com.nimbusds:lang-tag:1.4.3'
|
dependency 'com.nimbusds:lang-tag:1.4.3'
|
||||||
dependency 'com.nimbusds:nimbus-jose-jwt:5.14'
|
dependency 'com.nimbusds:nimbus-jose-jwt:5.14'
|
||||||
dependency 'com.nimbusds:oauth2-oidc-sdk:5.64.4'
|
dependency 'com.nimbusds:oauth2-oidc-sdk:5.64.4'
|
||||||
dependency 'com.squareup.okhttp3:okhttp:3.12.2'
|
dependency 'com.squareup.okhttp3:okhttp:3.12.10'
|
||||||
dependency 'com.squareup.okio:okio:1.13.0'
|
dependency 'com.squareup.okio:okio:1.13.0'
|
||||||
dependency 'com.sun.xml.bind:jaxb-core:2.3.0.1'
|
dependency 'com.sun.xml.bind:jaxb-core:2.3.0.1'
|
||||||
dependency 'com.sun.xml.bind:jaxb-impl:2.3.0.1'
|
dependency 'com.sun.xml.bind:jaxb-impl:2.3.0.1'
|
||||||
dependency 'com.unboundid:unboundid-ldapsdk:4.0.10'
|
dependency 'com.unboundid:unboundid-ldapsdk:4.0.14'
|
||||||
dependency 'com.vaadin.external.google:android-json:0.0.20131108.vaadin1'
|
dependency 'com.vaadin.external.google:android-json:0.0.20131108.vaadin1'
|
||||||
dependency 'commons-cli:commons-cli:1.4'
|
dependency 'commons-cli:commons-cli:1.4'
|
||||||
dependency 'commons-codec:commons-codec:1.12'
|
dependency 'commons-codec:commons-codec:1.12'
|
||||||
@@ -115,7 +115,7 @@ dependencyManagement {
|
|||||||
dependency 'org.apache.directory.shared:shared-cursor:0.9.15'
|
dependency 'org.apache.directory.shared:shared-cursor:0.9.15'
|
||||||
dependency 'org.apache.directory.shared:shared-ldap-constants:0.9.15'
|
dependency 'org.apache.directory.shared:shared-ldap-constants:0.9.15'
|
||||||
dependency 'org.apache.directory.shared:shared-ldap:0.9.15'
|
dependency 'org.apache.directory.shared:shared-ldap:0.9.15'
|
||||||
dependency 'org.apache.httpcomponents:httpclient:4.5.7'
|
dependency 'org.apache.httpcomponents:httpclient:4.5.12'
|
||||||
dependency 'org.apache.httpcomponents:httpcore:4.4.8'
|
dependency 'org.apache.httpcomponents:httpcore:4.4.8'
|
||||||
dependency 'org.apache.httpcomponents:httpmime:4.5.3'
|
dependency 'org.apache.httpcomponents:httpmime:4.5.3'
|
||||||
dependency 'org.apache.mina:mina-core:2.0.0-M6'
|
dependency 'org.apache.mina:mina-core:2.0.0-M6'
|
||||||
@@ -128,16 +128,16 @@ dependencyManagement {
|
|||||||
dependency 'org.apache.tomcat.embed:tomcat-embed-logging-log4j:8.0.44'
|
dependency 'org.apache.tomcat.embed:tomcat-embed-logging-log4j:8.0.44'
|
||||||
dependency 'org.apache.tomcat.embed:tomcat-embed-websocket:8.5.23'
|
dependency 'org.apache.tomcat.embed:tomcat-embed-websocket:8.5.23'
|
||||||
dependency 'org.apache.tomcat:tomcat-annotations-api:8.5.23'
|
dependency 'org.apache.tomcat:tomcat-annotations-api:8.5.23'
|
||||||
dependency 'org.aspectj:aspectjrt:1.9.2'
|
dependency 'org.aspectj:aspectjrt:1.9.5'
|
||||||
dependency 'org.aspectj:aspectjtools:1.9.2'
|
dependency 'org.aspectj:aspectjtools:1.9.5'
|
||||||
dependency 'org.aspectj:aspectjweaver:1.9.2'
|
dependency 'org.aspectj:aspectjweaver:1.9.5'
|
||||||
dependency 'org.assertj:assertj-core:3.11.1'
|
dependency 'org.assertj:assertj-core:3.11.1'
|
||||||
dependency 'org.attoparser:attoparser:2.0.4.RELEASE'
|
dependency 'org.attoparser:attoparser:2.0.4.RELEASE'
|
||||||
dependency 'org.bouncycastle:bcpkix-jdk15on:1.61'
|
dependency 'org.bouncycastle:bcpkix-jdk15on:1.64'
|
||||||
dependency 'org.bouncycastle:bcprov-jdk15on:1.61'
|
dependency 'org.bouncycastle:bcprov-jdk15on:1.64'
|
||||||
dependency 'org.codehaus.groovy:groovy-all:2.4.14'
|
dependency 'org.codehaus.groovy:groovy-all:2.4.19'
|
||||||
dependency 'org.codehaus.groovy:groovy-json:2.4.14'
|
dependency 'org.codehaus.groovy:groovy-json:2.4.19'
|
||||||
dependency 'org.codehaus.groovy:groovy:2.4.14'
|
dependency 'org.codehaus.groovy:groovy:2.4.19'
|
||||||
dependency 'org.eclipse.jdt:ecj:3.12.3'
|
dependency 'org.eclipse.jdt:ecj:3.12.3'
|
||||||
dependency 'org.eclipse.jetty.websocket:websocket-api:9.4.7.v20170914'
|
dependency 'org.eclipse.jetty.websocket:websocket-api:9.4.7.v20170914'
|
||||||
dependency 'org.eclipse.jetty.websocket:websocket-client:9.4.7.v20170914'
|
dependency 'org.eclipse.jetty.websocket:websocket-client:9.4.7.v20170914'
|
||||||
@@ -158,9 +158,9 @@ dependencyManagement {
|
|||||||
dependency 'org.hamcrest:hamcrest-core:1.3'
|
dependency 'org.hamcrest:hamcrest-core:1.3'
|
||||||
dependency 'org.hibernate.common:hibernate-commons-annotations:5.0.1.Final'
|
dependency 'org.hibernate.common:hibernate-commons-annotations:5.0.1.Final'
|
||||||
dependency 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final'
|
dependency 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final'
|
||||||
dependency 'org.hibernate:hibernate-core:5.2.17.Final'
|
dependency 'org.hibernate:hibernate-core:5.2.18.Final'
|
||||||
dependency 'org.hibernate:hibernate-entitymanager:5.2.18.Final'
|
dependency 'org.hibernate:hibernate-entitymanager:5.2.18.Final'
|
||||||
dependency 'org.hibernate:hibernate-validator:6.0.16.Final'
|
dependency 'org.hibernate:hibernate-validator:6.0.19.Final'
|
||||||
dependency 'org.hsqldb:hsqldb:2.4.1'
|
dependency 'org.hsqldb:hsqldb:2.4.1'
|
||||||
dependency 'org.jasig.cas.client:cas-client-core:3.5.1'
|
dependency 'org.jasig.cas.client:cas-client-core:3.5.1'
|
||||||
dependency 'org.javassist:javassist:3.22.0-CR2'
|
dependency 'org.javassist:javassist:3.22.0-CR2'
|
||||||
@@ -171,17 +171,17 @@ dependencyManagement {
|
|||||||
dependency 'org.objenesis:objenesis:2.6'
|
dependency 'org.objenesis:objenesis:2.6'
|
||||||
dependency 'org.openid4java:openid4java-nodeps:0.9.6'
|
dependency 'org.openid4java:openid4java-nodeps:0.9.6'
|
||||||
dependency 'org.ow2.asm:asm:6.0'
|
dependency 'org.ow2.asm:asm:6.0'
|
||||||
dependency 'org.reactivestreams:reactive-streams:1.0.1'
|
dependency 'org.reactivestreams:reactive-streams:1.0.3'
|
||||||
dependency 'org.seleniumhq.selenium:htmlunit-driver:2.33.3'
|
dependency 'org.seleniumhq.selenium:htmlunit-driver:2.33.3'
|
||||||
dependency 'org.seleniumhq.selenium:selenium-api:3.141.59'
|
dependency 'org.seleniumhq.selenium:selenium-api:3.141.59'
|
||||||
dependency 'org.seleniumhq.selenium:selenium-java:3.141.59'
|
dependency 'org.seleniumhq.selenium:selenium-java:3.141.59'
|
||||||
dependency 'org.seleniumhq.selenium:selenium-support:3.141.59'
|
dependency 'org.seleniumhq.selenium:selenium-support:3.141.59'
|
||||||
dependency 'org.skyscreamer:jsonassert:1.5.0'
|
dependency 'org.skyscreamer:jsonassert:1.5.0'
|
||||||
dependency 'org.slf4j:jcl-over-slf4j:1.7.26'
|
dependency 'org.slf4j:jcl-over-slf4j:1.7.30'
|
||||||
dependency 'org.slf4j:jul-to-slf4j:1.7.26'
|
dependency 'org.slf4j:jul-to-slf4j:1.7.30'
|
||||||
dependency 'org.slf4j:log4j-over-slf4j:1.7.26'
|
dependency 'org.slf4j:log4j-over-slf4j:1.7.30'
|
||||||
dependency 'org.slf4j:slf4j-api:1.7.26'
|
dependency 'org.slf4j:slf4j-api:1.7.30'
|
||||||
dependency 'org.slf4j:slf4j-nop:1.7.26'
|
dependency 'org.slf4j:slf4j-nop:1.7.30'
|
||||||
dependency 'org.sonatype.sisu.inject:cglib:2.2.1-v20090111'
|
dependency 'org.sonatype.sisu.inject:cglib:2.2.1-v20090111'
|
||||||
dependency 'org.springframework.ldap:spring-ldap-core:2.3.2.RELEASE'
|
dependency 'org.springframework.ldap:spring-ldap-core:2.3.2.RELEASE'
|
||||||
dependency 'org.thymeleaf:thymeleaf-spring5:3.0.11.RELEASE'
|
dependency 'org.thymeleaf:thymeleaf-spring5:3.0.11.RELEASE'
|
||||||
|
|||||||
+144
@@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.ldap.server;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.ldap.core.ContextSource;
|
||||||
|
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||||
|
import org.springframework.security.ldap.SpringSecurityLdapTemplate;
|
||||||
|
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link UnboundIdContainer}, specifically relating to LDIF file detection.
|
||||||
|
*
|
||||||
|
* @author Eleftheria Stein
|
||||||
|
*/
|
||||||
|
public class UnboundIdContainerLdifTests {
|
||||||
|
|
||||||
|
AnnotationConfigApplicationContext appCtx;
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void closeAppContext() {
|
||||||
|
if (appCtx != null) {
|
||||||
|
appCtx.close();
|
||||||
|
appCtx = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void unboundIdContainerWhenCustomLdifNameThenLdifLoaded() {
|
||||||
|
appCtx = new AnnotationConfigApplicationContext(CustomLdifConfig.class);
|
||||||
|
|
||||||
|
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) appCtx
|
||||||
|
.getBean(ContextSource.class);
|
||||||
|
|
||||||
|
SpringSecurityLdapTemplate template = new SpringSecurityLdapTemplate(contextSource);
|
||||||
|
assertThat(template.compare("uid=bob,ou=people", "uid", "bob")).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class CustomLdifConfig {
|
||||||
|
private UnboundIdContainer container = new UnboundIdContainer("dc=springframework,dc=org",
|
||||||
|
"classpath:test-server.ldif");
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
UnboundIdContainer ldapContainer() {
|
||||||
|
this.container.setPort(0);
|
||||||
|
return this.container;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
ContextSource contextSource(UnboundIdContainer container) {
|
||||||
|
return new DefaultSpringSecurityContextSource("ldap://127.0.0.1:"
|
||||||
|
+ container.getPort() + "/dc=springframework,dc=org");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
void shutdown() {
|
||||||
|
this.container.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void unboundIdContainerWhenWildcardLdifNameThenLdifLoaded() {
|
||||||
|
appCtx = new AnnotationConfigApplicationContext(WildcardLdifConfig.class);
|
||||||
|
|
||||||
|
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) appCtx
|
||||||
|
.getBean(ContextSource.class);
|
||||||
|
|
||||||
|
SpringSecurityLdapTemplate template = new SpringSecurityLdapTemplate(contextSource);
|
||||||
|
assertThat(template.compare("uid=bob,ou=people", "uid", "bob")).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class WildcardLdifConfig {
|
||||||
|
private UnboundIdContainer container = new UnboundIdContainer("dc=springframework,dc=org",
|
||||||
|
"classpath*:test-server.ldif");
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
UnboundIdContainer ldapContainer() {
|
||||||
|
this.container.setPort(0);
|
||||||
|
return this.container;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
ContextSource contextSource(UnboundIdContainer container) {
|
||||||
|
return new DefaultSpringSecurityContextSource("ldap://127.0.0.1:"
|
||||||
|
+ container.getPort() + "/dc=springframework,dc=org");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
void shutdown() {
|
||||||
|
this.container.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void unboundIdContainerWhenMalformedLdifThenException() {
|
||||||
|
try {
|
||||||
|
appCtx = new AnnotationConfigApplicationContext(MalformedLdifConfig.class);
|
||||||
|
failBecauseExceptionWasNotThrown(IllegalStateException.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertThat(e.getCause()).isInstanceOf(IllegalStateException.class);
|
||||||
|
assertThat(e.getMessage()).contains("Unable to load LDIF classpath:test-server-malformed.txt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class MalformedLdifConfig {
|
||||||
|
private UnboundIdContainer container = new UnboundIdContainer("dc=springframework,dc=org",
|
||||||
|
"classpath:test-server-malformed.txt");
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
UnboundIdContainer ldapContainer() {
|
||||||
|
this.container.setPort(0);
|
||||||
|
return this.container;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
void shutdown() {
|
||||||
|
this.container.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
dn: ou=groups,dc=springframework,dc=org
|
||||||
|
objectclass: top
|
||||||
|
objectclass: organizationalUnit
|
||||||
|
ou: groups
|
||||||
|
|
||||||
|
dn ou=subgroups,ou=groups,dc=springframework,dc=org
|
||||||
|
objectclass: top
|
||||||
|
objectclass: organizationalUnit
|
||||||
|
ou: subgroups
|
||||||
@@ -114,10 +114,10 @@ public class UnboundIdContainer implements InitializingBean, DisposableBean, Lif
|
|||||||
|
|
||||||
private void importLdif(InMemoryDirectoryServer directoryServer) {
|
private void importLdif(InMemoryDirectoryServer directoryServer) {
|
||||||
if (StringUtils.hasText(this.ldif)) {
|
if (StringUtils.hasText(this.ldif)) {
|
||||||
Resource resource = this.context.getResource(this.ldif);
|
|
||||||
try {
|
try {
|
||||||
if (resource.exists()) {
|
Resource[] resources = this.context.getResources(this.ldif);
|
||||||
try (InputStream inputStream = resource.getInputStream()) {
|
if (resources.length > 0 && resources[0].exists()) {
|
||||||
|
try (InputStream inputStream = resources[0].getInputStream()) {
|
||||||
directoryServer.importFromLDIF(false, new LDIFReader(inputStream));
|
directoryServer.importFromLDIF(false, new LDIFReader(inputStream));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"]
|
||||||
Executable
+4
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
VERSION=$1
|
||||||
|
until http -h --check-status --ignore-stdin https://repo1.maven.org/maven2/org/springframework/security/spring-security-core/$VERSION/; do sleep 10; clear; done; spd-say "It is now uploaded"
|
||||||
+1
-1
@@ -43,7 +43,7 @@ final class WithMockUserSecurityContextFactory implements
|
|||||||
.username() : withUser.value();
|
.username() : withUser.value();
|
||||||
if (username == null) {
|
if (username == null) {
|
||||||
throw new IllegalArgumentException(withUser
|
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<>();
|
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
|
||||||
|
|||||||
+1
-1
@@ -563,6 +563,6 @@ public class SwitchUserFilter extends GenericFilterBean
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static RequestMatcher createMatcher(String pattern) {
|
private static RequestMatcher createMatcher(String pattern) {
|
||||||
return new AntPathRequestMatcher(pattern, null, true, new UrlPathHelper());
|
return new AntPathRequestMatcher(pattern, "POST", true, new UrlPathHelper());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-8
@@ -15,14 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.security.web.server.header;
|
package org.springframework.security.web.server.header;
|
||||||
|
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
|
||||||
|
|
||||||
import reactor.core.publisher.Mono;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combines multiple {@link ServerHttpHeadersWriter} instances into a single instance.
|
* Combines multiple {@link ServerHttpHeadersWriter} instances into a single instance.
|
||||||
@@ -43,8 +41,9 @@ public class CompositeServerHttpHeadersWriter implements ServerHttpHeadersWriter
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Void> writeHttpHeaders(ServerWebExchange exchange) {
|
public Mono<Void> writeHttpHeaders(ServerWebExchange exchange) {
|
||||||
Stream<Mono<Void>> results = writers.stream().map( writer -> writer.writeHttpHeaders(exchange));
|
return Flux.fromIterable(this.writers)
|
||||||
return Mono.when(results.collect(Collectors.toList()));
|
.concatMap(w -> w.writeHttpHeaders(exchange))
|
||||||
|
.then();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+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.SecurityContext;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
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.security.web.authentication.logout.LogoutHandler;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
@@ -82,7 +81,7 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory {
|
|||||||
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
|
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
|
||||||
private AuthenticationEntryPoint authenticationEntryPoint;
|
private AuthenticationEntryPoint authenticationEntryPoint;
|
||||||
private AuthenticationManager authenticationManager;
|
private AuthenticationManager authenticationManager;
|
||||||
private LogoutHandler logoutHandler;
|
private List<LogoutHandler> logoutHandlers;
|
||||||
|
|
||||||
HttpServlet3RequestFactory(String rolePrefix) {
|
HttpServlet3RequestFactory(String rolePrefix) {
|
||||||
this.rolePrefix = rolePrefix;
|
this.rolePrefix = rolePrefix;
|
||||||
@@ -146,7 +145,7 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory {
|
|||||||
* {@link HttpServletRequest#logout()}.
|
* {@link HttpServletRequest#logout()}.
|
||||||
*/
|
*/
|
||||||
public void setLogoutHandlers(List<LogoutHandler> logoutHandlers) {
|
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
|
@Override
|
||||||
public void logout() throws ServletException {
|
public void logout() throws ServletException {
|
||||||
LogoutHandler handler = HttpServlet3RequestFactory.this.logoutHandler;
|
List<LogoutHandler> handlers = HttpServlet3RequestFactory.this.logoutHandlers;
|
||||||
if (handler == null) {
|
if (CollectionUtils.isEmpty(handlers)) {
|
||||||
HttpServlet3RequestFactory.this.logger.debug(
|
HttpServlet3RequestFactory.this.logger.debug(
|
||||||
"logoutHandlers is null, so allowing original HttpServletRequest to handle logout");
|
"logoutHandlers is null, so allowing original HttpServletRequest to handle logout");
|
||||||
super.logout();
|
super.logout();
|
||||||
@@ -255,7 +254,9 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory {
|
|||||||
}
|
}
|
||||||
Authentication authentication = SecurityContextHolder.getContext()
|
Authentication authentication = SecurityContextHolder.getContext()
|
||||||
.getAuthentication();
|
.getAuthentication();
|
||||||
handler.logout(this, this.response, authentication);
|
for (LogoutHandler handler : handlers) {
|
||||||
|
handler.logout(this, this.response, authentication);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAuthenticated() {
|
private boolean isAuthenticated() {
|
||||||
|
|||||||
+1
-1
@@ -107,7 +107,7 @@ public final class AntPathRequestMatcher
|
|||||||
*
|
*
|
||||||
* @param pattern the ant pattern to use for matching
|
* @param pattern the ant pattern to use for matching
|
||||||
* @param httpMethod the HTTP method. The {@code matches} method will return false if
|
* @param httpMethod the HTTP method. The {@code matches} method will return false if
|
||||||
* the incoming request doesn't doesn't have the same method.
|
* the incoming request doesn't have the same method.
|
||||||
* @param caseSensitive true if the matcher should consider case, else false
|
* @param caseSensitive true if the matcher should consider case, else false
|
||||||
* @param urlPathHelper if non-null, will be used for extracting the path from the HttpServletRequest
|
* @param urlPathHelper if non-null, will be used for extracting the path from the HttpServletRequest
|
||||||
*/
|
*/
|
||||||
|
|||||||
+42
-5
@@ -16,11 +16,17 @@
|
|||||||
|
|
||||||
package org.springframework.security.web.authentication.switchuser;
|
package org.springframework.security.web.authentication.switchuser;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.*;
|
import java.util.ArrayList;
|
||||||
import static org.mockito.Mockito.*;
|
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.junit.rules.ExpectedException;
|
||||||
|
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockHttpServletResponse;
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
import org.springframework.security.authentication.AccountExpiredException;
|
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.authentication.SimpleUrlAuthenticationSuccessHandler;
|
||||||
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import java.util.*;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests
|
* Tests
|
||||||
@@ -75,6 +83,7 @@ public class SwitchUserFilterTests {
|
|||||||
request.setScheme("http");
|
request.setScheme("http");
|
||||||
request.setServerName("localhost");
|
request.setServerName("localhost");
|
||||||
request.setRequestURI("/login/impersonate");
|
request.setRequestURI("/login/impersonate");
|
||||||
|
request.setMethod("POST");
|
||||||
|
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
@@ -125,6 +134,20 @@ public class SwitchUserFilterTests {
|
|||||||
assertThat(filter.requiresExitUser(request)).isFalse();
|
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
|
@Test
|
||||||
public void requiresExitUserWhenMatcherThenWorks() {
|
public void requiresExitUserWhenMatcherThenWorks() {
|
||||||
SwitchUserFilter filter = new SwitchUserFilter();
|
SwitchUserFilter filter = new SwitchUserFilter();
|
||||||
@@ -159,6 +182,20 @@ public class SwitchUserFilterTests {
|
|||||||
assertThat(filter.requiresSwitchUser(request)).isFalse();
|
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
|
@Test
|
||||||
public void requiresSwitchUserWhenMatcherThenWorks() {
|
public void requiresSwitchUserWhenMatcherThenWorks() {
|
||||||
SwitchUserFilter filter = new SwitchUserFilter();
|
SwitchUserFilter filter = new SwitchUserFilter();
|
||||||
|
|||||||
+32
-10
@@ -15,11 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.security.web.server.header;
|
package org.springframework.security.web.server.header;
|
||||||
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -28,10 +23,19 @@ import org.mockito.junit.MockitoJUnitRunner;
|
|||||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||||
import org.springframework.mock.web.server.MockServerWebExchange;
|
import org.springframework.mock.web.server.MockServerWebExchange;
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.test.StepVerifier;
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
@@ -55,7 +59,6 @@ public class CompositeServerHttpHeadersWriterTests {
|
|||||||
@Test
|
@Test
|
||||||
public void writeHttpHeadersWhenErrorNoErrorThenError() {
|
public void writeHttpHeadersWhenErrorNoErrorThenError() {
|
||||||
when(writer1.writeHttpHeaders(exchange)).thenReturn(Mono.error(new RuntimeException()));
|
when(writer1.writeHttpHeaders(exchange)).thenReturn(Mono.error(new RuntimeException()));
|
||||||
when(writer2.writeHttpHeaders(exchange)).thenReturn(Mono.empty());
|
|
||||||
|
|
||||||
Mono<Void> result = writer.writeHttpHeaders(exchange);
|
Mono<Void> result = writer.writeHttpHeaders(exchange);
|
||||||
|
|
||||||
@@ -64,13 +67,11 @@ public class CompositeServerHttpHeadersWriterTests {
|
|||||||
.verify();
|
.verify();
|
||||||
|
|
||||||
verify(writer1).writeHttpHeaders(exchange);
|
verify(writer1).writeHttpHeaders(exchange);
|
||||||
verify(writer2).writeHttpHeaders(exchange);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void writeHttpHeadersWhenErrorErrorThenError() {
|
public void writeHttpHeadersWhenErrorErrorThenError() {
|
||||||
when(writer1.writeHttpHeaders(exchange)).thenReturn(Mono.error(new RuntimeException()));
|
when(writer1.writeHttpHeaders(exchange)).thenReturn(Mono.error(new RuntimeException()));
|
||||||
when(writer2.writeHttpHeaders(exchange)).thenReturn(Mono.error(new RuntimeException()));
|
|
||||||
|
|
||||||
Mono<Void> result = writer.writeHttpHeaders(exchange);
|
Mono<Void> result = writer.writeHttpHeaders(exchange);
|
||||||
|
|
||||||
@@ -79,7 +80,6 @@ public class CompositeServerHttpHeadersWriterTests {
|
|||||||
.verify();
|
.verify();
|
||||||
|
|
||||||
verify(writer1).writeHttpHeaders(exchange);
|
verify(writer1).writeHttpHeaders(exchange);
|
||||||
verify(writer2).writeHttpHeaders(exchange);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -96,4 +96,26 @@ public class CompositeServerHttpHeadersWriterTests {
|
|||||||
verify(writer1).writeHttpHeaders(exchange);
|
verify(writer1).writeHttpHeaders(exchange);
|
||||||
verify(writer2).writeHttpHeaders(exchange);
|
verify(writer2).writeHttpHeaders(exchange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void writeHttpHeadersSequential() throws Exception {
|
||||||
|
AtomicBoolean slowDone = new AtomicBoolean();
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
ServerHttpHeadersWriter slow = exchange ->
|
||||||
|
Mono.delay(Duration.ofMillis(100))
|
||||||
|
.doOnSuccess(__ -> slowDone.set(true))
|
||||||
|
.then();
|
||||||
|
ServerHttpHeadersWriter second = exchange ->
|
||||||
|
Mono.fromRunnable(() -> {
|
||||||
|
latch.countDown();
|
||||||
|
assertThat(slowDone.get())
|
||||||
|
.describedAs("ServerLogoutHandler should be executed sequentially")
|
||||||
|
.isTrue();
|
||||||
|
});
|
||||||
|
CompositeServerHttpHeadersWriter writer = new CompositeServerHttpHeadersWriter(slow, second);
|
||||||
|
|
||||||
|
writer.writeHttpHeaders(this.exchange).block();
|
||||||
|
|
||||||
|
assertThat(latch.await(3, TimeUnit.SECONDS)).isTrue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user