1
0
mirror of synced 2026-08-06 10:18:52 +00:00

Compare commits

..

78 Commits

Author SHA1 Message Date
Josh Cummings 6747e1330f Release 4.2.20.RELEASE 2020-12-09 10:32:52 -07:00
Josh Cummings 932b084923 Update to Spring LDAP 2.3.3
Closes gh-9274
2020-12-09 10:32:27 -07:00
Josh Cummings 66ca1d93f2 Update to GAE 1.9.83
Closes gh-9273
2020-12-09 10:32:22 -07:00
Josh Cummings 8fb27d9329 Update to Spring Framework 4.3.30
Closes gh-9272
2020-12-09 10:32:14 -07:00
Rob Winch 14e3e0f0b7 Use artifactoryUsername/Password 2020-11-17 09:26:50 -06:00
Rob Winch 76f33ae6e6 Next Developement Version 2020-10-07 14:19:08 -05:00
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
Rob Winch e7b43f14c8 Release 4.2.14.RELEASE 2020-02-06 07:27:15 -06:00
Rob Winch 0629ecbb00 uploadArchives customizePom 2020-02-05 22:51:04 -06:00
Rob Winch 93557505c0 Apply signing plugin 2020-02-05 22:51:04 -06:00
Rob Winch 8facc74da2 gradle-nexus-staging-plugin:0.10.0
Avoid NoClassDefFoundError: org/gradle/api/provider/Property
2020-02-05 22:51:04 -06:00
Rob Winch c0f16908a1 Revert "Release 4.2.14.RELEASE"
This reverts commit 8be0691e8f.

The release failed and we need to apply some fixes.
2020-02-05 22:50:44 -06:00
Rob Winch 8be0691e8f Release 4.2.14.RELEASE 2020-02-05 21:30:27 -06:00
Rob Winch e794dcd203 Update to Thymeleaf 3.0.11.RELEASE
Fixes gh-7948
2020-02-05 21:22:41 -06:00
Rob Winch dbaeb2fdd9 Update to Spring Boot 1.5.22.RELEASE
Fixes gh-7947
2020-02-05 21:22:25 -06:00
Rob Winch ae2809634f Update to Spring Session 1.3.5.RELEASE
Fixes gh-7946
2020-02-05 21:22:21 -06:00
Rob Winch 8fd5cca501 Update to Spring Data Redis 1.8.23.RELEASE
Fixes gh-7945
2020-02-05 21:22:17 -06:00
Rob Winch a867f92416 Update to Spring Data JPA 1.11.23.RELEASE
Fixes gh-7944
2020-02-05 21:21:57 -06:00
Rob Winch a1a61d3259 Update to Spring Data Commons 1.13.23.RELEASE
Fixes gh-7943
2020-02-05 21:21:50 -06:00
Rob Winch fbf3c7d083 Update to CGLIB 3.2.12
Fixes gh-7942
2020-02-05 21:21:42 -06:00
Rob Winch 76a869995e Update to Spring Framework 4.3.26.RELEASE
Fixes gh-7941
2020-02-05 21:21:42 -06:00
Rob Winch 702ec17a5f Add Jenkinsfile
Fixes gh-7940
2020-02-05 21:21:18 -06:00
Rob Winch ba4953b057 Add Deploy Artifacts Support
Fixes gh-7939
2020-02-05 21:21:18 -06:00
Filip Hanik b87ea1373d Build using openjdk8
Fixes gh-7169

[closes #7169]
2020-01-13 10:35:21 -07:00
Josh Cummings 7754a11a4a Add file extension to wait-for-done 2019-06-19 13:54:19 -06:00
Josh Cummings 409ef7d5e1 Release Scripts
Added a script for polling Maven Central to notify when release is
uploaded.
2019-06-19 13:40:15 -06:00
Josh Cummings d01b6fc6b1 Release Scripts
Added scripts for pushing released artifacts to the appropriate
repositories.
2019-06-19 13:32:25 -06:00
Spring Buildmaster 0994a64830 Next development version 2019-06-19 18:35:05 +00:00
54 changed files with 718 additions and 122 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:
- oraclejdk8
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
Vendored
+109
View File
@@ -0,0 +1,109 @@
def projectProperties = [
[$class: 'BuildDiscarderProperty',
strategy: [$class: 'LogRotator', numToKeepStr: '5']],
pipelineTriggers([cron('@daily')])
]
properties(projectProperties)
def SUCCESS = hudson.model.Result.SUCCESS.toString()
currentBuild.result = SUCCESS
def ARTIFACTORY_CREDENTIALS = usernamePassword(credentialsId: '02bd1690-b54f-4c9f-819d-a77cb7a9822c', usernameVariable: 'ARTIFACTORY_USERNAME', passwordVariable: 'ARTIFACTORY_PASSWORD')
try {
parallel check: {
stage('Check') {
node {
checkout scm
sh "git clean -dfx"
try {
withCredentials([ARTIFACTORY_CREDENTIALS]) {
withEnv(["JAVA_HOME=${ tool 'jdk8' }"]) {
sh "./gradlew test -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --refresh-dependencies --no-daemon --stacktrace"
}
}
} catch(Exception e) {
currentBuild.result = 'FAILED: check'
throw e
} finally {
junit '**/build/test-results/*/*.xml'
}
}
}
}
if(currentBuild.result == 'SUCCESS') {
parallel artifacts: {
stage('Deploy Artifacts') {
node {
checkout scm
sh "git clean -dfx"
withCredentials([file(credentialsId: 'spring-signing-secring.gpg', variable: 'SIGNING_KEYRING_FILE')]) {
withCredentials([string(credentialsId: 'spring-gpg-passphrase', variable: 'SIGNING_PASSWORD')]) {
withCredentials([usernamePassword(credentialsId: 'oss-token', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USERNAME')]) {
withCredentials([ARTIFACTORY_CREDENTIALS]) {
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"
}
}
}
}
}
}
}
},
docs: {
stage('Deploy Docs') {
node {
checkout scm
sh "git clean -dfx"
withCredentials([file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')]) {
withEnv(["JAVA_HOME=${ tool 'jdk8' }"]) {
sh "./gradlew deployDocs -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --refresh-dependencies --no-daemon --stacktrace"
}
}
}
}
},
schema: {
stage('Deploy Schema') {
node {
checkout scm
sh "git clean -dfx"
withCredentials([file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')]) {
withEnv(["JAVA_HOME=${ tool 'jdk8' }"]) {
sh "./gradlew deploySchema -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --refresh-dependencies --no-daemon --stacktrace"
}
}
}
}
}
}
} catch(Exception e) {
currentBuild.result = 'FAILED: deploys'
throw e
} finally {
def buildStatus = currentBuild.result
def buildNotSuccess = !SUCCESS.equals(buildStatus)
def lastBuildNotSuccess = !SUCCESS.equals(currentBuild.previousBuild?.result)
if(buildNotSuccess || lastBuildNotSuccess) {
stage('Notifiy') {
node {
final def RECIPIENTS = [[$class: 'DevelopersRecipientProvider'], [$class: 'RequesterRecipientProvider']]
def subject = "${buildStatus}: Build ${env.JOB_NAME} ${env.BUILD_NUMBER} status is now ${buildStatus}"
def details = """The build status changed to ${buildStatus}. For details see ${env.BUILD_URL}"""
emailext (
subject: subject,
body: details,
recipientProviders: RECIPIENTS,
to: "$SPRING_SECURITY_TEAM_EMAILS"
)
}
}
}
}
-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
+3
View File
@@ -1,5 +1,8 @@
apply plugin: 'maven-bom'
apply from: "$rootDir/gradle/maven-deployment.gradle"
apply from: "$rootDir/gradle/artifactory.gradle"
apply from: "$rootDir/gradle/ossrh.gradle"
apply from: "$rootDir/gradle/deploy-artifacts.gradle"
generatePom.enabled = false
sonarqube.skipProject = true
+42 -9
View File
@@ -1,17 +1,27 @@
buildscript {
repositories {
maven { url "https://repo.spring.io/plugins-release" }
maven { url "https://repo.spring.io/plugins-snapshot" }
maven {
url = 'https://repo.spring.io/plugins-snapshot'
if (project.hasProperty('artifactoryUsername')) {
credentials {
username "$artifactoryUsername"
password "$artifactoryPassword"
}
}
}
}
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'
}
}
@@ -20,6 +30,7 @@ plugins {
}
apply plugin: 'base'
apply from: "$rootDir/gradle/finalize-deploy.gradle"
description = 'Spring Security'
@@ -30,8 +41,8 @@ allprojects {
ext.releaseBuild = version.endsWith('RELEASE')
ext.snapshotBuild = version.endsWith('SNAPSHOT')
ext.springVersion = '4.3.23.RELEASE'
ext.springLdapVersion = '2.3.2.RELEASE'
ext.springVersion = '4.3.30.RELEASE'
ext.springLdapVersion = '2.3.3.RELEASE'
group = 'org.springframework.security'
@@ -86,7 +97,6 @@ configure(allprojects - javaProjects) {
}
configure(subprojects - coreModuleProjects - project(':spring-security-samples-javaconfig-messages') - project(':spring-security-bom')) {
tasks.findByPath("artifactoryPublish")?.enabled = false
sonarqube {
skipProject = true
}
@@ -102,10 +112,13 @@ configure(javaProjects) {
}
apply from: "$rootDir/gradle/ide.gradle"
apply from: "$rootDir/gradle/release-checks.gradle"
apply from: "$rootDir/gradle/maven-deployment.gradle"
}
configure(coreModuleProjects) {
apply from: "$rootDir/gradle/maven-deployment.gradle"
apply from: "$rootDir/gradle/artifactory.gradle"
apply from: "$rootDir/gradle/ossrh.gradle"
apply from: "$rootDir/gradle/deploy-artifacts.gradle"
apply plugin: 'emma'
apply plugin: 'spring-io'
@@ -116,6 +129,9 @@ configure(coreModuleProjects) {
}
dependencyManagement {
imports {
mavenBom("org.springframework:spring-framework-bom:${springVersion}")
}
springIoTestRuntime {
imports {
mavenBom("io.spring.platform:platform-bom:${springIoVersion}") {
@@ -194,3 +210,20 @@ artifacts {
archives project(':docs').docsZip
archives project(':docs').schemaZip
}
if (project.hasProperty('artifactoryUsername')) {
allprojects { project ->
project.repositories { repos ->
all { repo ->
if (!repo.url.toString().startsWith("https://repo.spring.io/")) {
return;
}
repo.credentials {
username = artifactoryUsername
password = artifactoryPassword
}
}
}
}
}
@@ -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.23.RELEASE";
static final String MIN_SPRING_VERSION = "4.3.30.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");
}
}
+3
View File
@@ -1,5 +1,7 @@
// Docbook and Javadoc building and uploading tasks
apply plugin: 'base'
apply from: "$rootDir/gradle/deploy-docs.gradle"
apply from: "$rootDir/gradle/deploy-schema.gradle"
task docs {
dependsOn 'manual:reference', 'apidocs', 'guides:asciidoctor'
@@ -152,6 +154,7 @@ task schemaZip(type: Zip) {
}
assert xsdFile != null
into (shortName) {
duplicatesStrategy 'exclude'
from xsdFile.path
}
}
+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.13.RELEASE
version=4.2.20.RELEASE
+33
View File
@@ -0,0 +1,33 @@
apply plugin: "com.jfrog.artifactory"
def isSnapshot = version?.matches(/^.*[.-]BUILD-SNAPSHOT$/)
artifactory {
contextUrl = 'https://repo.spring.io'
publish {
repository {
repoKey = isSnapshot ? 'libs-snapshot-local' : 'libs-release-local'
if(project.hasProperty('artifactoryUsername')) {
username = artifactoryUsername
password = artifactoryPassword
}
}
}
}
artifactoryPublish {
publishConfigs 'archives'
publishIvy false
properties = [
'bintray.package': "${project.group}:spring-security",
'bintray.version': "${project.version}"
]
}
artifactory {
publish {
defaults {
publishConfigs('archives')
}
}
}
+11
View File
@@ -0,0 +1,11 @@
def isSnapshot = version?.matches(/^.*[.-]BUILD-SNAPSHOT$/)
task deployArtifacts {
group = 'Deploy tasks'
description = "Deploys the artifacts to either Artifactory or Maven Central"
if(isSnapshot) {
dependsOn "artifactoryPublish"
} else {
dependsOn "uploadArchives"
}
}
+46
View File
@@ -0,0 +1,46 @@
apply plugin: 'org.hidetake.ssh'
project.ssh.settings {
knownHosts = allowAnyHosts
}
project.remotes {
docs {
role 'docs'
host = 'docs.af.pivotal.io'
user = project.findProperty('deployDocsSshUsername')
if(project.hasProperty('deployDocsSshKeyPath')) {
identity = project.file(project.findProperty('deployDocsSshKeyPath'))
}
if(project.hasProperty('deployDocsSshPassphrase')) {
passphrase = project.findProperty('deployDocsSshPassphrase')
}
}
}
project.task('deployDocs') {
dependsOn 'docsZip'
doFirst {
project.ssh.run {
session(project.remotes.docs) {
def now = System.currentTimeMillis()
def name = project.rootProject.name
def version = project.rootProject.version
def tempPath = "/tmp/${name}-${now}-docs".replaceAll(' ', '_')
execute "mkdir -p $tempPath"
project.tasks.docsZip.outputs.each { o ->
put from: o.files, into: tempPath
}
execute "unzip $tempPath/*.zip -d $tempPath"
def extractPath = "/var/www/domains/springsource.org/www/htdocs/autorepo/docs/${name}/${version}/"
execute "rm -rf $extractPath"
execute "mkdir -p $extractPath"
execute "mv $tempPath/* $extractPath"
}
}
}
}
+50
View File
@@ -0,0 +1,50 @@
apply plugin: 'org.hidetake.ssh'
project.ssh.settings {
knownHosts = allowAnyHosts
}
project.remotes {
docs {
role 'docs'
host = 'docs.af.pivotal.io'
user = project.findProperty('deployDocsSshUsername')
if(project.hasProperty('deployDocsSshKeyPath')) {
identity = project.file(project.findProperty('deployDocsSshKeyPath'))
}
if(project.hasProperty('deployDocsSshPassphrase')) {
passphrase = project.findProperty('deployDocsSshPassphrase')
}
}
}
project.task('deploySchema') {
dependsOn 'schemaZip'
doFirst {
project.ssh.run {
session(project.remotes.docs) {
def now = System.currentTimeMillis()
def name = project.rootProject.name
def version = project.rootProject.version
def tempPath = "/tmp/${name}-${now}-schema".replaceAll(' ', '_')
execute "mkdir -p $tempPath"
project.tasks.schemaZip.outputs.each { o ->
println "Putting $o.files"
put from: o.files, into: tempPath
}
execute "unzip $tempPath/*.zip -d $tempPath"
def extractPath = "/var/www/domains/springsource.org/www/htdocs/autorepo/schema/${name}/${version}/"
execute "rm -rf $extractPath"
execute "mkdir -p $extractPath"
execute "rm -f $tempPath*.zip"
execute "rm -rf $extractPath*"
execute "mv $tempPath/* $extractPath"
}
}
}
}
+13
View File
@@ -0,0 +1,13 @@
def isSnapshot = version?.matches(/^.*[.-]BUILD-SNAPSHOT$/)
def isRelease = !isSnapshot
task finalizeDeployArtifacts {
}
if (isRelease && project.hasProperty("ossrhUsername")) {
project.ext.nexusUsername = project.ossrhUsername
project.ext.nexusPassword = project.ossrhPassword
project.getPluginManager().apply("io.codearte.nexus-staging")
finalizeDeployArtifacts.dependsOn project.tasks.closeAndReleaseRepository
project.nexusStaging.packageGroup = 'org.springframework'
}
+10 -10
View File
@@ -11,17 +11,17 @@ targetCompatibility = 1.6
ext.apacheDsVersion = '1.5.5'
ext.aspectjVersion = '1.8.14'
ext.casClientVersion = '3.4.1'
ext.cglibVersion = '3.2.10'
ext.cglibVersion = '3.2.12'
ext.commonsCodecVersion = '1.12'
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'
@@ -32,12 +32,12 @@ ext.seleniumVersion = '2.44.0'
ext.servletApiVersion = '3.1.0'
ext.slf4jVersion = '1.7.25'
ext.spockVersion = '0.7-groovy-2.0'
ext.springDataCommonsVersion = '1.13.20.RELEASE'
ext.springDataJpaVersion = '1.11.20.RELEASE'
ext.springDataRedisVersion = '1.8.20.RELEASE'
ext.springSessionVersion = '1.3.4.RELEASE'
ext.springBootVersion = '1.5.16.RELEASE'
ext.thymeleafVersion = '3.0.9.RELEASE'
ext.springDataCommonsVersion = '1.13.23.RELEASE'
ext.springDataJpaVersion = '1.11.23.RELEASE'
ext.springDataRedisVersion = '1.8.23.RELEASE'
ext.springSessionVersion = '1.3.5.RELEASE'
ext.springBootVersion = '1.5.22.RELEASE'
ext.thymeleafVersion = '3.0.11.RELEASE'
ext.jsonassertVersion = '1.4.0'
ext.validationApiVersion = '1.1.0.Final'
@@ -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 = [
+6 -13
View File
@@ -25,6 +25,12 @@ install {
}
}
uploadArchives {
repositories.mavenDeployer {
customizePom(pom, project)
}
}
def customizePom(pom, gradleProject) {
pom.whenConfigured { p ->
p.dependencies.findAll{ it.scope == "optional" }.each {
@@ -71,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
+46
View File
@@ -0,0 +1,46 @@
def isSnapshot = version?.matches(/^.*[.-]BUILD-SNAPSHOT$/)
def isRelease = !isSnapshot
if(project.hasProperty("signing.keyId") && isRelease) {
apply plugin: "signing"
sign(project)
}
if(project.hasProperty('ossrhUsername')) {
uploadArchives {
repositories {
mavenDeployer {
repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
authentication(userName: project.ossrhUsername, password: project.ossrhPassword)
}
snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
authentication(userName: project.ossrhUsername, password: project.ossrhPassword)
}
}
}
}
}
def sign(Project project) {
project.install {
repositories {
mavenDeployer {
beforeDeployment { MavenDeployment deployment -> project.signing.signPom(deployment) }
}
}
}
project.uploadArchives {
repositories {
mavenDeployer {
beforeDeployment { MavenDeployment deployment -> project.signing.signPom(deployment) }
}
}
}
project.signing {
required { project.gradle.taskGraph.hasTask("uploadArchives") }
sign project.configurations.archives
}
}
+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.83"
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) }
+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
BUILD_NUMBER=$1
ENCRYPTED_ARTIFACTORY_PWD=$2
export ARTIFACTORY_BUILD_API_URL=https://repo.spring.io/api/build/distribute/Spring%20Security%20-%204.2.x%20-%20Default%20Job/$BUILD_NUMBER
curl -i -u buildmaster:$ENCRYPTED_ARTIFACTORY_PWD -XPOST $ARTIFACTORY_BUILD_API_URL -H "Content-Type: application/json" -d '{"sourceRepos": ["libs-release-local"], "targetRepo": "spring-distributions"}'
@@ -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"]
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
RELEASE_VERSION=$1
BINTRAY_API_KEY=$2
SONATYPE_USER_TOKEN=$3
SONATYPE_USER_TOKEN_PWD=$4
curl -i -u spring-operator:$BINTRAY_API_KEY -XPOST "https://api.bintray.com/maven_central_sync/spring/jars/org.springframework.security/versions/$RELEASE_VERSION" -H "Content-Type: application/json" -d "{\"username\": \"$SONATYPE_USER_TOKEN\", \"password\": \"$SONATYPE_USER_TOKEN_PWD\"}"
+4
View File
@@ -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"
@@ -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");
}
}
}