Compare commits
109 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 783e426183 | |||
| ca6348800e | |||
| fb85ad6bd7 | |||
| dcef3d6ebb | |||
| 89763a5b73 | |||
| 9d19b7337e | |||
| fda0220fad | |||
| 9141a8a7c0 | |||
| 406e1e6951 | |||
| 2deb1cda9f | |||
| dbda7e35a4 | |||
| 335a01577a | |||
| 3624ba5b4e | |||
| a34bf01754 | |||
| 30132892a0 | |||
| 6db418f47b | |||
| 6c286696b4 | |||
| 337317a060 | |||
| 554768f1e4 | |||
| 6428cb411e | |||
| 4cb77e5386 | |||
| 256d14ede0 | |||
| d09fb5b500 | |||
| fd244eb95c | |||
| 32751a2ce7 | |||
| eb6bd9bea9 | |||
| 5dee8534cd | |||
| 489ffcfce5 | |||
| 6c0ecea494 | |||
| ac6a86fb5f | |||
| ae17cc255b | |||
| e5eda24054 | |||
| 915de03f42 | |||
| 6aa7f05579 | |||
| 545339c663 | |||
| 4476df93e9 | |||
| 336e247e70 | |||
| 435e389609 | |||
| e5ceeb4e22 | |||
| 68368c87ca | |||
| 86d0fd77a7 | |||
| dd8952f700 | |||
| 3ccf6764c1 | |||
| 521feb9a1b | |||
| bc141febdb | |||
| a79a81cd24 | |||
| 3440909fc9 | |||
| 39f7a14126 | |||
| 9e6b10ce46 | |||
| 247635ed92 | |||
| 1cec497a50 | |||
| 0428cdd934 | |||
| 7bc98db23c | |||
| 7b703a3b98 | |||
| 3c7c256fc9 | |||
| d9c7f42b4c | |||
| 93dd10917c | |||
| f01989ff49 | |||
| 07234f6255 | |||
| 22c1685d70 | |||
| 7b8ed826b8 | |||
| e5f2e72843 | |||
| e631805635 | |||
| d81b436e5d | |||
| 0e4fd349a9 | |||
| f279346dac | |||
| c05fc951d8 | |||
| 221d4f8fb1 | |||
| e9427e421b | |||
| 85719fcd64 | |||
| fe37d0f5f9 | |||
| b4f2777755 | |||
| 051e3fb079 | |||
| 14f5ebcc3b | |||
| 4fdf343045 | |||
| 514f0053cc | |||
| 5dcb6e37b1 | |||
| 861e7994ff | |||
| 5c7ff5c24a | |||
| a458b682d6 | |||
| d04bfaca5a | |||
| 9d2ba5be42 | |||
| 021ee0d317 | |||
| a199819acb | |||
| 18e2457ddf | |||
| e1ef0477fb | |||
| d57b0b11ab | |||
| 7fcc3f58e4 | |||
| c1d399b300 | |||
| 829c386756 | |||
| a38352c4cc | |||
| d108bf58bf | |||
| 85d244598c | |||
| 014f3c8f21 | |||
| dd6fc48dd8 | |||
| 5a65da400d | |||
| 5ba051aa70 | |||
| 366c371912 | |||
| c5fedb6f8d | |||
| d59f128210 | |||
| 59a0ba285f | |||
| 9d9aadb80f | |||
| 71e491fcf0 | |||
| 2ce174dbf0 | |||
| 2b81983f7c | |||
| 8a05548dcb | |||
| 4f265c8fbc | |||
| 3ca78df15f | |||
| 78c5c733e5 |
+1
-1
@@ -13,4 +13,4 @@ cache:
|
||||
- $HOME/.gradle/caches/
|
||||
- $HOME/.gradle/wrapper/
|
||||
|
||||
script: ./gradlew build
|
||||
script: ./gradlew build --refresh-dependencies --no-daemon
|
||||
|
||||
Vendored
+113
@@ -0,0 +1,113 @@
|
||||
def projectProperties = [
|
||||
[$class: 'BuildDiscarderProperty',
|
||||
strategy: [$class: 'LogRotator', numToKeepStr: '5']],
|
||||
pipelineTriggers([cron('@daily')])
|
||||
]
|
||||
properties(projectProperties)
|
||||
|
||||
def SUCCESS = hudson.model.Result.SUCCESS.toString()
|
||||
currentBuild.result = SUCCESS
|
||||
|
||||
try {
|
||||
parallel check: {
|
||||
stage('Check') {
|
||||
node {
|
||||
checkout scm
|
||||
try {
|
||||
sh "./gradlew clean check --refresh-dependencies --no-daemon"
|
||||
} catch(Exception e) {
|
||||
currentBuild.result = 'FAILED: check'
|
||||
throw e
|
||||
} finally {
|
||||
junit '**/build/*-results/*.xml'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
sonar: {
|
||||
stage('Sonar') {
|
||||
node {
|
||||
checkout scm
|
||||
withCredentials([string(credentialsId: 'spring-sonar.login', variable: 'SONAR_LOGIN')]) {
|
||||
try {
|
||||
sh "./gradlew clean sonarqube -PexcludeProjects='**/samples/**' -Dsonar.host.url=$SPRING_SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN --refresh-dependencies --no-daemon"
|
||||
} catch(Exception e) {
|
||||
currentBuild.result = 'FAILED: sonar'
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
springio: {
|
||||
stage('Spring IO') {
|
||||
node {
|
||||
checkout scm
|
||||
try {
|
||||
sh "./gradlew clean springIoCheck -PplatformVersion=Cairo-BUILD-SNAPSHOT -PexcludeProjects='**/samples/**' --refresh-dependencies --no-daemon --stacktrace"
|
||||
} catch(Exception e) {
|
||||
currentBuild.result = 'FAILED: springio'
|
||||
throw e
|
||||
} finally {
|
||||
junit '**/build/spring-io*-results/*.xml'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(currentBuild.result == 'SUCCESS') {
|
||||
parallel artifactory: {
|
||||
stage('Artifactory Deploy') {
|
||||
node {
|
||||
checkout scm
|
||||
withCredentials([usernamePassword(credentialsId: '02bd1690-b54f-4c9f-819d-a77cb7a9822c', usernameVariable: 'ARTIFACTORY_USERNAME', passwordVariable: 'ARTIFACTORY_PASSWORD')]) {
|
||||
sh "./gradlew check artifactoryPublish -x check -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --no-daemon --stacktrace"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
docs: {
|
||||
stage('Deploy Docs') {
|
||||
node {
|
||||
checkout scm
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
schema: {
|
||||
stage('Deploy Schema') {
|
||||
node {
|
||||
checkout scm
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// Acl Module build file
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-security-core'),
|
||||
springCoreDependency,
|
||||
'aopalliance:aopalliance:1.0',
|
||||
"org.springframework:spring-aop:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
"org.springframework:spring-tx:$springVersion",
|
||||
"org.springframework:spring-jdbc:$springVersion"
|
||||
|
||||
optional "net.sf.ehcache:ehcache:$ehcacheVersion"
|
||||
|
||||
testCompile "org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-context-support:$springVersion",
|
||||
"org.springframework:spring-test:$springVersion"
|
||||
|
||||
testRuntime "org.hsqldb:hsqldb:$hsqlVersion"
|
||||
}
|
||||
-171
@@ -1,171 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-acl</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<name>spring-security-acl</name>
|
||||
<description>spring-security-acl</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
<organization>
|
||||
<name>spring.io</name>
|
||||
<url>http://spring.io/</url>
|
||||
</organization>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>rwinch</id>
|
||||
<name>Rob Winch</name>
|
||||
<email>rwinch@gopivotal.com</email>
|
||||
</developer>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
|
||||
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
|
||||
<url>https://github.com/spring-projects/spring-security</url>
|
||||
</scm>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>4.3.5.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>aopalliance</groupId>
|
||||
<artifactId>aopalliance</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>1.2</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
<version>2.9.0</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>2.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>1.7.7</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,19 @@
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-security-core')
|
||||
compile 'aopalliance:aopalliance'
|
||||
compile 'org.springframework:spring-aop'
|
||||
compile 'org.springframework:spring-context'
|
||||
compile 'org.springframework:spring-core'
|
||||
compile 'org.springframework:spring-jdbc'
|
||||
compile 'org.springframework:spring-tx'
|
||||
|
||||
optional 'net.sf.ehcache:ehcache'
|
||||
|
||||
testCompile 'org.springframework:spring-beans'
|
||||
testCompile 'org.springframework:spring-context-support'
|
||||
testCompile 'org.springframework:spring-test'
|
||||
|
||||
testRuntime 'org.hsqldb:hsqldb'
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-security-core'),
|
||||
springCoreDependency,
|
||||
"org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion"
|
||||
|
||||
testCompile 'aopalliance:aopalliance:1.0',
|
||||
"org.springframework:spring-aop:$springVersion"
|
||||
}
|
||||
-150
@@ -1,150 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-aspects</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<name>spring-security-aspects</name>
|
||||
<description>spring-security-aspects</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
<organization>
|
||||
<name>spring.io</name>
|
||||
<url>http://spring.io/</url>
|
||||
</organization>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>rwinch</id>
|
||||
<name>Rob Winch</name>
|
||||
<email>rwinch@gopivotal.com</email>
|
||||
</developer>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
|
||||
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
|
||||
<url>https://github.com/spring-projects/spring-security</url>
|
||||
</scm>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>4.3.5.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>1.2</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<version>1.8.4</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>aopalliance</groupId>
|
||||
<artifactId>aopalliance</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>2.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>1.7.7</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,12 @@
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
apply plugin: 'aspectj'
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-security-core')
|
||||
compile 'org.springframework:spring-beans'
|
||||
compile 'org.springframework:spring-context'
|
||||
compile 'org.springframework:spring-core'
|
||||
|
||||
testCompile 'aopalliance:aopalliance'
|
||||
testCompile 'org.springframework:spring-aop'
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
apply plugin: 'maven-bom'
|
||||
apply from: "$rootDir/gradle/maven-deployment.gradle"
|
||||
|
||||
generatePom.enabled = false
|
||||
sonarqube.skipProject = true
|
||||
|
||||
mavenBom {
|
||||
projects = coreModuleProjects
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
apply plugin: 'maven-bom'
|
||||
|
||||
sonarqube.skipProject = true
|
||||
|
||||
project.rootProject.allprojects.each { p ->
|
||||
p.plugins.withType(io.spring.gradle.convention.SpringMavenPlugin) {
|
||||
project.mavenBom.projects.add(p)
|
||||
}
|
||||
}
|
||||
+11
-184
@@ -1,192 +1,19 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
maven { url "https://repo.spring.io/plugins-release" }
|
||||
maven { url "https://repo.spring.io/plugins-snapshot" }
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.7")
|
||||
classpath("io.spring.gradle:spring-io-plugin:0.0.6.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("io.spring.gradle:docbook-reference-plugin:0.3.1")
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.0.BUILD-SNAPSHOT")
|
||||
classpath 'io.spring.gradle:spring-build-conventions:0.0.2.RELEASE'
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"
|
||||
}
|
||||
repositories {
|
||||
maven { url 'https://repo.spring.io/plugins-snapshot' }
|
||||
}
|
||||
}
|
||||
apply plugin: 'io.spring.convention.root'
|
||||
|
||||
plugins {
|
||||
id "org.sonarqube" version "2.1-rc1"
|
||||
}
|
||||
|
||||
apply plugin: 'base'
|
||||
|
||||
group = 'org.springframework.security'
|
||||
description = 'Spring Security'
|
||||
|
||||
allprojects {
|
||||
apply plugin: 'idea'
|
||||
apply plugin: 'eclipse'
|
||||
ext.snapshotBuild = version.contains("SNAPSHOT")
|
||||
ext.releaseBuild = version.contains("SNAPSHOT")
|
||||
ext.milestoneBuild = !(snapshotBuild || releaseBuild)
|
||||
|
||||
ext.releaseBuild = version.endsWith('RELEASE')
|
||||
ext.snapshotBuild = version.endsWith('SNAPSHOT')
|
||||
ext.springVersion = '4.3.5.RELEASE'
|
||||
ext.springLdapVersion = '2.2.0.RELEASE'
|
||||
|
||||
group = 'org.springframework.security'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url "https://repo.spring.io/libs-snapshot" }
|
||||
maven { url "https://repo.spring.io/plugins-release" }
|
||||
maven { url "http://repo.terracotta.org/maven2/" }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sonarqube {
|
||||
properties {
|
||||
property "sonar.java.coveragePlugin", "jacoco"
|
||||
property "sonar.projectName", "Spring Security"
|
||||
property "sonar.jacoco.reportPath", "${buildDir.name}/jacoco.exec"
|
||||
property "sonar.links.homepage", 'https://www.springsource.org/spring-security'
|
||||
property "sonar.links.ci", 'https://build.springsource.org/browse/SEC-B32X'
|
||||
property "sonar.links.issue", 'https://jira.springsource.org/browse/SEC'
|
||||
property "sonar.links.scm", 'https://github.com/SpringSource/spring-security'
|
||||
property "sonar.links.scm_dev", 'https://github.com/SpringSource/spring-security.git'
|
||||
property "sonar.java.coveragePlugin", "jacoco"
|
||||
}
|
||||
}
|
||||
|
||||
// Set up different subproject lists for individual configuration
|
||||
ext.javaProjects = subprojects.findAll { project -> project.name != 'docs' && project.name != 'manual' && project.name != 'guides' && project.name != 'spring-security-bom' }
|
||||
ext.sampleProjects = subprojects.findAll { project -> project.name.startsWith('spring-security-samples') }
|
||||
ext.itestProjects = subprojects.findAll { project -> project.name.startsWith('itest') }
|
||||
ext.coreModuleProjects = javaProjects - sampleProjects - itestProjects
|
||||
ext.aspectjProjects = [project(':spring-security-aspects'), project(':spring-security-samples-xml-aspectj'), project(':spring-security-samples-javaconfig-aspectj')]
|
||||
|
||||
configure(allprojects - javaProjects) {
|
||||
task afterEclipseImport {
|
||||
ext.srcFile = file('.classpath')
|
||||
inputs.file srcFile
|
||||
outputs.dir srcFile
|
||||
|
||||
onlyIf { !srcFile.exists() }
|
||||
|
||||
doLast {
|
||||
srcFile << """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configure(subprojects - coreModuleProjects - project(':spring-security-samples-javaconfig-messages') - project(':spring-security-bom')) {
|
||||
tasks.findByPath("artifactoryPublish")?.enabled = false
|
||||
sonarqube {
|
||||
skipProject = true
|
||||
}
|
||||
}
|
||||
|
||||
configure(javaProjects) {
|
||||
ext.TOMCAT_GRADLE = "$rootDir/gradle/tomcat.gradle"
|
||||
ext.WAR_SAMPLE_GRADLE = "$rootDir/gradle/war-sample.gradle"
|
||||
ext.BOOT_SAMPLE_GRADLE = "$rootDir/gradle/boot-sample.gradle"
|
||||
apply from: "$rootDir/gradle/javaprojects.gradle"
|
||||
if(!project.name.contains('gae')) {
|
||||
apply from: "$rootDir/gradle/checkstyle.gradle"
|
||||
}
|
||||
apply from: "$rootDir/gradle/ide.gradle"
|
||||
apply from: "$rootDir/gradle/release-checks.gradle"
|
||||
apply from: "$rootDir/gradle/maven-deployment.gradle"
|
||||
}
|
||||
|
||||
configure(coreModuleProjects) {
|
||||
apply plugin: 'emma'
|
||||
apply plugin: 'spring-io'
|
||||
|
||||
ext.springIoVersion = project.hasProperty('platformVersion') ? platformVersion : 'Athens-BUILD-SNAPSHOT'
|
||||
|
||||
configurations {
|
||||
jacoco //Configuration Group used by Sonar to provide Code Coverage using JaCoCo
|
||||
}
|
||||
|
||||
dependencyManagement {
|
||||
springIoTestRuntime {
|
||||
imports {
|
||||
mavenBom("io.spring.platform:platform-bom:${springIoVersion}") {
|
||||
bomProperties([
|
||||
'mockito.version': '1.10.19'
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
jacoco "org.jacoco:org.jacoco.agent:0.7.5.201505241946:runtime"
|
||||
}
|
||||
test {
|
||||
jvmArgs "-javaagent:${configurations.jacoco.asPath}=destfile=${buildDir}/jacoco.exec,includes=${project.group}.*"
|
||||
}
|
||||
integrationTest {
|
||||
jvmArgs "-javaagent:${configurations.jacoco.asPath}=destfile=${buildDir}/jacoco.exec,includes=${project.group}.*"
|
||||
}
|
||||
}
|
||||
|
||||
configure (aspectjProjects) {
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'aspectj'
|
||||
}
|
||||
|
||||
task coreBuild {
|
||||
dependsOn coreModuleProjects*.tasks*.matching { task -> task.name == 'build' }
|
||||
}
|
||||
|
||||
task coreInstall {
|
||||
dependsOn coreModuleProjects*.tasks*.matching { task -> task.name == 'install' }
|
||||
}
|
||||
|
||||
// Task for creating the distro zip
|
||||
|
||||
task dist(type: Zip) {
|
||||
dependsOn { subprojects*.tasks*.matching { task -> task.name.endsWith('generatePom') } }
|
||||
classifier = 'dist'
|
||||
|
||||
evaluationDependsOn(':docs')
|
||||
evaluationDependsOn(':docs:manual')
|
||||
|
||||
def zipRootDir = "${project.name}-$version"
|
||||
into(zipRootDir) {
|
||||
from(rootDir) {
|
||||
include '*.adoc'
|
||||
include '*.txt'
|
||||
}
|
||||
into('docs') {
|
||||
with(project(':docs').apiSpec)
|
||||
with(project(':docs:manual').spec)
|
||||
with(project(':docs:guides').spec)
|
||||
}
|
||||
project.coreModuleProjects*.tasks*.withType(AbstractArchiveTask).flatten().each{ archiveTask ->
|
||||
if(archiveTask!=dist){
|
||||
into("$zipRootDir/dist") {
|
||||
from archiveTask.outputs.files
|
||||
}
|
||||
}
|
||||
}
|
||||
sampleProjects.each { project->
|
||||
into("$zipRootDir/samples/$project.name") {
|
||||
from(project.projectDir) {
|
||||
include "src/main/**"
|
||||
include "pom.xml"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives dist
|
||||
archives project(':docs').docsZip
|
||||
archives project(':docs').schemaZip
|
||||
}
|
||||
dependencyManagementExport.projects = subprojects.findAll { !it.name.contains('-boot') }
|
||||
|
||||
@@ -13,7 +13,9 @@ public class MavenBomPlugin implements Plugin<Project> {
|
||||
public void apply(Project project) {
|
||||
project.plugins.apply(JavaPlugin)
|
||||
project.plugins.apply(MavenPlugin)
|
||||
|
||||
project.group = project.rootProject.group
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import org.gradle.api.tasks.*
|
||||
|
||||
public class MavenBomTask extends DefaultTask {
|
||||
|
||||
Set<Project> projects
|
||||
Set<Project> projects = []
|
||||
|
||||
File bomFile
|
||||
|
||||
@@ -52,4 +52,4 @@ public class MavenBomTask extends DefaultTask {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,15 +26,11 @@ class AspectJPlugin implements Plugin<Project> {
|
||||
void apply(Project project) {
|
||||
project.plugins.apply(JavaPlugin)
|
||||
|
||||
if (!project.hasProperty('aspectjVersion')) {
|
||||
throw new GradleException("You must set the property 'aspectjVersion' before applying the aspectj plugin")
|
||||
}
|
||||
|
||||
if (project.configurations.findByName('ajtools') == null) {
|
||||
project.configurations.create('ajtools')
|
||||
project.dependencies {
|
||||
ajtools "org.aspectj:aspectjtools:${project.aspectjVersion}"
|
||||
optional "org.aspectj:aspectjrt:${project.aspectjVersion}"
|
||||
ajtools "org.aspectj:aspectjtools"
|
||||
optional "org.aspectj:aspectjrt"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-security-core'),
|
||||
project(':spring-security-web'),
|
||||
springCoreDependency,
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
"org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-web:$springVersion",
|
||||
"org.jasig.cas.client:cas-client-core:$casClientVersion"
|
||||
|
||||
optional "net.sf.ehcache:ehcache:$ehcacheVersion",
|
||||
"com.fasterxml.jackson.core:jackson-databind:$jacksonDatabindVersion"
|
||||
|
||||
testCompile "org.skyscreamer:jsonassert:$jsonassertVersion"
|
||||
|
||||
provided "javax.servlet:javax.servlet-api:$servletApiVersion"
|
||||
}
|
||||
-175
@@ -1,175 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-cas</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<name>spring-security-cas</name>
|
||||
<description>spring-security-cas</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
<organization>
|
||||
<name>spring.io</name>
|
||||
<url>http://spring.io/</url>
|
||||
</organization>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>rwinch</id>
|
||||
<name>Rob Winch</name>
|
||||
<email>rwinch@gopivotal.com</email>
|
||||
</developer>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
|
||||
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
|
||||
<url>https://github.com/spring-projects/spring-security</url>
|
||||
</scm>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>4.3.5.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-core</artifactId>
|
||||
<version>3.4.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.8.4</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>1.2</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
<version>2.9.0</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>2.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.skyscreamer</groupId>
|
||||
<artifactId>jsonassert</artifactId>
|
||||
<version>1.3.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>1.7.7</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,18 @@
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-security-core')
|
||||
compile project(':spring-security-web')
|
||||
compile 'org.jasig.cas.client:cas-client-core'
|
||||
compile 'org.springframework:spring-beans'
|
||||
compile 'org.springframework:spring-context'
|
||||
compile 'org.springframework:spring-core'
|
||||
compile 'org.springframework:spring-web'
|
||||
|
||||
optional 'com.fasterxml.jackson.core:jackson-databind'
|
||||
optional 'net.sf.ehcache:ehcache'
|
||||
|
||||
provided 'javax.servlet:javax.servlet-api'
|
||||
|
||||
testCompile 'org.skyscreamer:jsonassert'
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
import javax.security.auth.login.ConfigurationSpi;
|
||||
|
||||
// Config Module build file
|
||||
|
||||
apply plugin: 'groovy'
|
||||
apply plugin: 'trang'
|
||||
|
||||
compileTestJava.dependsOn(':spring-security-core:compileTestJava')
|
||||
|
||||
dependencies {
|
||||
// NB: Don't add other compile time dependencies to the config module as this breaks tooling
|
||||
compile project(':spring-security-core'),
|
||||
springCoreDependency,
|
||||
'aopalliance:aopalliance:1.0',
|
||||
"org.springframework:spring-aop:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
"org.springframework:spring-beans:$springVersion"
|
||||
|
||||
optional project(':spring-security-web'),
|
||||
project(':spring-security-ldap'),
|
||||
project(':spring-security-openid'),
|
||||
project(':spring-security-messaging'),
|
||||
"org.springframework:spring-web:$springVersion",
|
||||
"org.springframework:spring-websocket:$springVersion",
|
||||
"org.springframework:spring-webmvc:$springVersion",
|
||||
"org.aspectj:aspectjweaver:$aspectjVersion",
|
||||
"org.springframework:spring-jdbc:$springVersion",
|
||||
"org.springframework:spring-tx:$springVersion"
|
||||
|
||||
provided "javax.servlet:javax.servlet-api:$servletApiVersion"
|
||||
|
||||
testCompile project(':spring-security-cas'),
|
||||
project(':spring-security-core').sourceSets.test.output,
|
||||
project(':spring-security-aspects'),
|
||||
'javax.annotation:jsr250-api:1.0',
|
||||
"org.springframework.ldap:spring-ldap-core:$springLdapVersion",
|
||||
"org.springframework:spring-expression:$springVersion",
|
||||
"org.springframework:spring-jdbc:$springVersion",
|
||||
"org.springframework:spring-orm:$springVersion",
|
||||
"org.springframework:spring-tx:$springVersion",
|
||||
"org.slf4j:jcl-over-slf4j:$slf4jVersion",
|
||||
"org.eclipse.persistence:javax.persistence:$javaPersistenceVersion",
|
||||
"org.hibernate:hibernate-entitymanager:$hibernateVersion",
|
||||
"org.codehaus.groovy:groovy-all:$groovyVersion",
|
||||
"org.apache.directory.server:apacheds-core:$apacheDsVersion",
|
||||
"org.apache.directory.server:apacheds-core-entry:$apacheDsVersion",
|
||||
"org.apache.directory.server:apacheds-protocol-shared:$apacheDsVersion",
|
||||
"org.apache.directory.server:apacheds-protocol-ldap:$apacheDsVersion",
|
||||
"org.apache.directory.server:apacheds-server-jndi:$apacheDsVersion",
|
||||
'org.apache.directory.shared:shared-ldap:0.9.15',
|
||||
'ldapsdk:ldapsdk:4.1',
|
||||
powerMockDependencies,
|
||||
"org.hsqldb:hsqldb:$hsqlVersion",
|
||||
spockDependencies
|
||||
|
||||
testCompile('org.openid4java:openid4java-nodeps:0.9.6') {
|
||||
exclude group: 'com.google.code.guice', module: 'guice'
|
||||
}
|
||||
testCompile("org.springframework.data:spring-data-jpa:$springDataJpaVersion") {
|
||||
exclude group: 'org.aspectj', module: 'aspectjrt'
|
||||
}
|
||||
|
||||
testRuntime "org.hsqldb:hsqldb:$hsqlVersion",
|
||||
"cglib:cglib-nodep:$cglibVersion"
|
||||
}
|
||||
|
||||
test {
|
||||
inputs.file file("$rootDir/docs/manual/src/docbook/appendix-namespace.xml")
|
||||
}
|
||||
|
||||
rncToXsd {
|
||||
rncDir = file('src/main/resources/org/springframework/security/config/')
|
||||
xsdDir = rncDir
|
||||
xslFile = new File(rncDir, 'spring-security.xsl')
|
||||
}
|
||||
|
||||
build.dependsOn rncToXsd
|
||||
-410
@@ -1,410 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<name>spring-security-config</name>
|
||||
<description>spring-security-config</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
<organization>
|
||||
<name>spring.io</name>
|
||||
<url>http://spring.io/</url>
|
||||
</organization>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>rwinch</id>
|
||||
<name>Rob Winch</name>
|
||||
<email>rwinch@gopivotal.com</email>
|
||||
</developer>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
|
||||
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
|
||||
<url>https://github.com/spring-projects/spring-security</url>
|
||||
</scm>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>4.3.5.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>aopalliance</groupId>
|
||||
<artifactId>aopalliance</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>1.2</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<version>1.8.4</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-ldap</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-messaging</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-openid</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-websocket</artifactId>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib-nodep</artifactId>
|
||||
<version>3.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>jsr250-api</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ldapsdk</groupId>
|
||||
<artifactId>ldapsdk</artifactId>
|
||||
<version>4.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-core</artifactId>
|
||||
<version>1.5.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-core-entry</artifactId>
|
||||
<version>1.5.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-protocol-ldap</artifactId>
|
||||
<version>1.5.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-protocol-shared</artifactId>
|
||||
<version>1.5.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-server-jndi</artifactId>
|
||||
<version>1.5.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.shared</groupId>
|
||||
<artifactId>shared-ldap</artifactId>
|
||||
<version>0.9.15</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>2.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
<version>2.4.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.persistence</groupId>
|
||||
<artifactId>javax.persistence</artifactId>
|
||||
<version>2.1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-entitymanager</artifactId>
|
||||
<version>5.0.11.Final</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openid4java</groupId>
|
||||
<artifactId>openid4java-nodeps</artifactId>
|
||||
<version>0.9.6</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>guice</artifactId>
|
||||
<groupId>com.google.code.guice</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-mockito</artifactId>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<groupId>org.mockito</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-support</artifactId>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-core</artifactId>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4</artifactId>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4-common</artifactId>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-reflect</artifactId>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>1.7.7</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-core</artifactId>
|
||||
<version>0.7-groovy-2.0</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>junit-dep</artifactId>
|
||||
<groupId>junit</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-spring</artifactId>
|
||||
<version>0.7-groovy-2.0</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>junit-dep</artifactId>
|
||||
<groupId>junit</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-jpa</artifactId>
|
||||
<version>1.10.2.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<groupId>org.aspectj</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-core</artifactId>
|
||||
<version>2.2.0.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-aspects</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-cas</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-expression</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-orm</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,68 @@
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
apply plugin: 'trang'
|
||||
|
||||
dependencies {
|
||||
// NB: Don't add other compile time dependencies to the config module as this breaks tooling
|
||||
compile project(':spring-security-core')
|
||||
compile 'aopalliance:aopalliance:1.0'
|
||||
compile 'org.springframework:spring-aop'
|
||||
compile 'org.springframework:spring-beans'
|
||||
compile 'org.springframework:spring-context'
|
||||
compile 'org.springframework:spring-core'
|
||||
|
||||
optional project(':spring-security-ldap')
|
||||
optional project(':spring-security-messaging')
|
||||
optional project(':spring-security-oauth2-client')
|
||||
optional project(':spring-security-openid')
|
||||
optional project(':spring-security-web')
|
||||
optional project(':spring-security-webflux')
|
||||
optional 'org.aspectj:aspectjweaver'
|
||||
optional 'org.springframework:spring-jdbc'
|
||||
optional 'org.springframework:spring-tx'
|
||||
optional 'org.springframework:spring-webmvc'
|
||||
optional'org.springframework:spring-web'
|
||||
optional'org.springframework:spring-websocket'
|
||||
|
||||
provided 'javax.servlet:javax.servlet-api'
|
||||
|
||||
testCompile project(':spring-security-aspects')
|
||||
testCompile project(':spring-security-cas')
|
||||
testCompile project(path : ':spring-security-core', configuration : 'tests')
|
||||
testCompile project(path : ':spring-security-webflux', configuration : 'tests')
|
||||
testCompile apachedsDependencies
|
||||
testCompile powerMockDependencies
|
||||
testCompile spockDependencies
|
||||
testCompile 'javax.annotation:jsr250-api:1.0'
|
||||
testCompile 'ldapsdk:ldapsdk:4.1'
|
||||
testCompile 'org.codehaus.groovy:groovy-all'
|
||||
testCompile 'org.eclipse.persistence:javax.persistence'
|
||||
testCompile 'org.hibernate:hibernate-entitymanager'
|
||||
testCompile 'org.hsqldb:hsqldb'
|
||||
testCompile ('org.openid4java:openid4java-nodeps') {
|
||||
exclude group: 'com.google.code.guice', module: 'guice'
|
||||
}
|
||||
testCompile 'org.slf4j:jcl-over-slf4j'
|
||||
testCompile 'org.springframework.ldap:spring-ldap-core'
|
||||
testCompile 'org.springframework:spring-expression'
|
||||
testCompile 'org.springframework:spring-jdbc'
|
||||
testCompile 'org.springframework:spring-orm'
|
||||
testCompile 'org.springframework:spring-tx'
|
||||
testCompile ('org.springframework.data:spring-data-jpa') {
|
||||
exclude group: 'org.aspectj', module: 'aspectjrt'
|
||||
}
|
||||
|
||||
testRuntime 'cglib:cglib-nodep'
|
||||
testRuntime 'org.hsqldb:hsqldb'
|
||||
}
|
||||
|
||||
test {
|
||||
inputs.file file("$rootDir/docs/manual/src/docbook/appendix-namespace.xml")
|
||||
}
|
||||
|
||||
rncToXsd {
|
||||
rncDir = file('src/main/resources/org/springframework/security/config/')
|
||||
xsdDir = rncDir
|
||||
xslFile = new File(rncDir, 'spring-security.xsl')
|
||||
}
|
||||
|
||||
build.dependsOn rncToXsd
|
||||
+8
@@ -77,6 +77,10 @@ final class FilterComparator implements Comparator<Filter>, Serializable {
|
||||
order += STEP;
|
||||
put(LogoutFilter.class, order);
|
||||
order += STEP;
|
||||
filterToOrder.put(
|
||||
"org.springframework.security.oauth2.client.authentication.AuthorizationCodeRequestRedirectFilter",
|
||||
order);
|
||||
order += STEP;
|
||||
put(X509AuthenticationFilter.class, order);
|
||||
order += STEP;
|
||||
put(AbstractPreAuthenticatedProcessingFilter.class, order);
|
||||
@@ -84,6 +88,10 @@ final class FilterComparator implements Comparator<Filter>, Serializable {
|
||||
filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter",
|
||||
order);
|
||||
order += STEP;
|
||||
filterToOrder.put(
|
||||
"org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationProcessingFilter",
|
||||
order);
|
||||
order += STEP;
|
||||
put(UsernamePasswordAuthenticationFilter.class, order);
|
||||
order += STEP;
|
||||
put(ConcurrentSessionFilter.class, order);
|
||||
|
||||
+153
@@ -61,6 +61,7 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.config.annotation.web.configurers.oauth2.client.OAuth2LoginConfigurer;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.PortMapper;
|
||||
import org.springframework.security.web.PortMapperImpl;
|
||||
@@ -896,6 +897,158 @@ public final class HttpSecurity extends
|
||||
return getOrApply(new FormLoginConfigurer<HttpSecurity>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures authentication against an external <i>OAuth 2.0</i> or <i>OpenID Connect 1.0</i> Provider.
|
||||
* <br>
|
||||
* <br>
|
||||
*
|
||||
* The <i>"authentication flow"</i> is realized using the <b>Authorization Code Grant</b>,
|
||||
* as specified in the <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1">OAuth 2.0 Authorization Framework</a>.
|
||||
* <br>
|
||||
* <br>
|
||||
*
|
||||
* As a prerequisite to using this feature, the developer must register a <i>Client</i> with an <i>Authorization Server</i>.
|
||||
* The output of the <i>Client Registration</i> process results in a number of properties that are then used for configuring
|
||||
* an instance of a {@link org.springframework.security.oauth2.client.registration.ClientRegistration}.
|
||||
* Properties specific to a <i>Client</i> include: <i>client_id</i>, <i>client_secret</i>, <i>scope</i>, <i>redirect_uri</i>, etc.
|
||||
* There are also properties specific to the <i>Provider</i>, for example,
|
||||
* <i>Authorization Endpoint URI</i>, <i>Token Endpoint URI</i>, <i>UserInfo Endpoint URI</i>, etc.
|
||||
* <br>
|
||||
* <br>
|
||||
*
|
||||
* Multiple client support is provided for use cases where the application provides the user the option
|
||||
* for <i>"Logging in"</i> against one or more Providers, for example, <i>Google</i>, <i>GitHub</i>, <i>Facebook</i>, etc.
|
||||
* <br>
|
||||
* <br>
|
||||
*
|
||||
* {@link org.springframework.security.oauth2.client.registration.ClientRegistration}(s) are composed within a
|
||||
* {@link org.springframework.security.oauth2.client.registration.ClientRegistrationRepository}.
|
||||
* An instance of {@link org.springframework.security.oauth2.client.registration.ClientRegistrationRepository} is <b>required</b>
|
||||
* and may be supplied via the {@link ApplicationContext} or configured using
|
||||
* {@link OAuth2LoginConfigurer#clients(org.springframework.security.oauth2.client.registration.ClientRegistrationRepository)}.
|
||||
* <br>
|
||||
* <br>
|
||||
*
|
||||
* The default configuration provides an auto-generated login page at <code>"/login"</code> and
|
||||
* redirects to <code>"/login?error"</code> when an authentication error occurs.
|
||||
* The login page will display each of the clients (composed within the
|
||||
* {@link org.springframework.security.oauth2.client.registration.ClientRegistrationRepository})
|
||||
* with an anchor link to <code>"/oauth2/authorization/code/{clientAlias}"</code>.
|
||||
* Clicking through the link will initiate the <i>"Authorization Request"</i> flow
|
||||
* redirecting the end-user's user-agent to the <i>Authorization Endpoint</i> of the <i>Provider</i>.
|
||||
* Assuming the <i>Resource Owner</i> (end-user) grants the <i>Client</i> access, the <i>Authorization Server</i>
|
||||
* will redirect the end-user's user-agent to the <i>Redirection Endpoint</i> containing the <i>Authorization Code</i>
|
||||
* - the <i>Redirection Endpoint</i> is automatically configured for the application and
|
||||
* defaults to <code>"/oauth2/authorize/code/{clientAlias}"</code>.
|
||||
*
|
||||
* <p>
|
||||
* At this point in the <i>"authentication flow"</i>, the configured
|
||||
* {@link org.springframework.security.oauth2.client.authentication.AuthorizationGrantTokenExchanger}
|
||||
* will exchange the <i>Authorization Code</i> for an <i>Access Token</i> and then use it to access the protected resource
|
||||
* at the <i>UserInfo Endpoint</i> (via {@link org.springframework.security.oauth2.client.user.OAuth2UserService})
|
||||
* in order to retrieve the details of the <i>Resource Owner</i> (end-user) and establish the <i>"authenticated"</i> session.
|
||||
*
|
||||
* <h2>Example Configurations</h2>
|
||||
*
|
||||
* The minimal configuration defaults to automatically generating a login page at <code>"/login"</code>
|
||||
* and redirecting to <code>"/login?error"</code> when an authentication error occurs or redirecting to
|
||||
* <code>"/"</code> when an authenticated session is established.
|
||||
*
|
||||
* <pre>
|
||||
* @EnableWebSecurity
|
||||
* public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
*
|
||||
* @Override
|
||||
* protected void configure(HttpSecurity http) throws Exception {
|
||||
* http
|
||||
* .authorizeRequests()
|
||||
* .anyRequest().authenticated()
|
||||
* .and()
|
||||
* .oauth2Login();
|
||||
* }
|
||||
*
|
||||
* @Bean
|
||||
* public ClientRegistrationRepository clientRegistrationRepository() {
|
||||
* // ClientRegistrationRepositoryImpl must be composed of at least one ClientRegistration instance
|
||||
* return new ClientRegistrationRepositoryImpl();
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* The following shows the configuration options available for customizing the defaults.
|
||||
*
|
||||
* <pre>
|
||||
* @EnableWebSecurity
|
||||
* public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
*
|
||||
* @Override
|
||||
* protected void configure(HttpSecurity http) throws Exception {
|
||||
* http
|
||||
* .authorizeRequests()
|
||||
* .anyRequest().authenticated()
|
||||
* .and()
|
||||
* .oauth2Login()
|
||||
* .clients(this.clientRegistrationRepository())
|
||||
* .authorizationRequestBuilder(this.authorizationRequestBuilder())
|
||||
* .authorizationCodeTokenExchanger(this.authorizationCodeTokenExchanger())
|
||||
* .userInfoEndpoint()
|
||||
* .userInfoService(this.userInfoService())
|
||||
* .userInfoEndpoint()
|
||||
* // Provide a mapping between a Converter implementation and a UserInfo Endpoint URI
|
||||
* .userInfoTypeConverter(this.userInfoConverter(),
|
||||
* new URI("https://www.googleapis.com/oauth2/v3/userinfo"));
|
||||
* }
|
||||
*
|
||||
* @Bean
|
||||
* public ClientRegistrationRepository clientRegistrationRepository() {
|
||||
* // ClientRegistrationRepositoryImpl must be composed of at least one ClientRegistration instance
|
||||
* return new ClientRegistrationRepositoryImpl();
|
||||
* }
|
||||
*
|
||||
* @Bean
|
||||
* public AuthorizationRequestUriBuilder authorizationRequestBuilder() {
|
||||
* // Custom URI builder for the "Authorization Request"
|
||||
* return new AuthorizationRequestUriBuilderImpl();
|
||||
* }
|
||||
*
|
||||
* @Bean
|
||||
* public AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger() {
|
||||
* // Custom implementation that exchanges an "Authorization Code Grant" for an "Access Token"
|
||||
* return new AuthorizationCodeTokenExchangerImpl();
|
||||
* }
|
||||
*
|
||||
* @Bean
|
||||
* public OAuth2UserService userInfoService() {
|
||||
* // Custom implementation that retrieves the details of the authenticated user at the "UserInfo Endpoint"
|
||||
* return new OAuth2UserServiceImpl();
|
||||
* }
|
||||
*
|
||||
* @Bean
|
||||
* public Converter<ClientHttpResponse, UserInfo> userInfoConverter() {
|
||||
* // Default converter implementation for UserInfo
|
||||
* return new org.springframework.security.oauth2.client.user.converter.UserInfoConverter();
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @since 5.0
|
||||
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1">Section 4.1 Authorization Code Grant Flow</a>
|
||||
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1.1">Section 4.1.1 Authorization Request</a>
|
||||
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1.2">Section 4.1.2 Authorization Response</a>
|
||||
* @see org.springframework.security.oauth2.client.registration.ClientRegistration
|
||||
* @see org.springframework.security.oauth2.client.registration.ClientRegistrationRepository
|
||||
* @see org.springframework.security.oauth2.client.authentication.AuthorizationRequestUriBuilder
|
||||
* @see org.springframework.security.oauth2.client.authentication.AuthorizationGrantTokenExchanger
|
||||
* @see org.springframework.security.oauth2.client.user.OAuth2UserService
|
||||
*
|
||||
* @return the {@link OAuth2LoginConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
*/
|
||||
public OAuth2LoginConfigurer<HttpSecurity> oauth2Login() throws Exception {
|
||||
return getOrApply(new OAuth2LoginConfigurer<HttpSecurity>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures channel security. In order for this configuration to be useful at least
|
||||
* one mapping to a required channel must be provided.
|
||||
|
||||
+2
-2
@@ -213,7 +213,7 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
* Forward Authentication Failure Handler
|
||||
*
|
||||
* @param forwardUrl the target URL in case of failure
|
||||
* @return he {@link FormLoginConfigurer} for additional customization
|
||||
* @return the {@link FormLoginConfigurer} for additional customization
|
||||
*/
|
||||
public FormLoginConfigurer<H> failureForwardUrl(String forwardUrl) {
|
||||
failureHandler(new ForwardAuthenticationFailureHandler(forwardUrl));
|
||||
@@ -224,7 +224,7 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
* Forward Authentication Success Handler
|
||||
*
|
||||
* @param forwardUrl the target URL in case of success
|
||||
* @return he {@link FormLoginConfigurer} for additional customization
|
||||
* @return the {@link FormLoginConfigurer} for additional customization
|
||||
*/
|
||||
public FormLoginConfigurer<H> successForwardUrl(String forwardUrl) {
|
||||
successHandler(new ForwardAuthenticationSuccessHandler(forwardUrl));
|
||||
|
||||
+2
-2
@@ -227,7 +227,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows completing configuration of Strict Transport Security and continuing
|
||||
* Allows completing configuration of X-XSS-Protection and continuing
|
||||
* configuration of headers.
|
||||
*
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
@@ -282,7 +282,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows completing configuration of Strict Transport Security and continuing
|
||||
* Allows completing configuration of Cache Control and continuing
|
||||
* configuration of headers.
|
||||
*
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers.oauth2.client;
|
||||
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer;
|
||||
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationProcessingFilter;
|
||||
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationProvider;
|
||||
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationToken;
|
||||
import org.springframework.security.oauth2.client.authentication.AuthorizationGrantTokenExchanger;
|
||||
import org.springframework.security.oauth2.client.authentication.nimbus.NimbusAuthorizationCodeTokenExchanger;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.user.OAuth2UserService;
|
||||
import org.springframework.security.oauth2.client.user.nimbus.NimbusOAuth2UserService;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
final class AuthorizationCodeAuthenticationFilterConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
AbstractAuthenticationFilterConfigurer<H, AuthorizationCodeAuthenticationFilterConfigurer<H>, AuthorizationCodeAuthenticationProcessingFilter> {
|
||||
|
||||
private AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger;
|
||||
private OAuth2UserService userInfoService;
|
||||
private Map<URI, Function<ClientHttpResponse, ? extends OAuth2User>> userInfoTypeConverters = new HashMap<>();
|
||||
|
||||
|
||||
AuthorizationCodeAuthenticationFilterConfigurer() {
|
||||
super(new AuthorizationCodeAuthenticationProcessingFilter(), null);
|
||||
}
|
||||
|
||||
AuthorizationCodeAuthenticationFilterConfigurer<H> clientRegistrationRepository(ClientRegistrationRepository clientRegistrationRepository) {
|
||||
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
|
||||
Assert.notEmpty(clientRegistrationRepository.getRegistrations(), "clientRegistrationRepository cannot be empty");
|
||||
this.getBuilder().setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository);
|
||||
return this;
|
||||
}
|
||||
|
||||
AuthorizationCodeAuthenticationFilterConfigurer<H> authorizationCodeTokenExchanger(
|
||||
AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger) {
|
||||
|
||||
Assert.notNull(authorizationCodeTokenExchanger, "authorizationCodeTokenExchanger cannot be null");
|
||||
this.authorizationCodeTokenExchanger = authorizationCodeTokenExchanger;
|
||||
return this;
|
||||
}
|
||||
|
||||
AuthorizationCodeAuthenticationFilterConfigurer<H> userInfoService(OAuth2UserService userInfoService) {
|
||||
Assert.notNull(userInfoService, "userInfoService cannot be null");
|
||||
this.userInfoService = userInfoService;
|
||||
return this;
|
||||
}
|
||||
|
||||
AuthorizationCodeAuthenticationFilterConfigurer<H> userInfoTypeConverter(Function<ClientHttpResponse, ? extends OAuth2User> userInfoConverter, URI userInfoUri) {
|
||||
Assert.notNull(userInfoConverter, "userInfoConverter cannot be null");
|
||||
Assert.notNull(userInfoUri, "userInfoUri cannot be null");
|
||||
this.userInfoTypeConverters.put(userInfoUri, userInfoConverter);
|
||||
return this;
|
||||
}
|
||||
|
||||
String getLoginUrl() {
|
||||
return super.getLoginPage();
|
||||
}
|
||||
|
||||
String getLoginFailureUrl() {
|
||||
return super.getFailureUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(H http) throws Exception {
|
||||
AuthorizationCodeAuthenticationProvider authenticationProvider = new AuthorizationCodeAuthenticationProvider(
|
||||
this.getAuthorizationCodeTokenExchanger(), this.getUserInfoService());
|
||||
authenticationProvider = this.postProcess(authenticationProvider);
|
||||
http.authenticationProvider(authenticationProvider);
|
||||
super.init(http);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(H http) throws Exception {
|
||||
AuthorizationCodeAuthenticationProcessingFilter authFilter = this.getAuthenticationFilter();
|
||||
authFilter.setClientRegistrationRepository(OAuth2LoginConfigurer.getClientRegistrationRepository(this.getBuilder()));
|
||||
super.configure(http);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
|
||||
return this.getAuthenticationFilter().getAuthorizeRequestMatcher();
|
||||
}
|
||||
|
||||
private AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> getAuthorizationCodeTokenExchanger() {
|
||||
if (this.authorizationCodeTokenExchanger == null) {
|
||||
this.authorizationCodeTokenExchanger = new NimbusAuthorizationCodeTokenExchanger();
|
||||
}
|
||||
return this.authorizationCodeTokenExchanger;
|
||||
}
|
||||
|
||||
private OAuth2UserService getUserInfoService() {
|
||||
if (this.userInfoService == null) {
|
||||
this.userInfoService = new NimbusOAuth2UserService(this.userInfoTypeConverters);
|
||||
}
|
||||
return this.userInfoService;
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers.oauth2.client;
|
||||
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeRequestRedirectFilter;
|
||||
import org.springframework.security.oauth2.client.authentication.AuthorizationRequestUriBuilder;
|
||||
import org.springframework.security.oauth2.client.authentication.DefaultAuthorizationRequestUriBuilder;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
final class AuthorizationCodeRequestRedirectFilterConfigurer<B extends HttpSecurityBuilder<B>> extends
|
||||
AbstractHttpConfigurer<AuthorizationCodeRequestRedirectFilterConfigurer<B>, B> {
|
||||
|
||||
private AuthorizationRequestUriBuilder authorizationRequestBuilder;
|
||||
|
||||
AuthorizationCodeRequestRedirectFilterConfigurer<B> clientRegistrationRepository(ClientRegistrationRepository clientRegistrationRepository) {
|
||||
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
|
||||
Assert.notEmpty(clientRegistrationRepository.getRegistrations(), "clientRegistrationRepository cannot be empty");
|
||||
this.getBuilder().setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository);
|
||||
return this;
|
||||
}
|
||||
|
||||
AuthorizationCodeRequestRedirectFilterConfigurer<B> authorizationRequestBuilder(AuthorizationRequestUriBuilder authorizationRequestBuilder) {
|
||||
Assert.notNull(authorizationRequestBuilder, "authorizationRequestBuilder cannot be null");
|
||||
this.authorizationRequestBuilder = authorizationRequestBuilder;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(B http) throws Exception {
|
||||
AuthorizationCodeRequestRedirectFilter filter = new AuthorizationCodeRequestRedirectFilter(
|
||||
OAuth2LoginConfigurer.getClientRegistrationRepository(this.getBuilder()),
|
||||
this.getAuthorizationRequestBuilder());
|
||||
http.addFilter(this.postProcess(filter));
|
||||
}
|
||||
|
||||
private AuthorizationRequestUriBuilder getAuthorizationRequestBuilder() {
|
||||
if (this.authorizationRequestBuilder == null) {
|
||||
this.authorizationRequestBuilder = new DefaultAuthorizationRequestUriBuilder();
|
||||
}
|
||||
return this.authorizationRequestBuilder;
|
||||
}
|
||||
}
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configurers.oauth2.client;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeAuthenticationToken;
|
||||
import org.springframework.security.oauth2.client.authentication.AuthorizationCodeRequestRedirectFilter;
|
||||
import org.springframework.security.oauth2.client.authentication.AuthorizationGrantTokenExchanger;
|
||||
import org.springframework.security.oauth2.client.authentication.AuthorizationRequestUriBuilder;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.user.OAuth2UserService;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>> extends
|
||||
AbstractHttpConfigurer<OAuth2LoginConfigurer<B>, B> {
|
||||
|
||||
private final AuthorizationCodeRequestRedirectFilterConfigurer<B> authorizationCodeRequestRedirectFilterConfigurer;
|
||||
private final AuthorizationCodeAuthenticationFilterConfigurer<B> authorizationCodeAuthenticationFilterConfigurer;
|
||||
private final UserInfoEndpointConfig userInfoEndpointConfig;
|
||||
|
||||
public OAuth2LoginConfigurer() {
|
||||
this.authorizationCodeRequestRedirectFilterConfigurer = new AuthorizationCodeRequestRedirectFilterConfigurer<>();
|
||||
this.authorizationCodeAuthenticationFilterConfigurer = new AuthorizationCodeAuthenticationFilterConfigurer<>();
|
||||
this.userInfoEndpointConfig = new UserInfoEndpointConfig();
|
||||
}
|
||||
|
||||
public OAuth2LoginConfigurer<B> clients(ClientRegistration... clientRegistrations) {
|
||||
Assert.notEmpty(clientRegistrations, "clientRegistrations cannot be empty");
|
||||
return clients(new InMemoryClientRegistrationRepository(Arrays.asList(clientRegistrations)));
|
||||
}
|
||||
|
||||
public OAuth2LoginConfigurer<B> clients(ClientRegistrationRepository clientRegistrationRepository) {
|
||||
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
|
||||
Assert.notEmpty(clientRegistrationRepository.getRegistrations(), "clientRegistrationRepository cannot be empty");
|
||||
this.getBuilder().setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OAuth2LoginConfigurer<B> authorizationRequestBuilder(AuthorizationRequestUriBuilder authorizationRequestBuilder) {
|
||||
Assert.notNull(authorizationRequestBuilder, "authorizationRequestBuilder cannot be null");
|
||||
this.authorizationCodeRequestRedirectFilterConfigurer.authorizationRequestBuilder(authorizationRequestBuilder);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OAuth2LoginConfigurer<B> authorizationCodeTokenExchanger(
|
||||
AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger) {
|
||||
|
||||
Assert.notNull(authorizationCodeTokenExchanger, "authorizationCodeTokenExchanger cannot be null");
|
||||
this.authorizationCodeAuthenticationFilterConfigurer.authorizationCodeTokenExchanger(authorizationCodeTokenExchanger);
|
||||
return this;
|
||||
}
|
||||
|
||||
public UserInfoEndpointConfig userInfoEndpoint() {
|
||||
return this.userInfoEndpointConfig;
|
||||
}
|
||||
|
||||
public class UserInfoEndpointConfig {
|
||||
|
||||
private UserInfoEndpointConfig() {
|
||||
}
|
||||
|
||||
public OAuth2LoginConfigurer<B> userInfoService(OAuth2UserService userInfoService) {
|
||||
Assert.notNull(userInfoService, "userInfoService cannot be null");
|
||||
OAuth2LoginConfigurer.this.authorizationCodeAuthenticationFilterConfigurer.userInfoService(userInfoService);
|
||||
return this.and();
|
||||
}
|
||||
|
||||
public OAuth2LoginConfigurer<B> userInfoTypeConverter(Function<ClientHttpResponse, ? extends OAuth2User> userInfoConverter, URI userInfoUri) {
|
||||
Assert.notNull(userInfoConverter, "userInfoConverter cannot be null");
|
||||
Assert.notNull(userInfoUri, "userInfoUri cannot be null");
|
||||
OAuth2LoginConfigurer.this.authorizationCodeAuthenticationFilterConfigurer.userInfoTypeConverter(userInfoConverter, userInfoUri);
|
||||
return this.and();
|
||||
}
|
||||
|
||||
public OAuth2LoginConfigurer<B> and() {
|
||||
return OAuth2LoginConfigurer.this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(B http) throws Exception {
|
||||
this.authorizationCodeRequestRedirectFilterConfigurer.setBuilder(http);
|
||||
this.authorizationCodeAuthenticationFilterConfigurer.setBuilder(http);
|
||||
|
||||
this.authorizationCodeRequestRedirectFilterConfigurer.init(http);
|
||||
this.authorizationCodeAuthenticationFilterConfigurer.init(http);
|
||||
this.initDefaultLoginFilter(http);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(B http) throws Exception {
|
||||
this.authorizationCodeRequestRedirectFilterConfigurer.configure(http);
|
||||
this.authorizationCodeAuthenticationFilterConfigurer.configure(http);
|
||||
}
|
||||
|
||||
static <B extends HttpSecurityBuilder<B>> ClientRegistrationRepository getClientRegistrationRepository(B http) {
|
||||
ClientRegistrationRepository clientRegistrationRepository = http.getSharedObject(ClientRegistrationRepository.class);
|
||||
if (clientRegistrationRepository == null) {
|
||||
clientRegistrationRepository = getDefaultClientRegistrationRepository(http);
|
||||
http.setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository);
|
||||
}
|
||||
return clientRegistrationRepository;
|
||||
}
|
||||
|
||||
private static <B extends HttpSecurityBuilder<B>> ClientRegistrationRepository getDefaultClientRegistrationRepository(B http) {
|
||||
return http.getSharedObject(ApplicationContext.class).getBean(ClientRegistrationRepository.class);
|
||||
}
|
||||
|
||||
private void initDefaultLoginFilter(B http) {
|
||||
DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = http.getSharedObject(DefaultLoginPageGeneratingFilter.class);
|
||||
if (loginPageGeneratingFilter != null && !this.authorizationCodeAuthenticationFilterConfigurer.isCustomLoginPage()) {
|
||||
ClientRegistrationRepository clientRegistrationRepository = getClientRegistrationRepository(this.getBuilder());
|
||||
if (!CollectionUtils.isEmpty(clientRegistrationRepository.getRegistrations())) {
|
||||
Map<String, String> oauth2AuthenticationUrlToClientName = clientRegistrationRepository.getRegistrations().stream()
|
||||
.collect(Collectors.toMap(e -> AuthorizationCodeRequestRedirectFilter.AUTHORIZATION_BASE_URI + "/" + e.getClientAlias(),
|
||||
e -> e.getClientName()));
|
||||
loginPageGeneratingFilter.setOauth2LoginEnabled(true);
|
||||
loginPageGeneratingFilter.setOauth2AuthenticationUrlToClientName(oauth2AuthenticationUrlToClientName);
|
||||
loginPageGeneratingFilter.setLoginPageUrl(this.authorizationCodeAuthenticationFilterConfigurer.getLoginUrl());
|
||||
loginPageGeneratingFilter.setFailureUrl(this.authorizationCodeAuthenticationFilterConfigurer.getLoginFailureUrl());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web.reactive;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
@Import({HttpSecurityConfiguration.class, WebFluxSecurityConfiguration.class})
|
||||
@Configuration
|
||||
public @interface EnableWebFluxSecurity {
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web.reactive;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.core.ReactiveAdapterRegistry;
|
||||
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||
import org.springframework.security.authentication.UserDetailsRepositoryAuthenticationManager;
|
||||
import org.springframework.security.config.web.server.HttpSecurity;
|
||||
import org.springframework.security.core.userdetails.UserDetailsRepository;
|
||||
import org.springframework.security.web.reactive.result.method.annotation.AuthenticationPrincipalArgumentResolver;
|
||||
import org.springframework.security.web.server.context.WebSessionSecurityContextRepository;
|
||||
import org.springframework.web.reactive.config.WebFluxConfigurer;
|
||||
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
|
||||
|
||||
import static org.springframework.security.config.web.server.HttpSecurity.http;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public class HttpSecurityConfiguration implements WebFluxConfigurer {
|
||||
private static final String BEAN_NAME_PREFIX = "org.springframework.security.config.annotation.web.reactive.HttpSecurityConfiguration.";
|
||||
private static final String HTTPSECURITY_BEAN_NAME = BEAN_NAME_PREFIX + "httpSecurity";
|
||||
|
||||
@Autowired(required = false)
|
||||
private ReactiveAdapterRegistry adapterRegistry = new ReactiveAdapterRegistry();
|
||||
|
||||
@Autowired(required = false)
|
||||
private ReactiveAuthenticationManager authenticationManager;
|
||||
|
||||
@Autowired(required = false)
|
||||
private UserDetailsRepository userDetailsRepository;
|
||||
|
||||
@Override
|
||||
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
|
||||
configurer.addCustomResolver(authenticationPrincipalArgumentResolver());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationPrincipalArgumentResolver authenticationPrincipalArgumentResolver() {
|
||||
return new AuthenticationPrincipalArgumentResolver(adapterRegistry);
|
||||
}
|
||||
|
||||
@Bean(HTTPSECURITY_BEAN_NAME)
|
||||
@Scope("prototype")
|
||||
public HttpSecurity httpSecurity() {
|
||||
HttpSecurity http = http();
|
||||
http.httpBasic();
|
||||
http.authenticationManager(authenticationManager());
|
||||
http.securityContextRepository(new WebSessionSecurityContextRepository());
|
||||
return http;
|
||||
}
|
||||
|
||||
private ReactiveAuthenticationManager authenticationManager() {
|
||||
if(authenticationManager != null) {
|
||||
return authenticationManager;
|
||||
}
|
||||
if(userDetailsRepository != null) {
|
||||
return new UserDetailsRepositoryAuthenticationManager(userDetailsRepository);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web.reactive;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.web.server.HttpSecurity;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
import org.springframework.security.web.server.WebFilterChainFilter;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@Configuration
|
||||
public class WebFluxSecurityConfiguration {
|
||||
private static final String BEAN_NAME_PREFIX = "org.springframework.security.config.annotation.web.reactive.WebFluxSecurityConfiguration.";
|
||||
|
||||
private static final String SPRING_SECURITY_WEBFILTERCHAINFILTER_BEAN_NAME = BEAN_NAME_PREFIX + "WebFilterChainFilter";
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<SecurityWebFilterChain> securityWebFilterChains;
|
||||
|
||||
@Autowired
|
||||
ApplicationContext context;
|
||||
|
||||
@Bean(SPRING_SECURITY_WEBFILTERCHAINFILTER_BEAN_NAME)
|
||||
public WebFilterChainFilter springSecurityWebFilterChainFilter() {
|
||||
return WebFilterChainFilter.fromSecurityWebFilterChainsList(getSecurityWebFilterChains());
|
||||
}
|
||||
|
||||
private List<SecurityWebFilterChain> getSecurityWebFilterChains() {
|
||||
List<SecurityWebFilterChain> result = securityWebFilterChains;
|
||||
if(ObjectUtils.isEmpty(result)) {
|
||||
return defaultSecurityWebFilterChains();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<SecurityWebFilterChain> defaultSecurityWebFilterChains() {
|
||||
HttpSecurity http = context.getBean(HttpSecurity.class);
|
||||
http
|
||||
.authorizeExchange()
|
||||
.anyExchange().authenticated();
|
||||
return Arrays.asList(http.build());
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.core.userdetails;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.security.core.userdetails.MapUserDetailsRepository;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Constructs an {@link MapUserDetailsRepository} from a resource using {@link UserDetailsResourceFactoryBean}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
* @see UserDetailsResourceFactoryBean
|
||||
*/
|
||||
public class UserDetailsRepositoryResourceFactoryBean implements ResourceLoaderAware, FactoryBean<MapUserDetailsRepository> {
|
||||
private UserDetailsResourceFactoryBean userDetails = new UserDetailsResourceFactoryBean();
|
||||
|
||||
@Override
|
||||
public MapUserDetailsRepository getObject() throws Exception {
|
||||
Collection<UserDetails> users = userDetails.getObject();
|
||||
return new MapUserDetailsRepository(users);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return MapUserDetailsRepository.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
userDetails.setResourceLoader(resourceLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a the location of a Resource that is a Properties file in the format defined in {@link UserDetailsResourceFactoryBean}
|
||||
*
|
||||
* @param resourceLocation the location of the properties file that contains the users (i.e. "classpath:users.properties")
|
||||
* @return the UserDetailsResourceFactoryBean
|
||||
*/
|
||||
public void setResourceLocation(String resourceLocation) {
|
||||
this.userDetails.setResourceLocation(resourceLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a a Resource that is a Properties file in the format defined in {@link UserDetailsResourceFactoryBean}
|
||||
*
|
||||
* @param resource the Resource to use
|
||||
*/
|
||||
public void setResource(Resource resource) {
|
||||
this.userDetails.setResource(resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a UserDetailsRepositoryResourceFactoryBean with the location of a Resource that is a Properties file in the
|
||||
* format defined in {@link UserDetailsResourceFactoryBean}
|
||||
*
|
||||
* @param resourceLocatiton the location of the properties file that contains the users (i.e. "classpath:users.properties")
|
||||
* @return the UserDetailsResourceFactoryBean
|
||||
*/
|
||||
public static UserDetailsRepositoryResourceFactoryBean fromResourceLocation(String resourceLocatiton) {
|
||||
UserDetailsRepositoryResourceFactoryBean result = new UserDetailsRepositoryResourceFactoryBean();
|
||||
result.setResourceLocation(resourceLocatiton);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a UserDetailsRepositoryResourceFactoryBean with a Resource that is a Properties file in the
|
||||
* format defined in {@link UserDetailsResourceFactoryBean}
|
||||
*
|
||||
* @param propertiesResource the Resource that is a properties file that contains the users
|
||||
* @return the UserDetailsResourceFactoryBean
|
||||
*/
|
||||
public static UserDetailsRepositoryResourceFactoryBean fromResource(Resource propertiesResource) {
|
||||
UserDetailsRepositoryResourceFactoryBean result = new UserDetailsRepositoryResourceFactoryBean();
|
||||
result.setResource(propertiesResource);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.core.userdetails;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.memory.UserAttribute;
|
||||
import org.springframework.security.core.userdetails.memory.UserAttributeEditor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Parses a Resource that is a Properties file in the format of:
|
||||
*
|
||||
* <code>
|
||||
* username=password[,enabled|disabled],roles...
|
||||
* </code>
|
||||
*
|
||||
* The enabled and disabled properties are optional with enabled being the default. For example:
|
||||
*
|
||||
* <code>
|
||||
* user=password,ROLE_USER
|
||||
* admin=secret,ROLE_USER,ROLE_ADMIN
|
||||
* disabled_user=does_not_matter,disabled,ROLE_USER
|
||||
* </code>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public class UserDetailsResourceFactoryBean implements ResourceLoaderAware, FactoryBean<Collection<UserDetails>> {
|
||||
private ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
|
||||
private String resourceLocation;
|
||||
|
||||
private Resource resource;
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
Assert.notNull(resourceLoader,"resourceLoader cannot be null");
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<UserDetails> getObject() throws Exception {
|
||||
Properties userProperties = new Properties();
|
||||
Resource resource = getProperitesResource();
|
||||
try(InputStream in = resource.getInputStream()){
|
||||
userProperties.load(in);
|
||||
}
|
||||
|
||||
Collection<UserDetails> users = new ArrayList<>(userProperties.size());
|
||||
Enumeration<?> names = userProperties.propertyNames();
|
||||
UserAttributeEditor editor = new UserAttributeEditor();
|
||||
|
||||
while (names.hasMoreElements()) {
|
||||
String name = (String) names.nextElement();
|
||||
String property = userProperties.getProperty(name);
|
||||
editor.setAsText(property);
|
||||
UserAttribute attr = (UserAttribute) editor.getValue();
|
||||
if(attr == null) {
|
||||
throw new IllegalStateException("The entry with username '" + name + "' and value '" + property + "' could not be converted to a UserDetails.");
|
||||
}
|
||||
UserDetails user = User.withUsername(name)
|
||||
.password(attr.getPassword())
|
||||
.disabled(!attr.isEnabled())
|
||||
.authorities(attr.getAuthorities())
|
||||
.build();
|
||||
users.add(user);
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return Collection.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a the location of a Resource that is a Properties file in the format defined in {@link UserDetailsResourceFactoryBean}
|
||||
*
|
||||
* @param resourceLocation the location of the properties file that contains the users (i.e. "classpath:users.properties")
|
||||
*/
|
||||
public void setResourceLocation(String resourceLocation) {
|
||||
this.resourceLocation = resourceLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a a Resource that is a Properties file in the format defined in {@link UserDetailsResourceFactoryBean}
|
||||
*
|
||||
* @param resource the Resource to use
|
||||
*/
|
||||
public void setResource(Resource resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
private Resource getProperitesResource() {
|
||||
Resource result = resource;
|
||||
if(result == null && resourceLocation != null) {
|
||||
result = resourceLoader.getResource(resourceLocation);
|
||||
}
|
||||
Assert.notNull(result, "resource cannot be null if resourceLocation is null");
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a UserDetailsResourceFactoryBean with the location of a Resource that is a Properties file in the
|
||||
* format defined in {@link UserDetailsResourceFactoryBean}
|
||||
*
|
||||
* @param resourceLocatiton the location of the properties file that contains the users (i.e. "classpath:users.properties")
|
||||
* @return the UserDetailsResourceFactoryBean
|
||||
*/
|
||||
public static UserDetailsResourceFactoryBean fromResourceLocation(String resourceLocatiton) {
|
||||
UserDetailsResourceFactoryBean result = new UserDetailsResourceFactoryBean();
|
||||
result.setResourceLocation(resourceLocatiton);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a UserDetailsResourceFactoryBean with a Resource that is a Properties file in the
|
||||
* format defined in {@link UserDetailsResourceFactoryBean}
|
||||
*
|
||||
* @param propertiesResource the Resource that is a properties file that contains the users
|
||||
* @return the UserDetailsResourceFactoryBean
|
||||
*/
|
||||
public static UserDetailsResourceFactoryBean fromResource(Resource propertiesResource) {
|
||||
UserDetailsResourceFactoryBean result = new UserDetailsResourceFactoryBean();
|
||||
result.setResource(propertiesResource);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.provisioning;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.security.config.core.userdetails.UserDetailsResourceFactoryBean;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Constructs an {@link InMemoryUserDetailsManager} from a resource using {@link UserDetailsResourceFactoryBean}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
* @see UserDetailsResourceFactoryBean
|
||||
*/
|
||||
public class UserDetailsManagerResourceFactoryBean implements ResourceLoaderAware, FactoryBean<InMemoryUserDetailsManager> {
|
||||
private UserDetailsResourceFactoryBean userDetails = new UserDetailsResourceFactoryBean();
|
||||
|
||||
@Override
|
||||
public InMemoryUserDetailsManager getObject() throws Exception {
|
||||
Collection<UserDetails> users = userDetails.getObject();
|
||||
return new InMemoryUserDetailsManager(users);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return InMemoryUserDetailsManager.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
userDetails.setResourceLoader(resourceLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a the location of a Resource that is a Properties file in the format defined in {@link UserDetailsResourceFactoryBean}
|
||||
*
|
||||
* @param resourceLocation the location of the properties file that contains the users (i.e. "classpath:users.properties")
|
||||
* @return the UserDetailsResourceFactoryBean
|
||||
*/
|
||||
public void setResourceLocation(String resourceLocation) {
|
||||
this.userDetails.setResourceLocation(resourceLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a a Resource that is a Properties file in the format defined in {@link UserDetailsResourceFactoryBean}
|
||||
*
|
||||
* @param resource the Resource to use
|
||||
*/
|
||||
public void setResource(Resource resource) {
|
||||
this.userDetails.setResource(resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a UserDetailsServiceResourceFactoryBean with the location of a Resource that is a Properties file in the
|
||||
* format defined in {@link UserDetailsResourceFactoryBean}
|
||||
*
|
||||
* @param resourceLocation the location of the properties file that contains the users (i.e. "classpath:users.properties")
|
||||
* @return the UserDetailsResourceFactoryBean
|
||||
*/
|
||||
public static UserDetailsManagerResourceFactoryBean fromResourceLocation(String resourceLocation) {
|
||||
UserDetailsManagerResourceFactoryBean result = new UserDetailsManagerResourceFactoryBean();
|
||||
result.setResourceLocation(resourceLocation);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a UserDetailsServiceResourceFactoryBean with a Resource that is a Properties file in the
|
||||
* format defined in {@link UserDetailsResourceFactoryBean}
|
||||
*
|
||||
* @param resource the Resource that is a properties file that contains the users
|
||||
* @return the UserDetailsResourceFactoryBean
|
||||
*/
|
||||
public static UserDetailsManagerResourceFactoryBean fromResource(Resource resource) {
|
||||
UserDetailsManagerResourceFactoryBean result = new UserDetailsManagerResourceFactoryBean();
|
||||
result.setResource(resource);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.web.server;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.web.server.util.matcher.OrServerWebExchangeMatcher;
|
||||
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
|
||||
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
abstract class AbstractServerWebExchangeMatcherRegistry<T> {
|
||||
|
||||
/**
|
||||
* Maps any request.
|
||||
*
|
||||
* @return the object that is chained after creating the {@link ServerWebExchangeMatcher}
|
||||
*/
|
||||
public T anyExchange() {
|
||||
return matcher(ServerWebExchangeMatchers.anyExchange());
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of
|
||||
* {@link org.springframework.security.web.server.util.matcher.PathMatcherServerWebExchangeMatcher}
|
||||
* instances.
|
||||
*
|
||||
* @param method the {@link HttpMethod} to use for any
|
||||
* {@link HttpMethod}.
|
||||
*
|
||||
* @return the object that is chained after creating the {@link ServerWebExchangeMatcher}
|
||||
*/
|
||||
public T pathMatchers(HttpMethod method) {
|
||||
return pathMatchers(method, new String[] { "/**" });
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of
|
||||
* {@link org.springframework.security.web.server.util.matcher.PathMatcherServerWebExchangeMatcher}
|
||||
* instances.
|
||||
*
|
||||
* @param method the {@link HttpMethod} to use or {@code null} for any
|
||||
* {@link HttpMethod}.
|
||||
* @param antPatterns the ant patterns to create. If {@code null} or empty, then matches on nothing.
|
||||
* {@link org.springframework.security.web.server.util.matcher.PathMatcherServerWebExchangeMatcher} from
|
||||
*
|
||||
* @return the object that is chained after creating the {@link ServerWebExchangeMatcher}
|
||||
*/
|
||||
public T pathMatchers(HttpMethod method, String... antPatterns) {
|
||||
return matcher(ServerWebExchangeMatchers.pathMatchers(method, antPatterns));
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a {@link List} of
|
||||
* {@link org.springframework.security.web.server.util.matcher.PathMatcherServerWebExchangeMatcher}
|
||||
* instances that do not care which {@link HttpMethod} is used.
|
||||
*
|
||||
* @param antPatterns the ant patterns to create
|
||||
* {@link org.springframework.security.web.server.util.matcher.PathMatcherServerWebExchangeMatcher} from
|
||||
*
|
||||
* @return the object that is chained after creating the {@link ServerWebExchangeMatcher}
|
||||
*/
|
||||
public T pathMatchers(String... antPatterns) {
|
||||
return matcher(ServerWebExchangeMatchers.pathMatchers(antPatterns));
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates a list of {@link ServerWebExchangeMatcher} instances
|
||||
*
|
||||
* @param matchers the {@link ServerWebExchangeMatcher} instances
|
||||
*
|
||||
* @return the object that is chained after creating the {@link ServerWebExchangeMatcher}
|
||||
*/
|
||||
public T matchers(ServerWebExchangeMatcher... matchers) {
|
||||
return registerMatcher(new OrServerWebExchangeMatcher(matchers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses should implement this method for returning the object that is chained to
|
||||
* the creation of the {@link ServerWebExchangeMatcher} instances.
|
||||
*
|
||||
* @param matcher the {@link ServerWebExchangeMatcher} instances that were created
|
||||
* @return the chained Object for the subclass which allows association of something
|
||||
* else to the {@link ServerWebExchangeMatcher}
|
||||
*/
|
||||
protected abstract T registerMatcher(ServerWebExchangeMatcher matcher);
|
||||
|
||||
/**
|
||||
* Associates a {@link ServerWebExchangeMatcher} instances
|
||||
*
|
||||
* @param matcher the {@link ServerWebExchangeMatcher} instance
|
||||
*
|
||||
* @return the object that is chained after creating the {@link ServerWebExchangeMatcher}
|
||||
*/
|
||||
private T matcher(ServerWebExchangeMatcher matcher) {
|
||||
return registerMatcher(matcher);
|
||||
}
|
||||
}
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.web.server;
|
||||
|
||||
import org.springframework.security.web.server.header.CacheControlHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.CompositeHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.ContentTypeOptionsHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.HttpHeaderWriterWebFilter;
|
||||
import org.springframework.security.web.server.header.HttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.StrictTransportSecurityHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.XFrameOptionsHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.XXssProtectionHttpHeadersWriter;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public class HeaderBuilder {
|
||||
private final List<HttpHeadersWriter> writers;
|
||||
|
||||
private CacheControlHttpHeadersWriter cacheControl = new CacheControlHttpHeadersWriter();
|
||||
|
||||
private ContentTypeOptionsHttpHeadersWriter contentTypeOptions = new ContentTypeOptionsHttpHeadersWriter();
|
||||
|
||||
private StrictTransportSecurityHttpHeadersWriter hsts = new StrictTransportSecurityHttpHeadersWriter();
|
||||
|
||||
private XFrameOptionsHttpHeadersWriter frameOptions = new XFrameOptionsHttpHeadersWriter();
|
||||
|
||||
private XXssProtectionHttpHeadersWriter xss = new XXssProtectionHttpHeadersWriter();
|
||||
|
||||
public HeaderBuilder() {
|
||||
this.writers = new ArrayList<>(Arrays.asList(cacheControl, contentTypeOptions, hsts, frameOptions, xss));
|
||||
}
|
||||
|
||||
public CacheSpec cache() {
|
||||
return new CacheSpec();
|
||||
}
|
||||
|
||||
public ContentTypeOptionsSpec contentTypeOptions() {
|
||||
return new ContentTypeOptionsSpec();
|
||||
}
|
||||
|
||||
public FrameOptionsSpec frameOptions() {
|
||||
return new FrameOptionsSpec();
|
||||
}
|
||||
|
||||
public HstsSpec hsts() {
|
||||
return new HstsSpec();
|
||||
}
|
||||
|
||||
public HttpHeaderWriterWebFilter build() {
|
||||
HttpHeadersWriter writer = new CompositeHttpHeadersWriter(writers);
|
||||
return new HttpHeaderWriterWebFilter(writer);
|
||||
}
|
||||
|
||||
public XssProtectionSpec xssProtection() {
|
||||
return new XssProtectionSpec();
|
||||
}
|
||||
|
||||
public class CacheSpec {
|
||||
public void disable() {
|
||||
writers.remove(cacheControl);
|
||||
}
|
||||
|
||||
private CacheSpec() {}
|
||||
}
|
||||
|
||||
public class ContentTypeOptionsSpec {
|
||||
public void disable() {
|
||||
writers.remove(contentTypeOptions);
|
||||
}
|
||||
|
||||
private ContentTypeOptionsSpec() {}
|
||||
}
|
||||
|
||||
public class FrameOptionsSpec {
|
||||
public void mode(XFrameOptionsHttpHeadersWriter.Mode mode) {
|
||||
frameOptions.setMode(mode);
|
||||
}
|
||||
public void disable() {
|
||||
writers.remove(frameOptions);
|
||||
}
|
||||
|
||||
private FrameOptionsSpec() {}
|
||||
}
|
||||
|
||||
public class HstsSpec {
|
||||
public void maxAge(Duration maxAge) {
|
||||
hsts.setMaxAge(maxAge);
|
||||
}
|
||||
|
||||
public void includeSubdomains(boolean includeSubDomains) {
|
||||
hsts.setIncludeSubDomains(includeSubDomains);
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
writers.remove(hsts);
|
||||
}
|
||||
|
||||
private HstsSpec() {}
|
||||
}
|
||||
|
||||
public class XssProtectionSpec {
|
||||
public void disable() {
|
||||
writers.remove(xss);
|
||||
}
|
||||
|
||||
private XssProtectionSpec() {}
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.web.server;
|
||||
|
||||
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||
import org.springframework.security.web.server.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
|
||||
import org.springframework.security.web.server.HttpBasicAuthenticationConverter;
|
||||
import org.springframework.security.web.server.authentication.DefaultAuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.server.authentication.www.HttpBasicAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.server.context.SecurityContextRepository;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public class HttpBasicBuilder {
|
||||
private ReactiveAuthenticationManager authenticationManager;
|
||||
|
||||
private SecurityContextRepository securityContextRepository;
|
||||
|
||||
private AuthenticationEntryPoint entryPoint = new HttpBasicAuthenticationEntryPoint();
|
||||
|
||||
public HttpBasicBuilder authenticationManager(ReactiveAuthenticationManager authenticationManager) {
|
||||
this.authenticationManager = authenticationManager;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpBasicBuilder securityContextRepository(SecurityContextRepository securityContextRepository) {
|
||||
this.securityContextRepository = securityContextRepository;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthenticationWebFilter build() {
|
||||
AuthenticationWebFilter authenticationFilter = new AuthenticationWebFilter(authenticationManager);
|
||||
authenticationFilter.setEntryPoint(entryPoint);
|
||||
authenticationFilter.setAuthenticationConverter(new HttpBasicAuthenticationConverter());
|
||||
if(securityContextRepository != null) {
|
||||
DefaultAuthenticationSuccessHandler handler = new DefaultAuthenticationSuccessHandler();
|
||||
handler.setSecurityContextRepository(securityContextRepository);
|
||||
authenticationFilter.setAuthenticationSuccessHandler(handler);
|
||||
}
|
||||
return authenticationFilter;
|
||||
}
|
||||
}
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.web.server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||
import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
|
||||
import org.springframework.security.authorization.AuthorityAuthorizationManager;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.ReactiveAuthorizationManager;
|
||||
import org.springframework.security.web.server.MatcherSecurityWebFilterChain;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
import org.springframework.security.web.server.authorization.AuthorizationContext;
|
||||
import org.springframework.security.web.server.authorization.AuthorizationWebFilter;
|
||||
import org.springframework.security.web.server.authorization.DelegatingReactiveAuthorizationManager;
|
||||
import org.springframework.security.web.server.context.SecurityContextRepositoryWebFilter;
|
||||
import org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter;
|
||||
import org.springframework.security.web.server.context.SecurityContextRepository;
|
||||
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
|
||||
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcherEntry;
|
||||
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public class HttpSecurity {
|
||||
private ServerWebExchangeMatcher securityMatcher = ServerWebExchangeMatchers.anyExchange();
|
||||
|
||||
private AuthorizeExchangeBuilder authorizeExchangeBuilder;
|
||||
|
||||
private HeaderBuilder headers = new HeaderBuilder();
|
||||
private HttpBasicBuilder httpBasic;
|
||||
private ReactiveAuthenticationManager authenticationManager;
|
||||
|
||||
private Optional<SecurityContextRepository> securityContextRepository = Optional.empty();
|
||||
|
||||
/**
|
||||
* The ServerExchangeMatcher that determines which requests apply to this HttpSecurity instance.
|
||||
*
|
||||
* @param matcher the ServerExchangeMatcher that determines which requests apply to this HttpSecurity instance.
|
||||
* Default is all requests.
|
||||
*/
|
||||
public HttpSecurity securityMatcher(ServerWebExchangeMatcher matcher) {
|
||||
Assert.notNull(matcher, "matcher cannot be null");
|
||||
this.securityMatcher = matcher;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ServerExchangeMatcher that determines which requests apply to this HttpSecurity instance.
|
||||
* @return the ServerExchangeMatcher that determines which requests apply to this HttpSecurity instance.
|
||||
*/
|
||||
private ServerWebExchangeMatcher getSecurityMatcher() {
|
||||
return this.securityMatcher;
|
||||
}
|
||||
|
||||
public HttpSecurity securityContextRepository(SecurityContextRepository securityContextRepository) {
|
||||
Assert.notNull(securityContextRepository, "securityContextRepository cannot be null");
|
||||
this.securityContextRepository = Optional.of(securityContextRepository);
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpBasicBuilder httpBasic() {
|
||||
if(httpBasic == null) {
|
||||
httpBasic = new HttpBasicBuilder();
|
||||
}
|
||||
return httpBasic;
|
||||
}
|
||||
|
||||
public HeaderBuilder headers() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public AuthorizeExchangeBuilder authorizeExchange() {
|
||||
if(authorizeExchangeBuilder == null) {
|
||||
authorizeExchangeBuilder = new AuthorizeExchangeBuilder();
|
||||
}
|
||||
return authorizeExchangeBuilder;
|
||||
}
|
||||
|
||||
public HttpSecurity authenticationManager(ReactiveAuthenticationManager manager) {
|
||||
this.authenticationManager = manager;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SecurityWebFilterChain build() {
|
||||
List<WebFilter> filters = new ArrayList<>();
|
||||
if(headers != null) {
|
||||
filters.add(headers.build());
|
||||
}
|
||||
securityContextRepositoryWebFilter().ifPresent( f-> filters.add(f));
|
||||
if(httpBasic != null) {
|
||||
httpBasic.authenticationManager(authenticationManager);
|
||||
securityContextRepository.ifPresent( scr -> httpBasic.securityContextRepository(scr)) ;
|
||||
filters.add(httpBasic.build());
|
||||
}
|
||||
if(authorizeExchangeBuilder != null) {
|
||||
filters.add(new ExceptionTranslationWebFilter());
|
||||
filters.add(authorizeExchangeBuilder.build());
|
||||
}
|
||||
return new MatcherSecurityWebFilterChain(getSecurityMatcher(), filters);
|
||||
}
|
||||
|
||||
public static HttpSecurity http() {
|
||||
return new HttpSecurity();
|
||||
}
|
||||
|
||||
private Optional<SecurityContextRepositoryWebFilter> securityContextRepositoryWebFilter() {
|
||||
return securityContextRepository
|
||||
.flatMap( r -> Optional.of(new SecurityContextRepositoryWebFilter(r)));
|
||||
}
|
||||
|
||||
public class HttpBasicSpec extends HttpBasicBuilder {
|
||||
public HttpSecurity disable() {
|
||||
httpBasic = null;
|
||||
return HttpSecurity.this;
|
||||
}
|
||||
}
|
||||
|
||||
private HttpSecurity() {}
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public class AuthorizeExchangeBuilder extends AbstractServerWebExchangeMatcherRegistry<AuthorizeExchangeBuilder.Access> {
|
||||
private DelegatingReactiveAuthorizationManager.Builder managerBldr = DelegatingReactiveAuthorizationManager.builder();
|
||||
private ServerWebExchangeMatcher matcher;
|
||||
private boolean anyExchangeRegistered;
|
||||
|
||||
public HttpSecurity and() {
|
||||
return HttpSecurity.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Access anyExchange() {
|
||||
Access result = super.anyExchange();
|
||||
anyExchangeRegistered = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Access registerMatcher(ServerWebExchangeMatcher matcher) {
|
||||
if(anyExchangeRegistered) {
|
||||
throw new IllegalStateException("Cannot register " + matcher + " which would be unreachable because anyExchange() has already been registered.");
|
||||
}
|
||||
if(this.matcher != null) {
|
||||
throw new IllegalStateException("The matcher " + matcher + " does not have an access rule defined");
|
||||
}
|
||||
this.matcher = matcher;
|
||||
return new Access();
|
||||
}
|
||||
|
||||
protected WebFilter build() {
|
||||
if(this.matcher != null) {
|
||||
throw new IllegalStateException("The matcher " + matcher + " does not have an access rule defined");
|
||||
}
|
||||
return new AuthorizationWebFilter(managerBldr.build());
|
||||
}
|
||||
|
||||
public final class Access {
|
||||
|
||||
public AuthorizeExchangeBuilder permitAll() {
|
||||
return access( (a,e) -> Mono.just(new AuthorizationDecision(true)));
|
||||
}
|
||||
|
||||
public AuthorizeExchangeBuilder denyAll() {
|
||||
return access( (a,e) -> Mono.just(new AuthorizationDecision(false)));
|
||||
}
|
||||
|
||||
public AuthorizeExchangeBuilder hasRole(String role) {
|
||||
return access(AuthorityAuthorizationManager.hasRole(role));
|
||||
}
|
||||
|
||||
public AuthorizeExchangeBuilder hasAuthority(String authority) {
|
||||
return access(AuthorityAuthorizationManager.hasAuthority(authority));
|
||||
}
|
||||
|
||||
public AuthorizeExchangeBuilder authenticated() {
|
||||
return access(AuthenticatedAuthorizationManager.authenticated());
|
||||
}
|
||||
|
||||
public AuthorizeExchangeBuilder access(ReactiveAuthorizationManager<AuthorizationContext> manager) {
|
||||
managerBldr.add(new ServerWebExchangeMatcherEntry<>(matcher, manager));
|
||||
matcher = null;
|
||||
return AuthorizeExchangeBuilder.this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -346,7 +346,7 @@ public class NamespaceHttpTests extends BaseSpringSpec {
|
||||
}
|
||||
}
|
||||
|
||||
// http@request-matcher is not available (instead request matcher instances are used)
|
||||
// http@request-matcher is not available (instead request securityMatcher instances are used)
|
||||
|
||||
def "http@request-matcher-ref ant"() {
|
||||
when:
|
||||
|
||||
+2
-2
@@ -78,7 +78,7 @@ public class DefaultLoginPageConfigurerTests extends BaseSpringSpec {
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
|
||||
<p><font color='red'>Your login attempt was not successful, try again.<br/><br/>Reason: Bad credentials</font></p><h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
|
||||
<p style='color:red;'>Your login attempt was not successful, try again.<br/><br/>Reason: Bad credentials</p><h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
|
||||
<table>
|
||||
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
|
||||
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
|
||||
@@ -107,7 +107,7 @@ public class DefaultLoginPageConfigurerTests extends BaseSpringSpec {
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then: "sent to default success page"
|
||||
response.getContentAsString() == """<html><head><title>Login Page</title></head><body onload='document.f.username.focus();'>
|
||||
<p><font color='green'>You have been logged out</font></p><h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
|
||||
<p style='color:green;'>You have been logged out</p><h3>Login with Username and Password</h3><form name='f' action='/login' method='POST'>
|
||||
<table>
|
||||
<tr><td>User:</td><td><input type='text' name='username' value=''></td></tr>
|
||||
<tr><td>Password:</td><td><input type='password' name='password'/></td></tr>
|
||||
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -42,7 +42,6 @@ import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.codec.Base64;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint
|
||||
import org.springframework.security.web.FilterChainProxy
|
||||
import org.springframework.security.web.FilterInvocation
|
||||
|
||||
+1
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -38,7 +38,6 @@ import org.springframework.security.config.annotation.web.configuration.BaseWebC
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContextImpl
|
||||
import org.springframework.security.crypto.codec.Base64;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint
|
||||
import org.springframework.security.web.FilterChainProxy
|
||||
import org.springframework.security.web.FilterInvocation
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -28,7 +28,6 @@ import org.springframework.mock.web.MockHttpServletRequest
|
||||
import org.springframework.mock.web.MockHttpServletResponse
|
||||
import org.springframework.mock.web.MockServletContext
|
||||
import org.springframework.security.access.SecurityConfig
|
||||
import org.springframework.security.crypto.codec.Base64
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
@@ -383,7 +382,7 @@ class InterceptUrlConfigTests extends AbstractHttpConfigTests {
|
||||
|
||||
def login(MockHttpServletRequest request, String username, String password) {
|
||||
String toEncode = username + ':' + password
|
||||
request.addHeader('Authorization','Basic ' + new String(Base64.encode(toEncode.getBytes('UTF-8'))))
|
||||
request.addHeader('Authorization','Basic ' + Base64.encoder.encodeToString(toEncode.getBytes('UTF-8')))
|
||||
}
|
||||
|
||||
@RestController
|
||||
|
||||
+2
-2
@@ -26,10 +26,10 @@ import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.powermock.reflect.internal.WhiteboxImpl;
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
@@ -87,7 +87,7 @@ public class SecurityNamespaceHandlerTests {
|
||||
|
||||
Log logger = mock(Log.class);
|
||||
SecurityNamespaceHandler handler = new SecurityNamespaceHandler();
|
||||
WhiteboxImpl.setInternalState(handler, Log.class, logger);
|
||||
ReflectionTestUtils.setField(handler, "logger", logger);
|
||||
|
||||
handler.init();
|
||||
|
||||
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.annotation.web.reactive;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.runners.Enclosed;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.config.web.server.HttpSecurity;
|
||||
import org.springframework.security.core.userdetails.MapUserDetailsRepository;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetailsRepository;
|
||||
import org.springframework.security.test.web.reactive.server.WebTestClientBuilder;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
import org.springframework.security.web.server.WebFilterChainFilter;
|
||||
import org.springframework.security.web.server.util.matcher.PathMatcherServerWebExchangeMatcher;
|
||||
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@RunWith(Enclosed.class)
|
||||
public class EnableWebFluxSecurityTests {
|
||||
@RunWith(SpringRunner.class)
|
||||
public static class Defaults {
|
||||
@Autowired
|
||||
WebFilterChainFilter springSecurityFilterChain;
|
||||
|
||||
@Test
|
||||
public void defaultRequiresAuthentication() {
|
||||
WebTestClient client = WebTestClientBuilder.bindToWebFilters(springSecurityFilterChain).build();
|
||||
|
||||
client.get()
|
||||
.uri("/")
|
||||
.exchange()
|
||||
.expectStatus().isUnauthorized()
|
||||
.expectBody().isEmpty();
|
||||
}
|
||||
|
||||
@EnableWebFluxSecurity
|
||||
static class Config {
|
||||
@Bean
|
||||
public UserDetailsRepository userDetailsRepository() {
|
||||
return new MapUserDetailsRepository(User.withUsername("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
public static class MultiHttpSecurity {
|
||||
@Autowired
|
||||
WebFilterChainFilter springSecurityFilterChain;
|
||||
|
||||
@Test
|
||||
public void multiWorks() {
|
||||
WebTestClient client = WebTestClientBuilder.bindToWebFilters(springSecurityFilterChain).build();
|
||||
|
||||
client.get()
|
||||
.uri("/api/test")
|
||||
.exchange()
|
||||
.expectStatus().isUnauthorized()
|
||||
.expectBody().isEmpty();
|
||||
|
||||
client.get()
|
||||
.uri("/test")
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
}
|
||||
|
||||
@EnableWebFluxSecurity
|
||||
static class Config {
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
@Bean
|
||||
public SecurityWebFilterChain apiHttpSecurity(HttpSecurity http) {
|
||||
http
|
||||
.securityMatcher(new PathMatcherServerWebExchangeMatcher("/api/**"))
|
||||
.authorizeExchange()
|
||||
.anyExchange().denyAll();
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityWebFilterChain httpSecurity(HttpSecurity http) {
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UserDetailsRepository userDetailsRepository() {
|
||||
return new MapUserDetailsRepository(User.withUsername("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.core.userdetails;
|
||||
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.core.userdetails.UserDetailsRepository;
|
||||
import org.springframework.security.util.InMemoryResource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
public class UserDetailsRepositoryResourceFactoryBeanPropertiesResourceITests {
|
||||
@Autowired
|
||||
UserDetailsRepository users;
|
||||
|
||||
@Test
|
||||
public void loadUserByUsernameWhenUserFoundThenNotNull() {
|
||||
assertThat(users.findByUsername("user").block()).isNotNull();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
@Bean
|
||||
public UserDetailsRepositoryResourceFactoryBean userDetailsService() {
|
||||
return UserDetailsRepositoryResourceFactoryBean.fromResource(new InMemoryResource("user=password,ROLE_USER"));
|
||||
}
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.core.userdetails;
|
||||
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.core.userdetails.UserDetailsRepository;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
public class UserDetailsRepositoryResourceFactoryBeanPropertiesResourceLocationITests {
|
||||
@Autowired
|
||||
UserDetailsRepository users;
|
||||
|
||||
@Test
|
||||
public void loadUserByUsernameWhenUserFoundThenNotNull() {
|
||||
assertThat(users.findByUsername("user").block()).isNotNull();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
@Bean
|
||||
public UserDetailsRepositoryResourceFactoryBean userDetailsService() {
|
||||
return UserDetailsRepositoryResourceFactoryBean.fromResourceLocation("classpath:users.properties");
|
||||
}
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.core.userdetails;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.util.InMemoryResource;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class UserDetailsResourceFactoryBeanTest {
|
||||
@Mock
|
||||
ResourceLoader resourceLoader;
|
||||
|
||||
UserDetailsResourceFactoryBean factory = new UserDetailsResourceFactoryBean();
|
||||
|
||||
@Test
|
||||
public void setResourceLoaderWhenNullThenThrowsException() throws Exception {
|
||||
assertThatThrownBy(() -> factory.setResourceLoader(null) )
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasStackTraceContaining("resourceLoader cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getObjectWhenPropertiesResourceLocationNullThenThrowsIllegalStateException() throws Exception {
|
||||
factory.setResourceLoader(resourceLoader);
|
||||
|
||||
assertThatThrownBy(() -> factory.getObject() )
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasStackTraceContaining("resource cannot be null if resourceLocation is null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getObjectWhenPropertiesResourceLocationSingleUserThenThrowsGetsSingleUser() throws Exception {
|
||||
factory.setResourceLocation("classpath:users.properties");
|
||||
|
||||
Collection<UserDetails> users = factory.getObject();
|
||||
|
||||
assertLoaded();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getObjectWhenPropertiesResourceSingleUserThenThrowsGetsSingleUser() throws Exception {
|
||||
factory.setResource(new InMemoryResource("user=password,ROLE_USER"));
|
||||
|
||||
assertLoaded();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getObjectWhenInvalidUserThenThrowsMeaningfulException() throws Exception {
|
||||
factory.setResource(new InMemoryResource("user=invalidFormatHere"));
|
||||
|
||||
assertThatThrownBy(() -> factory.getObject() )
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasStackTraceContaining("user")
|
||||
.hasStackTraceContaining("invalidFormatHere");
|
||||
}
|
||||
|
||||
private void assertLoaded() throws Exception {
|
||||
Collection<UserDetails> users = factory.getObject();
|
||||
|
||||
UserDetails expectedUser = User.withUsername("user")
|
||||
.password("password")
|
||||
.authorities("ROLE_USER")
|
||||
.build();
|
||||
assertThat(users).containsExactly(expectedUser);
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -28,8 +28,8 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.internal.util.reflection.Whitebox;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.security.access.AccessDecisionManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
@@ -74,7 +74,8 @@ public class DefaultFilterChainValidatorTests {
|
||||
AnyRequestMatcher.INSTANCE, aaf, etf, fsi);
|
||||
fcp = new FilterChainProxy(securityChain);
|
||||
validator = new DefaultFilterChainValidator();
|
||||
Whitebox.setInternalState(validator, "logger", logger);
|
||||
|
||||
ReflectionTestUtils.setField(validator, "logger", logger);
|
||||
}
|
||||
|
||||
// SEC-1878
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
* Copyright 2012-2017 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.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.security.config.http;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Base64;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -31,7 +32,6 @@ import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
|
||||
import org.springframework.security.crypto.codec.Base64;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -87,7 +87,7 @@ public class NamespaceHttpBasicTests {
|
||||
// @formatter:on
|
||||
|
||||
this.request.addHeader("Authorization",
|
||||
"Basic " + new String(Base64.encode("user:test".getBytes("UTF-8"))));
|
||||
"Basic " + Base64.getEncoder().encodeToString("user:test".getBytes("UTF-8")));
|
||||
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
|
||||
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.provisioning;
|
||||
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.provisioning.UserDetailsManager;
|
||||
import org.springframework.security.util.InMemoryResource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
public class UserDetailsManagerResourceFactoryBeanPropertiesResourceITests {
|
||||
@Autowired
|
||||
UserDetailsManager users;
|
||||
|
||||
@Test
|
||||
public void loadUserByUsernameWhenUserFoundThenNotNull() {
|
||||
assertThat(users.loadUserByUsername("user")).isNotNull();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
@Bean
|
||||
public UserDetailsManagerResourceFactoryBean userDetailsService() {
|
||||
return UserDetailsManagerResourceFactoryBean.fromResource(new InMemoryResource("user=password,ROLE_USER"));
|
||||
}
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.provisioning;
|
||||
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.provisioning.UserDetailsManager;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
public class UserDetailsManagerResourceFactoryBeanPropertiesResourceLocationITests {
|
||||
@Autowired
|
||||
UserDetailsManager users;
|
||||
|
||||
@Test
|
||||
public void loadUserByUsernameWhenUserFoundThenNotNull() {
|
||||
assertThat(users.loadUserByUsername("user")).isNotNull();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
@Bean
|
||||
public UserDetailsManagerResourceFactoryBean userDetailsService() {
|
||||
return UserDetailsManagerResourceFactoryBean.fromResourceLocation("classpath:users.properties");
|
||||
}
|
||||
}
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.web.server;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.test.web.reactive.server.WebTestClientBuilder;
|
||||
import org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public class AuthorizeExchangeBuilderTests {
|
||||
HttpSecurity.AuthorizeExchangeBuilder authorization = HttpSecurity.http().new AuthorizeExchangeBuilder();
|
||||
|
||||
@Test
|
||||
public void antMatchersWhenMethodAndPatternsThenDiscriminatesByMethod() {
|
||||
authorization.pathMatchers(HttpMethod.POST, "/a", "/b").denyAll();
|
||||
authorization.anyExchange().permitAll();
|
||||
|
||||
WebTestClient client = buildClient();
|
||||
|
||||
client.get()
|
||||
.uri("/a")
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
|
||||
client.get()
|
||||
.uri("/b")
|
||||
.exchange()
|
||||
.expectStatus().isOk();
|
||||
|
||||
client.post()
|
||||
.uri("/a")
|
||||
.exchange()
|
||||
.expectStatus().isUnauthorized();
|
||||
|
||||
client.post()
|
||||
.uri("/b")
|
||||
.exchange()
|
||||
.expectStatus().isUnauthorized();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void antMatchersWhenPatternsThenAnyMethod() {
|
||||
authorization.pathMatchers("/a", "/b").denyAll();
|
||||
authorization.anyExchange().permitAll();
|
||||
|
||||
WebTestClient client = buildClient();
|
||||
|
||||
client.get()
|
||||
.uri("/a")
|
||||
.exchange()
|
||||
.expectStatus().isUnauthorized();
|
||||
|
||||
client.get()
|
||||
.uri("/b")
|
||||
.exchange()
|
||||
.expectStatus().isUnauthorized();
|
||||
|
||||
client.post()
|
||||
.uri("/a")
|
||||
.exchange()
|
||||
.expectStatus().isUnauthorized();
|
||||
|
||||
client.post()
|
||||
.uri("/b")
|
||||
.exchange()
|
||||
.expectStatus().isUnauthorized();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void antMatchersWhenNoAccessAndAnotherMatcherThenThrowsException() {
|
||||
authorization.pathMatchers("/incomplete");
|
||||
authorization.pathMatchers("/throws-exception");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void anyExchangeWhenFollowedByMatcherThenThrowsException() {
|
||||
authorization.anyExchange().denyAll();
|
||||
authorization.pathMatchers("/never-reached");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void buildWhenMatcherDefinedWithNoAccessThenThrowsException() {
|
||||
authorization.pathMatchers("/incomplete");
|
||||
authorization.build();
|
||||
}
|
||||
|
||||
private WebTestClient buildClient() {
|
||||
return WebTestClientBuilder.bindToWebFilters(new ExceptionTranslationWebFilter(), authorization.build()).build();
|
||||
}
|
||||
}
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.web.server;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.security.test.web.reactive.server.WebTestClientBuilder;
|
||||
import org.springframework.security.web.server.header.ContentTypeOptionsHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.StrictTransportSecurityHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.XFrameOptionsHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.XXssProtectionHttpHeadersWriter;
|
||||
import org.springframework.test.web.reactive.server.FluxExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public class HeaderBuilderTests {
|
||||
HeaderBuilder headers = new HeaderBuilder();
|
||||
|
||||
HttpHeaders expectedHeaders = new HttpHeaders();
|
||||
|
||||
Set<String> ignoredHeaderNames = Collections.singleton(HttpHeaders.CONTENT_TYPE);
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
expectedHeaders.add(StrictTransportSecurityHttpHeadersWriter.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains");
|
||||
expectedHeaders.add(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate");
|
||||
expectedHeaders.add(HttpHeaders.PRAGMA, "no-cache");
|
||||
expectedHeaders.add(HttpHeaders.EXPIRES, "0");
|
||||
expectedHeaders.add(ContentTypeOptionsHttpHeadersWriter.X_CONTENT_OPTIONS, "nosniff");
|
||||
expectedHeaders.add(XFrameOptionsHttpHeadersWriter.X_FRAME_OPTIONS, "DENY");
|
||||
expectedHeaders.add(XXssProtectionHttpHeadersWriter.X_XSS_PROTECTION, "1 ; mode=block");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headersWhenDefaultsThenAllDefaultsWritten() {
|
||||
assertHeaders();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headersWhenCacheDisableThenCacheNotWritten() {
|
||||
expectedHeaders.remove(HttpHeaders.CACHE_CONTROL);
|
||||
expectedHeaders.remove(HttpHeaders.PRAGMA);
|
||||
expectedHeaders.remove(HttpHeaders.EXPIRES);
|
||||
headers.cache().disable();
|
||||
|
||||
assertHeaders();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headersWhenContentOptionsDisableThenContentTypeOptionsNotWritten() {
|
||||
expectedHeaders.remove(ContentTypeOptionsHttpHeadersWriter.X_CONTENT_OPTIONS);
|
||||
headers.contentTypeOptions().disable();
|
||||
|
||||
assertHeaders();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headersWhenHstsDisableThenHstsNotWritten() {
|
||||
expectedHeaders.remove(StrictTransportSecurityHttpHeadersWriter.STRICT_TRANSPORT_SECURITY);
|
||||
headers.hsts().disable();
|
||||
|
||||
assertHeaders();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headersWhenHstsCustomThenCustomHstsWritten() {
|
||||
expectedHeaders.remove(StrictTransportSecurityHttpHeadersWriter.STRICT_TRANSPORT_SECURITY);
|
||||
expectedHeaders.add(StrictTransportSecurityHttpHeadersWriter.STRICT_TRANSPORT_SECURITY, "max-age=60");
|
||||
headers.hsts().maxAge(Duration.ofSeconds(60));
|
||||
headers.hsts().includeSubdomains(false);
|
||||
|
||||
assertHeaders();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headersWhenFrameOptionsDisableThenFrameOptionsNotWritten() {
|
||||
expectedHeaders.remove(XFrameOptionsHttpHeadersWriter.X_FRAME_OPTIONS);
|
||||
headers.frameOptions().disable();
|
||||
|
||||
assertHeaders();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headersWhenFrameOptionsModeThenFrameOptionsCustomMode() {
|
||||
expectedHeaders.remove(XFrameOptionsHttpHeadersWriter.X_FRAME_OPTIONS);
|
||||
expectedHeaders.add(XFrameOptionsHttpHeadersWriter.X_FRAME_OPTIONS, "SAMEORIGIN");
|
||||
headers.frameOptions().mode(XFrameOptionsHttpHeadersWriter.Mode.SAMEORIGIN);
|
||||
|
||||
assertHeaders();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headersWhenXssProtectionDisableThenXssProtectionNotWritten() {
|
||||
expectedHeaders.remove("X-Xss-Protection");
|
||||
headers.xssProtection().disable();
|
||||
|
||||
assertHeaders();
|
||||
}
|
||||
|
||||
private void assertHeaders() {
|
||||
WebTestClient client = buildClient();
|
||||
FluxExchangeResult<String> response = client.get()
|
||||
.uri("https://example.com/")
|
||||
.exchange()
|
||||
.returnResult(String.class);
|
||||
|
||||
Map<String,List<String>> responseHeaders = response.getResponseHeaders();
|
||||
ignoredHeaderNames.stream().forEach(responseHeaders::remove);
|
||||
|
||||
assertThat(responseHeaders).describedAs(response.toString()).isEqualTo(expectedHeaders);
|
||||
}
|
||||
|
||||
private WebTestClient buildClient() {
|
||||
return WebTestClientBuilder.bindToWebFilters(headers.build()).build();
|
||||
}
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.config.web.server;
|
||||
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.test.web.reactive.server.WebTestClientBuilder;
|
||||
import org.springframework.security.web.server.WebFilterChainFilter;
|
||||
import org.springframework.security.web.server.context.SecurityContextRepository;
|
||||
import org.springframework.security.web.server.context.WebSessionSecurityContextRepository;
|
||||
import org.springframework.test.web.reactive.server.EntityExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.FluxExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
import static org.springframework.web.reactive.function.client.ExchangeFilterFunctions.basicAuthentication;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class HttpSecurityTests {
|
||||
@Mock
|
||||
SecurityContextRepository contextRepository;
|
||||
@Mock
|
||||
ReactiveAuthenticationManager authenticationManager;
|
||||
|
||||
HttpSecurity http;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
http = HttpSecurity.http();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaults() {
|
||||
http.securityContextRepository(this.contextRepository);
|
||||
|
||||
WebTestClient client = buildClient();
|
||||
|
||||
FluxExchangeResult<String> result = client.get()
|
||||
.uri("/")
|
||||
.exchange()
|
||||
.expectHeader().valueMatches(HttpHeaders.CACHE_CONTROL, ".+")
|
||||
.returnResult(String.class);
|
||||
|
||||
assertThat(result.getResponseCookies()).isEmpty();
|
||||
// there is no need to try and load the SecurityContext by default
|
||||
verifyZeroInteractions(contextRepository);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basic() {
|
||||
given(this.authenticationManager.authenticate(any())).willReturn(Mono.just(new TestingAuthenticationToken("rob", "rob", "ROLE_USER", "ROLE_ADMIN")));
|
||||
|
||||
http.securityContextRepository(new WebSessionSecurityContextRepository());
|
||||
http.httpBasic();
|
||||
http.authenticationManager(authenticationManager);
|
||||
HttpSecurity.AuthorizeExchangeBuilder authorize = http.authorizeExchange();
|
||||
authorize.anyExchange().authenticated();
|
||||
|
||||
WebTestClient client = buildClient();
|
||||
|
||||
EntityExchangeResult<String> result = client
|
||||
.filter(basicAuthentication("rob", "rob"))
|
||||
.get()
|
||||
.uri("/")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().valueMatches(HttpHeaders.CACHE_CONTROL, ".+")
|
||||
.expectBody(String.class).consumeWith(b -> assertThat(b.getResponseBody()).isEqualTo("ok"))
|
||||
.returnResult();
|
||||
|
||||
assertThat(result.getResponseCookies().getFirst("SESSION")).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicWhenNoCredentialsThenUnauthorized() {
|
||||
http.authorizeExchange().anyExchange().authenticated();
|
||||
|
||||
WebTestClient client = buildClient();
|
||||
client
|
||||
.get()
|
||||
.uri("/")
|
||||
.exchange()
|
||||
.expectStatus().isUnauthorized()
|
||||
.expectHeader().valueMatches(HttpHeaders.CACHE_CONTROL, ".+")
|
||||
.expectBody().isEmpty();
|
||||
}
|
||||
|
||||
private WebTestClient buildClient() {
|
||||
WebFilterChainFilter springSecurityFilterChain = WebFilterChainFilter.fromSecurityWebFilterChains(http.build());
|
||||
return WebTestClientBuilder.bindToWebFilters(springSecurityFilterChain).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#
|
||||
# /*
|
||||
# * Copyright 2002-2017 the original author or authors.
|
||||
# *
|
||||
# * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# * you may not use this file except in compliance with the License.
|
||||
# * You may obtain a copy of the License at
|
||||
# *
|
||||
# * http://www.apache.org/licenses/LICENSE-2.0
|
||||
# *
|
||||
# * Unless required by applicable law or agreed to in writing, software
|
||||
# * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# * See the License for the specific language governing permissions and
|
||||
# * limitations under the License.
|
||||
# */
|
||||
#
|
||||
|
||||
user=password,ROLE_USER
|
||||
@@ -1,53 +0,0 @@
|
||||
// Core build file
|
||||
|
||||
// We don't define a module dependency on crypto to avoid creating a transitive dependency
|
||||
def cryptoProject = project(':spring-security-crypto')
|
||||
def cryptoClasses = cryptoProject.sourceSets.main.output
|
||||
|
||||
configurations {
|
||||
included
|
||||
|
||||
compile.extendsFrom included
|
||||
|
||||
testCompile.exclude group: 'org.mockito', module: 'mockito-all'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile springCoreDependency,
|
||||
'aopalliance:aopalliance:1.0',
|
||||
"org.springframework:spring-aop:$springVersion",
|
||||
"org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
"org.springframework:spring-expression:$springVersion"
|
||||
|
||||
optional "net.sf.ehcache:ehcache:$ehcacheVersion",
|
||||
'javax.annotation:jsr250-api:1.0',
|
||||
"org.aspectj:aspectjrt:$aspectjVersion",
|
||||
"org.springframework:spring-jdbc:$springVersion",
|
||||
"org.springframework:spring-tx:$springVersion",
|
||||
"com.fasterxml.jackson.core:jackson-databind:$jacksonDatabindVersion"
|
||||
|
||||
included cryptoProject
|
||||
|
||||
testCompile "commons-collections:commons-collections:$commonsCollectionsVersion",
|
||||
"org.springframework:spring-test:$springVersion",
|
||||
"org.slf4j:jcl-over-slf4j:$slf4jVersion",
|
||||
powerMockDependencies,
|
||||
"org.skyscreamer:jsonassert:$jsonassertVersion"
|
||||
|
||||
testRuntime "org.hsqldb:hsqldb:$hsqlVersion"
|
||||
}
|
||||
|
||||
classes.doLast {
|
||||
copy {
|
||||
from cryptoClasses
|
||||
into sourceSets.main.output.classesDir
|
||||
}
|
||||
}
|
||||
|
||||
sourceJar.from cryptoProject.sourceSets.main.java
|
||||
|
||||
configure(project.tasks.withType(Test)) {
|
||||
systemProperties['springSecurityVersion'] = version
|
||||
systemProperties['springVersion'] = springVersion
|
||||
}
|
||||
-314
@@ -1,314 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<name>spring-security-core</name>
|
||||
<description>spring-security-core</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
<organization>
|
||||
<name>spring.io</name>
|
||||
<url>http://spring.io/</url>
|
||||
</organization>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>rwinch</id>
|
||||
<name>Rob Winch</name>
|
||||
<email>rwinch@gopivotal.com</email>
|
||||
</developer>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
|
||||
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
|
||||
<url>https://github.com/spring-projects/spring-security</url>
|
||||
</scm>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>4.3.5.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>aopalliance</groupId>
|
||||
<artifactId>aopalliance</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-expression</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.8.4</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>1.2</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>jsr250-api</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
<version>2.9.0</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<version>1.8.4</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
<version>3.2.2</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<groupId>org.mockito</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<groupId>org.mockito</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>2.2.0</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<groupId>org.mockito</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<groupId>org.mockito</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-mockito</artifactId>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<groupId>org.mockito</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-support</artifactId>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<groupId>org.mockito</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-core</artifactId>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<groupId>org.mockito</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4</artifactId>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<groupId>org.mockito</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4-common</artifactId>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<groupId>org.mockito</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-reflect</artifactId>
|
||||
<version>1.6.2</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<groupId>org.mockito</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.skyscreamer</groupId>
|
||||
<artifactId>jsonassert</artifactId>
|
||||
<version>1.3.0</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<groupId>org.mockito</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>1.7.7</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<groupId>org.mockito</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<groupId>org.mockito</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,50 @@
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
|
||||
def includeProject = project(':spring-security-crypto')
|
||||
|
||||
configurations {
|
||||
included
|
||||
compile.extendsFrom included
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'aopalliance:aopalliance'
|
||||
compile 'org.springframework:spring-aop'
|
||||
compile 'org.springframework:spring-beans'
|
||||
compile 'org.springframework:spring-context'
|
||||
compile 'org.springframework:spring-core'
|
||||
compile 'org.springframework:spring-expression'
|
||||
|
||||
included includeProject
|
||||
|
||||
optional 'com.fasterxml.jackson.core:jackson-databind'
|
||||
optional 'io.projectreactor:reactor-core'
|
||||
optional 'javax.annotation:jsr250-api'
|
||||
optional 'net.sf.ehcache:ehcache'
|
||||
optional 'org.aspectj:aspectjrt'
|
||||
optional 'org.springframework:spring-jdbc'
|
||||
optional 'org.springframework:spring-tx'
|
||||
|
||||
testCompile powerMockDependencies
|
||||
testCompile 'commons-collections:commons-collections'
|
||||
testCompile 'io.projectreactor:reactor-test'
|
||||
testCompile 'org.skyscreamer:jsonassert'
|
||||
testCompile 'org.slf4j:jcl-over-slf4j'
|
||||
testCompile 'org.springframework:spring-test'
|
||||
|
||||
testRuntime 'org.hsqldb:hsqldb'
|
||||
}
|
||||
|
||||
classes.doLast {
|
||||
copy {
|
||||
from includeProject.sourceSets.main.output
|
||||
into sourceSets.main.output.classesDir
|
||||
}
|
||||
}
|
||||
|
||||
tasks.sourcesJar.from {includeProject.sourceSets.main.java}
|
||||
|
||||
configure(project.tasks.withType(Test)) {
|
||||
systemProperties['springSecurityVersion'] = version
|
||||
systemProperties['springVersion'] = project.dependencyManagement.managedVersions['org.springframework:spring-core']
|
||||
}
|
||||
+3
-3
@@ -24,8 +24,8 @@ import java.util.Collections;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.CredentialsContainer;
|
||||
import org.springframework.security.core.AuthenticatedPrincipal;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
/**
|
||||
* Base class for <code>Authentication</code> objects.
|
||||
@@ -79,8 +79,8 @@ public abstract class AbstractAuthenticationToken implements Authentication,
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
if (this.getPrincipal() instanceof UserDetails) {
|
||||
return ((UserDetails) this.getPrincipal()).getUsername();
|
||||
if (this.getPrincipal() instanceof AuthenticatedPrincipal) {
|
||||
return ((AuthenticatedPrincipal) this.getPrincipal()).getName();
|
||||
}
|
||||
|
||||
if (getPrincipal() instanceof Principal) {
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.authentication;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public interface ReactiveAuthenticationManager {
|
||||
|
||||
Mono<Authentication> authenticate(Authentication authentication);
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.authentication;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
|
||||
/**
|
||||
* Adapts an AuthenticationManager to the reactive APIs. This is somewhat necessary because many of the ways that
|
||||
* credentials are stored (i.e. JDBC, LDAP, etc) do not have reactive implementations. What's more is it is generally
|
||||
* considered best practice to store passwords in a hash that is intentionally slow which would block ever request
|
||||
* from coming in unless it was put on another thread.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public class ReactiveAuthenticationManagerAdapter implements ReactiveAuthenticationManager {
|
||||
private final AuthenticationManager authenticationManager;
|
||||
|
||||
public ReactiveAuthenticationManagerAdapter(AuthenticationManager authenticationManager) {
|
||||
Assert.notNull(authenticationManager, "authenticationManager cannot be null");
|
||||
this.authenticationManager = authenticationManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Authentication> authenticate(Authentication token) {
|
||||
return Mono.just(token)
|
||||
.publishOn(Schedulers.elastic())
|
||||
.flatMap( t -> {
|
||||
try {
|
||||
return Mono.just(authenticationManager.authenticate(t));
|
||||
} catch(Throwable error) {
|
||||
return Mono.error(error);
|
||||
}
|
||||
})
|
||||
.filter( a -> a.isAuthenticated());
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.authentication;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
import org.springframework.security.core.userdetails.UserDetailsRepository;
|
||||
import org.springframework.util.Assert;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public class UserDetailsRepositoryAuthenticationManager implements ReactiveAuthenticationManager {
|
||||
private final UserDetailsRepository repository;
|
||||
|
||||
public UserDetailsRepositoryAuthenticationManager(UserDetailsRepository userDetailsRepository) {
|
||||
Assert.notNull(userDetailsRepository, "userDetailsRepository cannot be null");
|
||||
this.repository = userDetailsRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Authentication> authenticate(Authentication authentication) {
|
||||
final String username = authentication.getName();
|
||||
return repository
|
||||
.findByUsername(username)
|
||||
.filter( u -> u.getPassword().equals(authentication.getCredentials()))
|
||||
.switchIfEmpty( Mono.error(new BadCredentialsException("Invalid Credentials")) )
|
||||
.map( u -> new UsernamePasswordAuthenticationToken(u, u.getPassword(), u.getAuthorities()) );
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -17,8 +17,8 @@
|
||||
package org.springframework.security.authentication.encoding;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Base64;
|
||||
|
||||
import org.springframework.security.crypto.codec.Base64;
|
||||
import org.springframework.security.crypto.codec.Utf8;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -107,13 +107,13 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
|
||||
prefix = forceLowerCasePrefix ? SSHA_PREFIX_LC : SSHA_PREFIX;
|
||||
}
|
||||
|
||||
return prefix + Utf8.decode(Base64.encode(hash));
|
||||
return prefix + Utf8.decode(Base64.getEncoder().encode(hash));
|
||||
}
|
||||
|
||||
private byte[] extractSalt(String encPass) {
|
||||
String encPassNoLabel = encPass.substring(6);
|
||||
|
||||
byte[] hashAndSalt = Base64.decode(encPassNoLabel.getBytes());
|
||||
byte[] hashAndSalt = Base64.getDecoder().decode(encPassNoLabel.getBytes());
|
||||
int saltLength = hashAndSalt.length - SHA_LENGTH;
|
||||
byte[] salt = new byte[saltLength];
|
||||
System.arraycopy(hashAndSalt, SHA_LENGTH, salt, 0, saltLength);
|
||||
|
||||
+3
-2
@@ -15,7 +15,8 @@
|
||||
*/
|
||||
package org.springframework.security.authentication.encoding;
|
||||
|
||||
import org.springframework.security.crypto.codec.Base64;
|
||||
import java.util.Base64;
|
||||
|
||||
import org.springframework.security.crypto.codec.Hex;
|
||||
import org.springframework.security.crypto.codec.Utf8;
|
||||
|
||||
@@ -57,7 +58,7 @@ public class Md4PasswordEncoder extends BaseDigestPasswordEncoder {
|
||||
byte[] resBuf = md4.digest();
|
||||
|
||||
if (getEncodeHashAsBase64()) {
|
||||
return Utf8.decode(Base64.encode(resBuf));
|
||||
return Utf8.decode(Base64.getEncoder().encode(resBuf));
|
||||
}
|
||||
else {
|
||||
return new String(Hex.encode(resBuf));
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -17,8 +17,8 @@ package org.springframework.security.authentication.encoding;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Base64;
|
||||
|
||||
import org.springframework.security.crypto.codec.Base64;
|
||||
import org.springframework.security.crypto.codec.Hex;
|
||||
import org.springframework.security.crypto.codec.Utf8;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -106,7 +106,7 @@ public class MessageDigestPasswordEncoder extends BaseDigestPasswordEncoder {
|
||||
}
|
||||
|
||||
if (getEncodeHashAsBase64()) {
|
||||
return Utf8.decode(Base64.encode(digest));
|
||||
return Utf8.decode(Base64.getEncoder().encode(digest));
|
||||
}
|
||||
else {
|
||||
return new String(Hex.encode(digest));
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.authorization;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public class AuthenticatedAuthorizationManager<T> implements ReactiveAuthorizationManager<T> {
|
||||
|
||||
@Override
|
||||
public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, T object) {
|
||||
return authentication
|
||||
.map(a -> new AuthorizationDecision(a.isAuthenticated()))
|
||||
.defaultIfEmpty(new AuthorizationDecision(false));
|
||||
}
|
||||
|
||||
public static <T> AuthenticatedAuthorizationManager<T> authenticated() {
|
||||
return new AuthenticatedAuthorizationManager<>();
|
||||
}
|
||||
|
||||
private AuthenticatedAuthorizationManager() {}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.authorization;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public class AuthorityAuthorizationManager<T> implements ReactiveAuthorizationManager<T> {
|
||||
private final String authority;
|
||||
|
||||
private AuthorityAuthorizationManager(String authority) {
|
||||
this.authority = authority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<AuthorizationDecision> check(Mono<Authentication> authentication, T object) {
|
||||
return authentication
|
||||
.filter(a -> a.isAuthenticated())
|
||||
.flatMapIterable( a -> a.getAuthorities())
|
||||
.map( g-> g.getAuthority())
|
||||
.hasElement(this.authority)
|
||||
.map( hasAuthority -> new AuthorizationDecision(hasAuthority))
|
||||
.defaultIfEmpty(new AuthorizationDecision(false));
|
||||
}
|
||||
|
||||
public static <T> AuthorityAuthorizationManager<T> hasAuthority(String authority) {
|
||||
Assert.notNull(authority, "authority cannot be null");
|
||||
return new AuthorityAuthorizationManager<>(authority);
|
||||
}
|
||||
|
||||
public static <T> AuthorityAuthorizationManager<T> hasRole(String role) {
|
||||
Assert.notNull(role, "role cannot be null");
|
||||
return hasAuthority("ROLE_" + role);
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.authorization;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public class AuthorizationDecision {
|
||||
private final boolean granted;
|
||||
|
||||
public AuthorizationDecision(boolean granted) {
|
||||
this.granted = granted;
|
||||
}
|
||||
|
||||
public boolean isGranted() {
|
||||
return granted;
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
package org.springframework.security.authorization;
|
||||
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public interface ReactiveAuthorizationManager<T> {
|
||||
Mono<AuthorizationDecision> check(Mono<Authentication> authentication, T object);
|
||||
|
||||
default Mono<Void> verify(Mono<Authentication> authentication, T object) {
|
||||
return check(authentication, object)
|
||||
.filter( d -> d.isGranted())
|
||||
.switchIfEmpty( Mono.error(new AccessDeniedException("Access Denied")) )
|
||||
.flatMap( d -> Mono.empty() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.core;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
|
||||
/**
|
||||
* Representation of an authenticated <code>Principal</code> once an
|
||||
* {@link Authentication} request has been successfully authenticated
|
||||
* by the {@link AuthenticationManager#authenticate(Authentication)} method.
|
||||
*
|
||||
* Implementors typically provide their own representation of a <code>Principal</code>,
|
||||
* which usually contains information describing the <code>Principal</code> entity,
|
||||
* such as, first/middle/last name, address, email, phone, id, etc.
|
||||
*
|
||||
* This interface allows implementors to expose specific attributes
|
||||
* of their custom representation of <code>Principal</code> in a generic way.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @since 5.0
|
||||
* @see Authentication#getPrincipal()
|
||||
* @see org.springframework.security.core.userdetails.UserDetails
|
||||
*/
|
||||
public interface AuthenticatedPrincipal {
|
||||
|
||||
/**
|
||||
* Returns the name of the authenticated <code>Principal</code>. Never <code>null</code>.
|
||||
*
|
||||
* @return the name of the authenticated <code>Principal</code>
|
||||
*/
|
||||
String getName();
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -38,9 +38,9 @@ public class SpringSecurityCoreVersion {
|
||||
* N.B. Classes are not intended to be serializable between different versions. See
|
||||
* SEC-1709 for why we still need a serial version.
|
||||
*/
|
||||
public static final long SERIAL_VERSION_UID = 420L;
|
||||
public static final long SERIAL_VERSION_UID = 500L;
|
||||
|
||||
static final String MIN_SPRING_VERSION = "4.3.5.RELEASE";
|
||||
static final String MIN_SPRING_VERSION = "5.0.0.RC2";
|
||||
|
||||
static {
|
||||
performVersionChecks();
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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,10 +16,10 @@
|
||||
package org.springframework.security.core.token;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Base64;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.security.crypto.codec.Base64;
|
||||
import org.springframework.security.crypto.codec.Hex;
|
||||
import org.springframework.security.crypto.codec.Utf8;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -89,7 +89,7 @@ public class KeyBasedPersistenceTokenService implements TokenService, Initializi
|
||||
// Compute key
|
||||
String sha512Hex = Sha512DigestUtils.shaHex(content + ":" + serverSecret);
|
||||
String keyPayload = content + ":" + sha512Hex;
|
||||
String key = Utf8.decode(Base64.encode(Utf8.encode(keyPayload)));
|
||||
String key = Utf8.decode(Base64.getEncoder().encode(Utf8.encode(keyPayload)));
|
||||
|
||||
return new DefaultToken(key, creationTime, extendedInformation);
|
||||
}
|
||||
@@ -99,7 +99,7 @@ public class KeyBasedPersistenceTokenService implements TokenService, Initializi
|
||||
return null;
|
||||
}
|
||||
String[] tokens = StringUtils.delimitedListToStringArray(
|
||||
Utf8.decode(Base64.decode(Utf8.encode(key))), ":");
|
||||
Utf8.decode(Base64.getDecoder().decode(Utf8.encode(key))), ":");
|
||||
Assert.isTrue(tokens.length >= 4, "Expected 4 or more tokens but found "
|
||||
+ tokens.length);
|
||||
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.core.userdetails;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public class MapUserDetailsRepository implements UserDetailsRepository {
|
||||
private final Map<String,UserDetails> users;
|
||||
|
||||
public MapUserDetailsRepository(Map<String,UserDetails> users) {
|
||||
this.users = users;
|
||||
}
|
||||
|
||||
public MapUserDetailsRepository(UserDetails... users) {
|
||||
this(Arrays.asList(users));
|
||||
}
|
||||
|
||||
public MapUserDetailsRepository(Collection<UserDetails> users) {
|
||||
Assert.notEmpty(users, "users cannot be null or empty");
|
||||
this.users = users.stream().collect(Collectors.toMap( u -> getKey(u.getName()), Function.identity()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<UserDetails> findByUsername(String username) {
|
||||
String key = getKey(username);
|
||||
UserDetails result = users.get(key);
|
||||
return result == null ? Mono.empty() : Mono.just(User.withUserDetails(result).build());
|
||||
}
|
||||
|
||||
private String getKey(String username) {
|
||||
return username.toLowerCase();
|
||||
}
|
||||
}
|
||||
@@ -248,6 +248,16 @@ public class User implements UserDetails, CredentialsContainer {
|
||||
return new UserBuilder().username(username);
|
||||
}
|
||||
|
||||
public static UserBuilder withUserDetails(UserDetails userDetails) {
|
||||
return withUsername(userDetails.getUsername())
|
||||
.password(userDetails.getPassword())
|
||||
.accountExpired(!userDetails.isAccountNonExpired())
|
||||
.accountLocked(!userDetails.isAccountNonLocked())
|
||||
.authorities(userDetails.getAuthorities())
|
||||
.credentialsExpired(!userDetails.isCredentialsNonExpired())
|
||||
.disabled(!userDetails.isEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the user to be added. At minimum the username, password, and authorities
|
||||
* should provided. The remaining attributes have reasonable defaults.
|
||||
@@ -351,7 +361,7 @@ public class User implements UserDetails, CredentialsContainer {
|
||||
* additional attributes for this user)
|
||||
* @see #roles(String...)
|
||||
*/
|
||||
public UserBuilder authorities(List<? extends GrantedAuthority> authorities) {
|
||||
public UserBuilder authorities(Collection<? extends GrantedAuthority> authorities) {
|
||||
this.authorities = new ArrayList<GrantedAuthority>(authorities);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.security.core.userdetails;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.AuthenticatedPrincipal;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
@@ -41,7 +42,7 @@ import java.util.Collection;
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface UserDetails extends Serializable {
|
||||
public interface UserDetails extends AuthenticatedPrincipal, Serializable {
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
@@ -60,8 +61,7 @@ public interface UserDetails extends Serializable {
|
||||
String getPassword();
|
||||
|
||||
/**
|
||||
* Returns the username used to authenticate the user. Cannot return <code>null</code>
|
||||
* .
|
||||
* Returns the username used to authenticate the user. Cannot return <code>null</code>.
|
||||
*
|
||||
* @return the username (never <code>null</code>)
|
||||
*/
|
||||
@@ -100,4 +100,14 @@ public interface UserDetails extends Serializable {
|
||||
* @return <code>true</code> if the user is enabled, <code>false</code> otherwise
|
||||
*/
|
||||
boolean isEnabled();
|
||||
|
||||
/**
|
||||
* Returns the name of the user. Cannot return <code>null</code>.
|
||||
* The default implementation of this method returns {@link #getUsername()}.
|
||||
*
|
||||
* @return the name of the user (never <code>null</code>)
|
||||
*/
|
||||
default String getName() {
|
||||
return getUsername();
|
||||
}
|
||||
}
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.core.userdetails;
|
||||
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface UserDetailsRepository {
|
||||
|
||||
Mono<UserDetails> findByUsername(String username);
|
||||
}
|
||||
+115
-7
@@ -16,17 +16,18 @@
|
||||
|
||||
package org.springframework.security.jackson2;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JacksonAnnotation;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import com.fasterxml.jackson.databind.Module;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder;
|
||||
import com.fasterxml.jackson.databind.*;
|
||||
import com.fasterxml.jackson.databind.cfg.MapperConfig;
|
||||
import com.fasterxml.jackson.databind.jsontype.*;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This utility class will find all the SecurityModules in classpath.
|
||||
@@ -65,7 +66,7 @@ public final class SecurityJackson2Modules {
|
||||
if(mapper != null) {
|
||||
TypeResolverBuilder<?> typeBuilder = mapper.getDeserializationConfig().getDefaultTyper(null);
|
||||
if (typeBuilder == null) {
|
||||
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
|
||||
mapper.setDefaultTyping(createWhitelistedDefaultTyping());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,4 +104,111 @@ public final class SecurityJackson2Modules {
|
||||
}
|
||||
return modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a TypeResolverBuilder that performs whitelisting.
|
||||
* @return a TypeResolverBuilder that performs whitelisting.
|
||||
*/
|
||||
private static TypeResolverBuilder<? extends TypeResolverBuilder> createWhitelistedDefaultTyping() {
|
||||
TypeResolverBuilder<? extends TypeResolverBuilder> result = new WhitelistTypeResolverBuilder(ObjectMapper.DefaultTyping.NON_FINAL);
|
||||
result = result.init(JsonTypeInfo.Id.CLASS, null);
|
||||
result = result.inclusion(JsonTypeInfo.As.PROPERTY);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of {@link ObjectMapper.DefaultTypeResolverBuilder} that overrides the {@link TypeIdResolver}
|
||||
* with {@link WhitelistTypeIdResolver}.
|
||||
* @author Rob Winch
|
||||
*/
|
||||
static class WhitelistTypeResolverBuilder extends ObjectMapper.DefaultTypeResolverBuilder {
|
||||
|
||||
public WhitelistTypeResolverBuilder(ObjectMapper.DefaultTyping defaultTyping) {
|
||||
super(defaultTyping);
|
||||
}
|
||||
|
||||
protected TypeIdResolver idResolver(MapperConfig<?> config,
|
||||
JavaType baseType, Collection<NamedType> subtypes, boolean forSer, boolean forDeser) {
|
||||
TypeIdResolver result = super.idResolver(config, baseType, subtypes, forSer, forDeser);
|
||||
return new WhitelistTypeIdResolver(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link TypeIdResolver} that delegates to an existing implementation and throws an IllegalStateException if the
|
||||
* class being looked up is not whitelisted, does not provide an explicit mixin, and is not annotated with Jackson
|
||||
* mappings. See https://github.com/spring-projects/spring-security/issues/4370
|
||||
*/
|
||||
static class WhitelistTypeIdResolver implements TypeIdResolver {
|
||||
private static final Set<String> WHITELIST_CLASS_NAMES = Collections.unmodifiableSet(new HashSet(Arrays.asList(
|
||||
"java.util.ArrayList",
|
||||
"java.util.Collections$EmptyMap",
|
||||
"java.util.Date",
|
||||
"java.util.TreeMap",
|
||||
"org.springframework.security.core.context.SecurityContextImpl"
|
||||
)));
|
||||
|
||||
private final TypeIdResolver delegate;
|
||||
|
||||
WhitelistTypeIdResolver(TypeIdResolver delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(JavaType baseType) {
|
||||
delegate.init(baseType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String idFromValue(Object value) {
|
||||
return delegate.idFromValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String idFromValueAndType(Object value, Class<?> suggestedType) {
|
||||
return delegate.idFromValueAndType(value, suggestedType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String idFromBaseType() {
|
||||
return delegate.idFromBaseType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaType typeFromId(DatabindContext context, String id) throws IOException {
|
||||
DeserializationConfig config = (DeserializationConfig) context.getConfig();
|
||||
JavaType result = delegate.typeFromId(context, id);
|
||||
String className = result.getRawClass().getName();
|
||||
if(isWhitelisted(className)) {
|
||||
return delegate.typeFromId(context, id);
|
||||
}
|
||||
boolean isExplicitMixin = config.findMixInClassFor(result.getRawClass()) != null;
|
||||
if(isExplicitMixin) {
|
||||
return result;
|
||||
}
|
||||
JacksonAnnotation jacksonAnnotation = AnnotationUtils.findAnnotation(result.getRawClass(), JacksonAnnotation.class);
|
||||
if(jacksonAnnotation != null) {
|
||||
return result;
|
||||
}
|
||||
throw new IllegalArgumentException("The class with " + id + " and name of " + className + " is not whitelisted. " +
|
||||
"If you believe this class is safe to deserialize, please provide an explicit mapping using Jackson annotations or by providing a Mixin. " +
|
||||
"If the serialization is only done by a trusted source, you can also enable default typing. " +
|
||||
"See https://github.com/spring-projects/spring-security/issues/4370 for details");
|
||||
}
|
||||
|
||||
private boolean isWhitelisted(String id) {
|
||||
return WHITELIST_CLASS_NAMES.contains(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescForKnownTypeIds() {
|
||||
return delegate.getDescForKnownTypeIds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonTypeInfo.Id getMechanism() {
|
||||
return delegate.getMechanism();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+14
@@ -17,8 +17,10 @@
|
||||
package org.springframework.security.authentication;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.*;
|
||||
import org.springframework.security.core.AuthenticatedPrincipal;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
@@ -135,6 +137,18 @@ public class AbstractAuthenticationTokenTests {
|
||||
assertThat(token.toString().lastIndexOf("Not granted any authorities") != -1).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNameWhenPrincipalIsAuthenticatedPrincipal() {
|
||||
String principalName = "test";
|
||||
|
||||
AuthenticatedPrincipal principal = mock(AuthenticatedPrincipal.class);
|
||||
when(principal.getName()).thenReturn(principalName);
|
||||
|
||||
MockAuthenticationImpl token = new MockAuthenticationImpl(principal, "Password", authorities);
|
||||
assertThat(token.getName()).isEqualTo(principalName);
|
||||
verify(principal, times(1)).getName();
|
||||
}
|
||||
|
||||
// ~ Inner Classes
|
||||
// ==================================================================================================
|
||||
|
||||
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.authentication;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ReactiveAuthenticationManagerAdapterTests {
|
||||
@Mock
|
||||
AuthenticationManager delegate;
|
||||
@Mock
|
||||
Authentication authentication;
|
||||
|
||||
ReactiveAuthenticationManagerAdapter manager;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
manager = new ReactiveAuthenticationManagerAdapter(delegate);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorNullAuthenticationManager() {
|
||||
new ReactiveAuthenticationManagerAdapter(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenSuccessThenSucces() {
|
||||
when(delegate.authenticate(any())).thenReturn(authentication);
|
||||
when(authentication.isAuthenticated()).thenReturn(true);
|
||||
|
||||
Authentication result = manager.authenticate(authentication).block();
|
||||
|
||||
assertThat(result).isEqualTo(authentication);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenReturnNotAuthenticatedThenError() {
|
||||
when(delegate.authenticate(any())).thenReturn(authentication);
|
||||
|
||||
Authentication result = manager.authenticate(authentication).block();
|
||||
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenBadCredentialsThenError() {
|
||||
when(delegate.authenticate(any())).thenThrow(new BadCredentialsException("Failed"));
|
||||
when(authentication.isAuthenticated()).thenReturn(true);
|
||||
|
||||
Mono<Authentication> result = manager.authenticate(authentication);
|
||||
|
||||
StepVerifier.create(result)
|
||||
.expectError(BadCredentialsException.class)
|
||||
.verify();
|
||||
}
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.authentication;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
|
||||
import org.springframework.security.core.userdetails.UserDetailsRepository;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class UserDetailsRepositoryAuthenticationManagerTests {
|
||||
@Mock
|
||||
UserDetailsRepository repository;
|
||||
UserDetailsRepositoryAuthenticationManager manager;
|
||||
String username;
|
||||
String password;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
manager = new UserDetailsRepositoryAuthenticationManager(repository);
|
||||
username = "user";
|
||||
password = "pass";
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorNullUserDetailsRepository() {
|
||||
UserDetailsRepository udr = null;
|
||||
new UserDetailsRepositoryAuthenticationManager(udr);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenUserNotFoundThenBadCredentials() {
|
||||
when(repository.findByUsername(username)).thenReturn(Mono.empty());
|
||||
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
|
||||
Mono<Authentication> authentication = manager.authenticate(token);
|
||||
|
||||
StepVerifier
|
||||
.create(authentication)
|
||||
.expectError(BadCredentialsException.class)
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenPasswordNotEqualThenBadCredentials() {
|
||||
User user = new User(username, password, AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
when(repository.findByUsername(user.getUsername())).thenReturn(Mono.just(user));
|
||||
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password + "INVALID");
|
||||
Mono<Authentication> authentication = manager.authenticate(token);
|
||||
|
||||
StepVerifier
|
||||
.create(authentication)
|
||||
.expectError(BadCredentialsException.class)
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenSuccessThenSuccess() {
|
||||
User user = new User(username, password, AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
when(repository.findByUsername(user.getUsername())).thenReturn(Mono.just(user));
|
||||
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
|
||||
Authentication authentication = manager.authenticate(token).block();
|
||||
|
||||
assertThat(authentication).isEqualTo(authentication);
|
||||
}
|
||||
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.authorization;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AuthenticatedAuthorizationManagerTests {
|
||||
@Mock
|
||||
Authentication authentication;
|
||||
|
||||
AuthenticatedAuthorizationManager<Object> manager = AuthenticatedAuthorizationManager.authenticated();
|
||||
|
||||
@Test
|
||||
public void checkWhenAuthenticatedThenReturnTrue() {
|
||||
when(authentication.isAuthenticated()).thenReturn(true);
|
||||
|
||||
boolean granted = manager.check(Mono.just(authentication), null).block().isGranted();
|
||||
|
||||
assertThat(granted).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWhenNotAuthenticatedThenReturnFalse() {
|
||||
boolean granted = manager.check(Mono.just(authentication), null).block().isGranted();
|
||||
|
||||
assertThat(granted).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWhenEmptyThenReturnFalse() {
|
||||
boolean granted = manager.check(Mono.empty(), null).block().isGranted();
|
||||
|
||||
assertThat(granted).isFalse();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void checkWhenErrorThenError() {
|
||||
Mono<AuthorizationDecision> result = manager.check(Mono.error(new RuntimeException("ooops")), null);
|
||||
|
||||
StepVerifier
|
||||
.create(result)
|
||||
.expectError()
|
||||
.verify();
|
||||
}
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.security.authorization;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.security.core.authority.AuthorityUtils.createAuthorityList;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AuthorityAuthorizationManagerTests {
|
||||
@Mock
|
||||
Authentication authentication;
|
||||
|
||||
AuthorityAuthorizationManager<Object> manager = AuthorityAuthorizationManager.hasAuthority("ADMIN");
|
||||
|
||||
@Test
|
||||
public void checkWhenHasAuthorityAndNotAuthenticatedThenReturnFalse() {
|
||||
boolean granted = manager.check(Mono.just(authentication), null).block().isGranted();
|
||||
|
||||
assertThat(granted).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWhenHasAuthorityAndEmptyThenReturnFalse() {
|
||||
boolean granted = manager.check(Mono.empty(), null).block().isGranted();
|
||||
|
||||
assertThat(granted).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWhenHasAuthorityAndErrorThenError() {
|
||||
Mono<AuthorizationDecision> result = manager.check(Mono.error(new RuntimeException("ooops")), null);
|
||||
|
||||
StepVerifier
|
||||
.create(result)
|
||||
.expectError()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWhenHasAuthorityAndAuthenticatedAndNoAuthoritiesThenReturnFalse() {
|
||||
when(authentication.isAuthenticated()).thenReturn(true);
|
||||
when(authentication.getAuthorities()).thenReturn(Collections.emptyList());
|
||||
|
||||
boolean granted = manager.check(Mono.just(authentication), null).block().isGranted();
|
||||
|
||||
assertThat(granted).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWhenHasAuthorityAndAuthenticatedAndWrongAuthoritiesThenReturnFalse() {
|
||||
authentication = new TestingAuthenticationToken("rob", "secret", "ROLE_ADMIN");
|
||||
|
||||
boolean granted = manager.check(Mono.just(authentication), null).block().isGranted();
|
||||
|
||||
assertThat(granted).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWhenHasAuthorityAndAuthorizedThenReturnTrue() {
|
||||
authentication = new TestingAuthenticationToken("rob", "secret", "ADMIN");
|
||||
|
||||
boolean granted = manager.check(Mono.just(authentication), null).block().isGranted();
|
||||
|
||||
assertThat(granted).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWhenHasRoleAndAuthorizedThenReturnTrue() {
|
||||
manager = AuthorityAuthorizationManager.hasRole("ADMIN");
|
||||
authentication = new TestingAuthenticationToken("rob", "secret", "ROLE_ADMIN");
|
||||
|
||||
boolean granted = manager.check(Mono.just(authentication), null).block().isGranted();
|
||||
|
||||
assertThat(granted).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWhenHasRoleAndNotAuthorizedThenReturnTrue() {
|
||||
manager = AuthorityAuthorizationManager.hasRole("ADMIN");
|
||||
authentication = new TestingAuthenticationToken("rob", "secret", "ADMIN");
|
||||
|
||||
boolean granted = manager.check(Mono.just(authentication), null).block().isGranted();
|
||||
|
||||
assertThat(granted).isFalse();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void hasRoleWhenNullThenException() {
|
||||
String role = null;
|
||||
AuthorityAuthorizationManager.hasRole(role);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void hasAuthorityWhenNullThenException() {
|
||||
String authority = null;
|
||||
AuthorityAuthorizationManager.hasAuthority(authority);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.security.concurrent;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
*/
|
||||
package org.springframework.security.core;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
@@ -29,7 +29,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*/
|
||||
public class JavaVersionTests {
|
||||
|
||||
private static final int JDK6_CLASS_VERSION = 50;
|
||||
private static final int JDK8_CLASS_VERSION = 52;
|
||||
|
||||
@Test
|
||||
public void authenticationCorrectJdkCompatibility() throws Exception {
|
||||
@@ -45,7 +45,7 @@ public class JavaVersionTests {
|
||||
data.readInt();
|
||||
data.readShort(); // minor
|
||||
int major = data.readShort();
|
||||
assertThat(major).isEqualTo(JDK6_CLASS_VERSION);
|
||||
assertThat(major).isEqualTo(JDK8_CLASS_VERSION);
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2002-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
package org.springframework.security.core.userdetails;
|
||||
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.core.userdetails.MapUserDetailsRepository;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class MapUserDetailsRepositoryTests {
|
||||
private static final UserDetails USER_DETAILS = User.withUsername("user")
|
||||
.password("password")
|
||||
.roles("USER")
|
||||
.build();
|
||||
|
||||
private MapUserDetailsRepository users = new MapUserDetailsRepository(Arrays.asList(USER_DETAILS));
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorNullUsers() {
|
||||
Collection<UserDetails> users = null;
|
||||
new MapUserDetailsRepository(users);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorEmptyUsers() {
|
||||
Collection<UserDetails> users = Collections.emptyList();
|
||||
new MapUserDetailsRepository(users);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByUsernameWhenFoundThenReturns() {
|
||||
assertThat((users.findByUsername(USER_DETAILS.getUsername()).block())).isEqualTo(USER_DETAILS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByUsernameWhenDifferentCaseThenReturns() {
|
||||
assertThat((users.findByUsername("uSeR").block())).isEqualTo(USER_DETAILS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByUsernameWhenClearCredentialsThenFindByUsernameStillHasCredentials() {
|
||||
User foundUser = users.findByUsername(USER_DETAILS.getUsername()).cast(User.class).block();
|
||||
assertThat(foundUser.getPassword()).isNotEmpty();
|
||||
foundUser.eraseCredentials();
|
||||
assertThat(foundUser.getPassword()).isNull();
|
||||
|
||||
foundUser = users.findByUsername(USER_DETAILS.getUsername()).cast(User.class).block();
|
||||
assertThat(foundUser.getPassword()).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByUsernameWhenNotFoundThenEmpty() {
|
||||
assertThat((users.findByUsername("notfound"))).isEqualTo(Mono.empty());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.core.userdetails;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests {@link UserDetails}
|
||||
*
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
public class UserDetailsTest {
|
||||
|
||||
@Test
|
||||
public void getNameWhenCalledThenDefaultToGetUsername() {
|
||||
UserDetails userDetails = new MockUserDetails("joeg");
|
||||
assertThat(userDetails.getName()).isEqualTo(userDetails.getUsername());
|
||||
}
|
||||
|
||||
private class MockUserDetails implements UserDetails {
|
||||
private final String username;
|
||||
|
||||
private MockUserDetails(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return AuthorityUtils.NO_AUTHORITIES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,4 +146,35 @@ public class UserTests {
|
||||
out.writeObject(user);
|
||||
out.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withUserDetailsWhenAllEnabled() throws Exception {
|
||||
User expected = new User("rob","pass", true, true, true, true, ROLE_12);
|
||||
|
||||
UserDetails actual = User.withUserDetails(expected).build();
|
||||
|
||||
assertThat(actual.getUsername()).isEqualTo(expected.getUsername());
|
||||
assertThat(actual.getPassword()).isEqualTo(expected.getPassword());
|
||||
assertThat(actual.getAuthorities()).isEqualTo(expected.getAuthorities());
|
||||
assertThat(actual.isAccountNonExpired()).isEqualTo(expected.isAccountNonExpired());
|
||||
assertThat(actual.isAccountNonLocked()).isEqualTo(expected.isAccountNonLocked());
|
||||
assertThat(actual.isCredentialsNonExpired()).isEqualTo(expected.isCredentialsNonExpired());
|
||||
assertThat(actual.isEnabled()).isEqualTo(expected.isEnabled());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void withUserDetailsWhenAllDisabled() throws Exception {
|
||||
User expected = new User("rob","pass", false, false, false, false, ROLE_12);
|
||||
|
||||
UserDetails actual = User.withUserDetails(expected).build();
|
||||
|
||||
assertThat(actual.getUsername()).isEqualTo(expected.getUsername());
|
||||
assertThat(actual.getPassword()).isEqualTo(expected.getPassword());
|
||||
assertThat(actual.getAuthorities()).isEqualTo(expected.getAuthorities());
|
||||
assertThat(actual.isAccountNonExpired()).isEqualTo(expected.isAccountNonExpired());
|
||||
assertThat(actual.isAccountNonLocked()).isEqualTo(expected.isAccountNonLocked());
|
||||
assertThat(actual.isCredentialsNonExpired()).isEqualTo(expected.isCredentialsNonExpired());
|
||||
assertThat(actual.isEnabled()).isEqualTo(expected.isEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2015-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package org.springframework.security.jackson2;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreType;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public class SecurityJackson2ModulesTests {
|
||||
private ObjectMapper mapper;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mapper = new ObjectMapper();
|
||||
SecurityJackson2Modules.enableDefaultTyping(mapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readValueWhenNotWhitelistedOrMappedThenThrowsException() throws Exception {
|
||||
String content = "{\"@class\":\"org.springframework.security.jackson2.SecurityJackson2ModulesTests$NotWhitelisted\",\"property\":\"bar\"}";
|
||||
assertThatThrownBy(() -> {
|
||||
mapper.readValue(content, Object.class);
|
||||
}
|
||||
).hasStackTraceContaining("whitelisted");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readValueWhenExplicitDefaultTypingAfterSecuritySetupThenReadsAsSpecificType() throws Exception {
|
||||
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
|
||||
String content = "{\"@class\":\"org.springframework.security.jackson2.SecurityJackson2ModulesTests$NotWhitelisted\",\"property\":\"bar\"}";
|
||||
|
||||
assertThat(mapper.readValue(content, Object.class)).isInstanceOf(NotWhitelisted.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readValueWhenExplicitDefaultTypingBeforeSecuritySetupThenReadsAsSpecificType() throws Exception {
|
||||
mapper = new ObjectMapper();
|
||||
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
|
||||
SecurityJackson2Modules.enableDefaultTyping(mapper);
|
||||
String content = "{\"@class\":\"org.springframework.security.jackson2.SecurityJackson2ModulesTests$NotWhitelisted\",\"property\":\"bar\"}";
|
||||
|
||||
assertThat(mapper.readValue(content, Object.class)).isInstanceOf(NotWhitelisted.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readValueWhenAnnotatedThenReadsAsSpecificType() throws Exception {
|
||||
String content = "{\"@class\":\"org.springframework.security.jackson2.SecurityJackson2ModulesTests$NotWhitelistedButAnnotated\",\"property\":\"bar\"}";
|
||||
|
||||
assertThat(mapper.readValue(content, Object.class)).isInstanceOf(NotWhitelistedButAnnotated.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readValueWhenMixinProvidedThenReadsAsSpecificType() throws Exception {
|
||||
mapper.addMixIn(NotWhitelisted.class, NotWhitelistedMixin.class);
|
||||
String content = "{\"@class\":\"org.springframework.security.jackson2.SecurityJackson2ModulesTests$NotWhitelisted\",\"property\":\"bar\"}";
|
||||
|
||||
assertThat(mapper.readValue(content, Object.class)).isInstanceOf(NotWhitelisted.class);
|
||||
}
|
||||
|
||||
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface NotJacksonAnnotation {}
|
||||
|
||||
@NotJacksonAnnotation
|
||||
static class NotWhitelisted {
|
||||
private String property = "bar";
|
||||
|
||||
public String getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public void setProperty(String property) {
|
||||
}
|
||||
}
|
||||
|
||||
@JsonIgnoreType(false)
|
||||
static class NotWhitelistedButAnnotated {
|
||||
private String property = "bar";
|
||||
|
||||
public String getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public void setProperty(String property) {
|
||||
}
|
||||
}
|
||||
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
|
||||
isGetterVisibility = JsonAutoDetect.Visibility.NONE)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
abstract class NotWhitelistedMixin {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
dependencies {
|
||||
optional 'org.bouncycastle:bcpkix-jdk15on:1.54'
|
||||
}
|
||||
-112
@@ -1,112 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-crypto</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<name>spring-security-crypto</name>
|
||||
<description>spring-security-crypto</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
<organization>
|
||||
<name>spring.io</name>
|
||||
<url>http://spring.io/</url>
|
||||
</organization>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>rwinch</id>
|
||||
<name>Rob Winch</name>
|
||||
<email>rwinch@gopivotal.com</email>
|
||||
</developer>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
|
||||
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
|
||||
<url>https://github.com/spring-projects/spring-security</url>
|
||||
</scm>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>4.3.5.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>1.2</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcpkix-jdk15on</artifactId>
|
||||
<version>1.54</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>2.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>1.7.7</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,6 @@
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
|
||||
dependencies {
|
||||
optional 'org.springframework:spring-jcl'
|
||||
optional 'org.bouncycastle:bcpkix-jdk15on'
|
||||
}
|
||||
@@ -1,646 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.crypto.codec;
|
||||
|
||||
/**
|
||||
* Base64 encoder which is a reduced version of Robert Harder's public domain
|
||||
* implementation (version 2.3.7). See <a
|
||||
* href="http://iharder.net/base64">http://iharder.net/base64</a> for more information.
|
||||
* <p>
|
||||
* For internal use only.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class Base64 {
|
||||
|
||||
/** No options specified. Value is zero. */
|
||||
public final static int NO_OPTIONS = 0;
|
||||
|
||||
/** Specify encoding in first bit. Value is one. */
|
||||
public final static int ENCODE = 1;
|
||||
|
||||
/** Specify decoding in first bit. Value is zero. */
|
||||
public final static int DECODE = 0;
|
||||
|
||||
/** Do break lines when encoding. Value is 8. */
|
||||
public final static int DO_BREAK_LINES = 8;
|
||||
|
||||
/**
|
||||
* Encode using Base64-like encoding that is URL- and Filename-safe as described in
|
||||
* Section 4 of RFC3548: <a
|
||||
* href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs
|
||||
* .org/rfcs/rfc3548.html</a>. It is important to note that data encoded this way is
|
||||
* <em>not</em> officially valid Base64, or at the very least should not be called
|
||||
* Base64 without also specifying that is was encoded using the URL- and Filename-safe
|
||||
* dialect.
|
||||
*/
|
||||
public final static int URL_SAFE = 16;
|
||||
|
||||
/**
|
||||
* Encode using the special "ordered" dialect of Base64 described here: <a
|
||||
* href="http://www.faqs.org/qa/rfcc-1940.html"
|
||||
* >http://www.faqs.org/qa/rfcc-1940.html</a>.
|
||||
*/
|
||||
public final static int ORDERED = 32;
|
||||
|
||||
/** Maximum line length (76) of Base64 output. */
|
||||
private final static int MAX_LINE_LENGTH = 76;
|
||||
|
||||
/** The equals sign (=) as a byte. */
|
||||
private final static byte EQUALS_SIGN = (byte) '=';
|
||||
|
||||
/** The new line character (\n) as a byte. */
|
||||
private final static byte NEW_LINE = (byte) '\n';
|
||||
|
||||
private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding
|
||||
private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding
|
||||
|
||||
/* ******** S T A N D A R D B A S E 6 4 A L P H A B E T ******** */
|
||||
|
||||
/** The 64 valid Base64 values. */
|
||||
/* Host platform me be something funny like EBCDIC, so we hardcode these values. */
|
||||
private final static byte[] _STANDARD_ALPHABET = { (byte) 'A', (byte) 'B',
|
||||
(byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H',
|
||||
(byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
|
||||
(byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T',
|
||||
(byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z',
|
||||
(byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f',
|
||||
(byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l',
|
||||
(byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r',
|
||||
(byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x',
|
||||
(byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3',
|
||||
(byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9',
|
||||
(byte) '+', (byte) '/' };
|
||||
|
||||
/**
|
||||
* Translates a Base64 value to either its 6-bit reconstruction value or a negative
|
||||
* number indicating some other meaning.
|
||||
**/
|
||||
private final static byte[] _STANDARD_DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9,
|
||||
-9, // Decimal 0 - 8
|
||||
-5, -5, // Whitespace: Tab and Linefeed
|
||||
-9, -9, // Decimal 11 - 12
|
||||
-5, // Whitespace: Carriage Return
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26
|
||||
-9, -9, -9, -9, -9, // Decimal 27 - 31
|
||||
-5, // Whitespace: Space
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
|
||||
62, // Plus sign at decimal 43
|
||||
-9, -9, -9, // Decimal 44 - 46
|
||||
63, // Slash at decimal 47
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine
|
||||
-9, -9, -9, // Decimal 58 - 60
|
||||
-1, // Equals sign at decimal 61
|
||||
-9, -9, -9, // Decimal 62 - 64
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N'
|
||||
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z'
|
||||
-9, -9, -9, -9, -9, -9, // Decimal 91 - 96
|
||||
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm'
|
||||
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z'
|
||||
-9, -9, -9, -9, -9 // Decimal 123 - 127
|
||||
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 128 - 139
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 140 - 152
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 153 - 165
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 166 - 178
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 179 - 191
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 192 - 204
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 205 - 217
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 218 - 230
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 231 - 243
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 // Decimal 244 - 255
|
||||
};
|
||||
|
||||
/* ******** U R L S A F E B A S E 6 4 A L P H A B E T ******** */
|
||||
|
||||
/**
|
||||
* Used in the URL- and Filename-safe dialect described in Section 4 of RFC3548: <a
|
||||
* href
|
||||
* ="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
|
||||
* Notice that the last two bytes become "hyphen" and "underscore" instead of "plus"
|
||||
* and "slash."
|
||||
*/
|
||||
private final static byte[] _URL_SAFE_ALPHABET = { (byte) 'A', (byte) 'B',
|
||||
(byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H',
|
||||
(byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
|
||||
(byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T',
|
||||
(byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z',
|
||||
(byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f',
|
||||
(byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l',
|
||||
(byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r',
|
||||
(byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x',
|
||||
(byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3',
|
||||
(byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9',
|
||||
(byte) '-', (byte) '_' };
|
||||
|
||||
/**
|
||||
* Used in decoding URL- and Filename-safe dialects of Base64.
|
||||
*/
|
||||
private final static byte[] _URL_SAFE_DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9,
|
||||
-9, // Decimal 0 - 8
|
||||
-5, -5, // Whitespace: Tab and Linefeed
|
||||
-9, -9, // Decimal 11 - 12
|
||||
-5, // Whitespace: Carriage Return
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26
|
||||
-9, -9, -9, -9, -9, // Decimal 27 - 31
|
||||
-5, // Whitespace: Space
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
|
||||
-9, // Plus sign at decimal 43
|
||||
-9, // Decimal 44
|
||||
62, // Minus sign at decimal 45
|
||||
-9, // Decimal 46
|
||||
-9, // Slash at decimal 47
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine
|
||||
-9, -9, -9, // Decimal 58 - 60
|
||||
-1, // Equals sign at decimal 61
|
||||
-9, -9, -9, // Decimal 62 - 64
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N'
|
||||
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z'
|
||||
-9, -9, -9, -9, // Decimal 91 - 94
|
||||
63, // Underscore at decimal 95
|
||||
-9, // Decimal 96
|
||||
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm'
|
||||
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z'
|
||||
-9, -9, -9, -9, -9 // Decimal 123 - 127
|
||||
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 128 - 139
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 140 - 152
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 153 - 165
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 166 - 178
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 179 - 191
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 192 - 204
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 205 - 217
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 218 - 230
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 231 - 243
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 // Decimal 244 - 255
|
||||
};
|
||||
|
||||
/* ******** O R D E R E D B A S E 6 4 A L P H A B E T ******** */
|
||||
|
||||
/**
|
||||
* I don't get the point of this technique, but someone requested it, and it is
|
||||
* described here: <a
|
||||
* href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/
|
||||
* qa/rfcc-1940.html</a>.
|
||||
*/
|
||||
private final static byte[] _ORDERED_ALPHABET = { (byte) '-', (byte) '0', (byte) '1',
|
||||
(byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7',
|
||||
(byte) '8', (byte) '9', (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D',
|
||||
(byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J',
|
||||
(byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P',
|
||||
(byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V',
|
||||
(byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) '_', (byte) 'a',
|
||||
(byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g',
|
||||
(byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm',
|
||||
(byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's',
|
||||
(byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y',
|
||||
(byte) 'z' };
|
||||
|
||||
/**
|
||||
* Used in decoding the "ordered" dialect of Base64.
|
||||
*/
|
||||
private final static byte[] _ORDERED_DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9,
|
||||
-9, // Decimal 0 - 8
|
||||
-5, -5, // Whitespace: Tab and Linefeed
|
||||
-9, -9, // Decimal 11 - 12
|
||||
-5, // Whitespace: Carriage Return
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26
|
||||
-9, -9, -9, -9, -9, // Decimal 27 - 31
|
||||
-5, // Whitespace: Space
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
|
||||
-9, // Plus sign at decimal 43
|
||||
-9, // Decimal 44
|
||||
0, // Minus sign at decimal 45
|
||||
-9, // Decimal 46
|
||||
-9, // Slash at decimal 47
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // Numbers zero through nine
|
||||
-9, -9, -9, // Decimal 58 - 60
|
||||
-1, // Equals sign at decimal 61
|
||||
-9, -9, -9, // Decimal 62 - 64
|
||||
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, // Letters 'A' through 'M'
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, // Letters 'N' through 'Z'
|
||||
-9, -9, -9, -9, // Decimal 91 - 94
|
||||
37, // Underscore at decimal 95
|
||||
-9, // Decimal 96
|
||||
38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, // Letters 'a' through 'm'
|
||||
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // Letters 'n' through 'z'
|
||||
-9, -9, -9, -9, -9 // Decimal 123 - 127
|
||||
, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 128 - 139
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 140 - 152
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 153 - 165
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 166 - 178
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 179 - 191
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 192 - 204
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 205 - 217
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 218 - 230
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 231 - 243
|
||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 // Decimal 244 - 255
|
||||
};
|
||||
|
||||
public static byte[] decode(byte[] bytes) {
|
||||
return decode(bytes, 0, bytes.length, NO_OPTIONS);
|
||||
}
|
||||
|
||||
public static byte[] encode(byte[] bytes) {
|
||||
return encodeBytesToBytes(bytes, 0, bytes.length, NO_OPTIONS);
|
||||
}
|
||||
|
||||
public static boolean isBase64(byte[] bytes) {
|
||||
try {
|
||||
decode(bytes);
|
||||
}
|
||||
catch (InvalidBase64CharacterException e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one of the _SOMETHING_ALPHABET byte arrays depending on the options
|
||||
* specified. It's possible, though silly, to specify ORDERED <b>and</b> URLSAFE in
|
||||
* which case one of them will be picked, though there is no guarantee as to which one
|
||||
* will be picked.
|
||||
*/
|
||||
private static byte[] getAlphabet(int options) {
|
||||
if ((options & URL_SAFE) == URL_SAFE) {
|
||||
return _URL_SAFE_ALPHABET;
|
||||
}
|
||||
else if ((options & ORDERED) == ORDERED) {
|
||||
return _ORDERED_ALPHABET;
|
||||
}
|
||||
else {
|
||||
return _STANDARD_ALPHABET;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one of the _SOMETHING_DECODABET byte arrays depending on the options
|
||||
* specified. It's possible, though silly, to specify ORDERED and URL_SAFE in which
|
||||
* case one of them will be picked, though there is no guarantee as to which one will
|
||||
* be picked.
|
||||
*/
|
||||
private static byte[] getDecodabet(int options) {
|
||||
if ((options & URL_SAFE) == URL_SAFE) {
|
||||
return _URL_SAFE_DECODABET;
|
||||
}
|
||||
else if ((options & ORDERED) == ORDERED) {
|
||||
return _ORDERED_DECODABET;
|
||||
}
|
||||
else {
|
||||
return _STANDARD_DECODABET;
|
||||
}
|
||||
}
|
||||
|
||||
/* ******** E N C O D I N G M E T H O D S ******** */
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Encodes up to three bytes of the array <var>source</var> and writes the resulting
|
||||
* four Base64 bytes to <var>destination</var>. The source and destination arrays can
|
||||
* be manipulated anywhere along their length by specifying <var>srcOffset</var> and
|
||||
* <var>destOffset</var>. This method does not check to make sure your arrays are
|
||||
* large enough to accomodate <var>srcOffset</var> + 3 for the <var>source</var> array
|
||||
* or <var>destOffset</var> + 4 for the <var>destination</var> array. The actual
|
||||
* number of significant bytes in your array is given by <var>numSigBytes</var>.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is the lowest level of the encoding methods with all possible parameters.
|
||||
* </p>
|
||||
*
|
||||
* @param source the array to convert
|
||||
* @param srcOffset the index where conversion begins
|
||||
* @param numSigBytes the number of significant bytes in your array
|
||||
* @param destination the array to hold the conversion
|
||||
* @param destOffset the index where output will be put
|
||||
* @return the <var>destination</var> array
|
||||
* @since 1.3
|
||||
*/
|
||||
private static byte[] encode3to4(byte[] source, int srcOffset, int numSigBytes,
|
||||
byte[] destination, int destOffset, int options) {
|
||||
|
||||
byte[] ALPHABET = getAlphabet(options);
|
||||
|
||||
// 1 2 3
|
||||
// 01234567890123456789012345678901 Bit position
|
||||
// --------000000001111111122222222 Array position from threeBytes
|
||||
// --------| || || || | Six bit groups to index ALPHABET
|
||||
// >>18 >>12 >> 6 >> 0 Right shift necessary
|
||||
// 0x3f 0x3f 0x3f Additional AND
|
||||
|
||||
// Create buffer with zero-padding if there are only one or two
|
||||
// significant bytes passed in the array.
|
||||
// We have to shift left 24 in order to flush out the 1's that appear
|
||||
// when Java treats a value as negative that is cast from a byte to an int.
|
||||
int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0)
|
||||
| (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0)
|
||||
| (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0);
|
||||
|
||||
switch (numSigBytes) {
|
||||
case 3:
|
||||
destination[destOffset] = ALPHABET[(inBuff >>> 18)];
|
||||
destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
|
||||
destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
|
||||
destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f];
|
||||
return destination;
|
||||
|
||||
case 2:
|
||||
destination[destOffset] = ALPHABET[(inBuff >>> 18)];
|
||||
destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
|
||||
destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
|
||||
destination[destOffset + 3] = EQUALS_SIGN;
|
||||
return destination;
|
||||
|
||||
case 1:
|
||||
destination[destOffset] = ALPHABET[(inBuff >>> 18)];
|
||||
destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
|
||||
destination[destOffset + 2] = EQUALS_SIGN;
|
||||
destination[destOffset + 3] = EQUALS_SIGN;
|
||||
return destination;
|
||||
|
||||
default:
|
||||
return destination;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param source The data to convert
|
||||
* @param off Offset in array where conversion should begin
|
||||
* @param len Length of data to convert
|
||||
* @param options Specified options
|
||||
* @return The Base64-encoded data as a String
|
||||
* @see Base64#DO_BREAK_LINES
|
||||
* @throws java.io.IOException if there is an error
|
||||
* @throws NullPointerException if source array is null
|
||||
* @throws IllegalArgumentException if source array, offset, or length are invalid
|
||||
* @since 2.3.1
|
||||
*/
|
||||
private static byte[] encodeBytesToBytes(byte[] source, int off, int len, int options) {
|
||||
|
||||
if (source == null) {
|
||||
throw new NullPointerException("Cannot serialize a null array.");
|
||||
} // end if: null
|
||||
|
||||
if (off < 0) {
|
||||
throw new IllegalArgumentException("Cannot have negative offset: " + off);
|
||||
} // end if: off < 0
|
||||
|
||||
if (len < 0) {
|
||||
throw new IllegalArgumentException("Cannot have length offset: " + len);
|
||||
} // end if: len < 0
|
||||
|
||||
if (off + len > source.length) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Cannot have offset of %d and length of %d with array of length %d",
|
||||
off, len, source.length));
|
||||
} // end if: off < 0
|
||||
|
||||
boolean breakLines = (options & DO_BREAK_LINES) > 0;
|
||||
|
||||
// int len43 = len * 4 / 3;
|
||||
// byte[] outBuff = new byte[ ( len43 ) // Main 4:3
|
||||
// + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding
|
||||
// + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines
|
||||
// Try to determine more precisely how big the array needs to be.
|
||||
// If we get it right, we don't have to do an array copy, and
|
||||
// we save a bunch of memory.
|
||||
int encLen = (len / 3) * 4 + (len % 3 > 0 ? 4 : 0); // Bytes needed for actual
|
||||
// encoding
|
||||
if (breakLines) {
|
||||
encLen += encLen / MAX_LINE_LENGTH; // Plus extra newline characters
|
||||
}
|
||||
byte[] outBuff = new byte[encLen];
|
||||
|
||||
int d = 0;
|
||||
int e = 0;
|
||||
int len2 = len - 2;
|
||||
int lineLength = 0;
|
||||
for (; d < len2; d += 3, e += 4) {
|
||||
encode3to4(source, d + off, 3, outBuff, e, options);
|
||||
|
||||
lineLength += 4;
|
||||
if (breakLines && lineLength >= MAX_LINE_LENGTH) {
|
||||
outBuff[e + 4] = NEW_LINE;
|
||||
e++;
|
||||
lineLength = 0;
|
||||
} // end if: end of line
|
||||
} // en dfor: each piece of array
|
||||
|
||||
if (d < len) {
|
||||
encode3to4(source, d + off, len - d, outBuff, e, options);
|
||||
e += 4;
|
||||
} // end if: some padding needed
|
||||
|
||||
// Only resize array if we didn't guess it right.
|
||||
if (e <= outBuff.length - 1) {
|
||||
byte[] finalOut = new byte[e];
|
||||
System.arraycopy(outBuff, 0, finalOut, 0, e);
|
||||
// System.err.println("Having to resize array from " + outBuff.length + " to "
|
||||
// + e );
|
||||
return finalOut;
|
||||
}
|
||||
else {
|
||||
// System.err.println("No need to resize array.");
|
||||
return outBuff;
|
||||
}
|
||||
}
|
||||
|
||||
/* ******** D E C O D I N G M E T H O D S ******** */
|
||||
|
||||
/**
|
||||
* Decodes four bytes from array <var>source</var> and writes the resulting bytes (up
|
||||
* to three of them) to <var>destination</var>. The source and destination arrays can
|
||||
* be manipulated anywhere along their length by specifying <var>srcOffset</var> and
|
||||
* <var>destOffset</var>. This method does not check to make sure your arrays are
|
||||
* large enough to accomodate <var>srcOffset</var> + 4 for the <var>source</var> array
|
||||
* or <var>destOffset</var> + 3 for the <var>destination</var> array. This method
|
||||
* returns the actual number of bytes that were converted from the Base64 encoding.
|
||||
* <p>
|
||||
* This is the lowest level of the decoding methods with all possible parameters.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param source the array to convert
|
||||
* @param srcOffset the index where conversion begins
|
||||
* @param destination the array to hold the conversion
|
||||
* @param destOffset the index where output will be put
|
||||
* @param options alphabet type is pulled from this (standard, url-safe, ordered)
|
||||
* @return the number of decoded bytes converted
|
||||
* @throws NullPointerException if source or destination arrays are null
|
||||
* @throws IllegalArgumentException if srcOffset or destOffset are invalid or there is
|
||||
* not enough room in the array.
|
||||
* @since 1.3
|
||||
*/
|
||||
private static int decode4to3(final byte[] source, final int srcOffset,
|
||||
final byte[] destination, final int destOffset, final int options) {
|
||||
|
||||
// Lots of error checking and exception throwing
|
||||
if (source == null) {
|
||||
throw new NullPointerException("Source array was null.");
|
||||
} // end if
|
||||
if (destination == null) {
|
||||
throw new NullPointerException("Destination array was null.");
|
||||
} // end if
|
||||
if (srcOffset < 0 || srcOffset + 3 >= source.length) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Source array with length %d cannot have offset of %d and still process four bytes.",
|
||||
source.length, srcOffset));
|
||||
} // end if
|
||||
if (destOffset < 0 || destOffset + 2 >= destination.length) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Destination array with length %d cannot have offset of %d and still store three bytes.",
|
||||
destination.length, destOffset));
|
||||
} // end if
|
||||
|
||||
byte[] DECODABET = getDecodabet(options);
|
||||
|
||||
// Example: Dk==
|
||||
if (source[srcOffset + 2] == EQUALS_SIGN) {
|
||||
// Two ways to do the same thing. Don't know which way I like best.
|
||||
// int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
|
||||
// | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );
|
||||
int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
|
||||
| ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12);
|
||||
|
||||
destination[destOffset] = (byte) (outBuff >>> 16);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Example: DkL=
|
||||
else if (source[srcOffset + 3] == EQUALS_SIGN) {
|
||||
// Two ways to do the same thing. Don't know which way I like best.
|
||||
// int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
|
||||
// | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
|
||||
// | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );
|
||||
int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
|
||||
| ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12)
|
||||
| ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6);
|
||||
|
||||
destination[destOffset] = (byte) (outBuff >>> 16);
|
||||
destination[destOffset + 1] = (byte) (outBuff >>> 8);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Example: DkLE
|
||||
else {
|
||||
// Two ways to do the same thing. Don't know which way I like best.
|
||||
// int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
|
||||
// | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
|
||||
// | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )
|
||||
// | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );
|
||||
int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
|
||||
| ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12)
|
||||
| ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6)
|
||||
| ((DECODABET[source[srcOffset + 3]] & 0xFF));
|
||||
|
||||
destination[destOffset] = (byte) (outBuff >> 16);
|
||||
destination[destOffset + 1] = (byte) (outBuff >> 8);
|
||||
destination[destOffset + 2] = (byte) (outBuff);
|
||||
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Low-level access to decoding ASCII characters in the form of a byte array.
|
||||
* <strong>Ignores GUNZIP option, if it's set.</strong> This is not generally a
|
||||
* recommended method, although it is used internally as part of the decoding process.
|
||||
* Special case: if len = 0, an empty array is returned. Still, if you need more speed
|
||||
* and reduced memory footprint (and aren't gzipping), consider this method.
|
||||
*
|
||||
* @param source The Base64 encoded data
|
||||
* @param off The offset of where to begin decoding
|
||||
* @param len The length of characters to decode
|
||||
* @param options Can specify options such as alphabet type to use
|
||||
* @return decoded data
|
||||
* @throws IllegalArgumentException If bogus characters exist in source data
|
||||
*/
|
||||
private static byte[] decode(final byte[] source, final int off, final int len,
|
||||
final int options) {
|
||||
|
||||
// Lots of error checking and exception throwing
|
||||
if (source == null) {
|
||||
throw new NullPointerException("Cannot decode null source array.");
|
||||
} // end if
|
||||
if (off < 0 || off + len > source.length) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Source array with length %d cannot have offset of %d and process %d bytes.",
|
||||
source.length, off, len));
|
||||
} // end if
|
||||
|
||||
if (len == 0) {
|
||||
return new byte[0];
|
||||
}
|
||||
else if (len < 4) {
|
||||
throw new IllegalArgumentException(
|
||||
"Base64-encoded string must have at least four characters, but length specified was "
|
||||
+ len);
|
||||
} // end if
|
||||
|
||||
byte[] DECODABET = getDecodabet(options);
|
||||
|
||||
int len34 = len * 3 / 4; // Estimate on array size
|
||||
byte[] outBuff = new byte[len34]; // Upper limit on size of output
|
||||
int outBuffPosn = 0; // Keep track of where we're writing
|
||||
|
||||
byte[] b4 = new byte[4]; // Four byte buffer from source, eliminating white space
|
||||
int b4Posn = 0; // Keep track of four byte input buffer
|
||||
int i = 0; // Source array counter
|
||||
byte sbiDecode = 0; // Special value from DECODABET
|
||||
|
||||
for (i = off; i < off + len; i++) { // Loop through source
|
||||
|
||||
sbiDecode = DECODABET[source[i] & 0xFF];
|
||||
|
||||
// White space, Equals sign, or legit Base64 character
|
||||
// Note the values such as -5 and -9 in the
|
||||
// DECODABETs at the top of the file.
|
||||
if (sbiDecode >= WHITE_SPACE_ENC) {
|
||||
if (sbiDecode >= EQUALS_SIGN_ENC) {
|
||||
b4[b4Posn++] = source[i]; // Save non-whitespace
|
||||
if (b4Posn > 3) { // Time to decode?
|
||||
outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, options);
|
||||
b4Posn = 0;
|
||||
|
||||
// If that was the equals sign, break out of 'for' loop
|
||||
if (source[i] == EQUALS_SIGN) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// There's a bad input character in the Base64 stream.
|
||||
throw new InvalidBase64CharacterException(String.format(
|
||||
"Bad Base64 input character decimal %d in array position %d",
|
||||
((int) source[i]) & 0xFF, i));
|
||||
}
|
||||
}
|
||||
|
||||
byte[] out = new byte[outBuffPosn];
|
||||
System.arraycopy(outBuff, 0, out, 0, outBuffPosn);
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
class InvalidBase64CharacterException extends IllegalArgumentException {
|
||||
|
||||
InvalidBase64CharacterException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
+187
-186
@@ -1,186 +1,187 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.crypto.scrypt;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.bouncycastle.crypto.generators.SCrypt;
|
||||
import org.springframework.security.crypto.codec.Base64;
|
||||
import org.springframework.security.crypto.codec.Utf8;
|
||||
import org.springframework.security.crypto.keygen.BytesKeyGenerator;
|
||||
import org.springframework.security.crypto.keygen.KeyGenerators;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Implementation of PasswordEncoder that uses the SCrypt hashing function.
|
||||
* Clients can optionally supply a cpu cost parameter, a memory cost parameter
|
||||
* and a parallelization parameter.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* A few <a href=
|
||||
* "http://bouncy-castle.1462172.n4.nabble.com/Java-Bouncy-Castle-scrypt-implementation-td4656832.html">
|
||||
* warnings</a>:
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>The currently implementation uses Bouncy castle which does not exploit
|
||||
* parallelism/optimizations that password crackers will, so there is an
|
||||
* unnecessary asymmetry between attacker and defender.</li>
|
||||
* <li>Scrypt is based on Salsa20 which performs poorly in Java (on par with
|
||||
* AES) but performs awesome (~4-5x faster) on SIMD capable platforms</li>
|
||||
* <li>While there are some that would disagree, consider reading -
|
||||
* <a href="http://blog.ircmaxell.com/2014/03/why-i-dont-recommend-scrypt.html">
|
||||
* Why I Don't Recommend Scrypt</a> (for password storage)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Shazin Sadakath
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class SCryptPasswordEncoder implements PasswordEncoder {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final int cpuCost;
|
||||
|
||||
private final int memoryCost;
|
||||
|
||||
private final int parallelization;
|
||||
|
||||
private final int keyLength;
|
||||
|
||||
private final BytesKeyGenerator saltGenerator;
|
||||
|
||||
public SCryptPasswordEncoder() {
|
||||
this(16384, 8, 1, 32, 64);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param cpuCost
|
||||
* cpu cost of the algorithm (as defined in scrypt this is N).
|
||||
* must be power of 2 greater than 1. Default is currently 16,348
|
||||
* or 2^14)
|
||||
* @param memoryCost
|
||||
* memory cost of the algorithm (as defined in scrypt this is r)
|
||||
* Default is currently 8.
|
||||
* @param parallelization
|
||||
* the parallelization of the algorithm (as defined in scrypt
|
||||
* this is p) Default is currently 1. Note that the
|
||||
* implementation does not currently take advantage of
|
||||
* parallelization.
|
||||
* @param keyLength
|
||||
* key length for the algorithm (as defined in scrypt this is
|
||||
* dkLen). The default is currently 32.
|
||||
* @param saltLength
|
||||
* salt length (as defined in scrypt this is the length of S).
|
||||
* The default is currently 64.
|
||||
*/
|
||||
public SCryptPasswordEncoder(int cpuCost, int memoryCost, int parallelization, int keyLength, int saltLength) {
|
||||
if (cpuCost <= 1) {
|
||||
throw new IllegalArgumentException("Cpu cost parameter must be > 1.");
|
||||
}
|
||||
if (memoryCost == 1 && cpuCost > 65536) {
|
||||
throw new IllegalArgumentException("Cpu cost parameter must be > 1 and < 65536.");
|
||||
}
|
||||
if (memoryCost < 1) {
|
||||
throw new IllegalArgumentException("Memory cost must be >= 1.");
|
||||
}
|
||||
int maxParallel = Integer.MAX_VALUE / (128 * memoryCost * 8);
|
||||
if (parallelization < 1 || parallelization > maxParallel) {
|
||||
throw new IllegalArgumentException("Parallelisation parameter p must be >= 1 and <= " + maxParallel
|
||||
+ " (based on block size r of " + memoryCost + ")");
|
||||
}
|
||||
if (keyLength < 1 || keyLength > Integer.MAX_VALUE) {
|
||||
throw new IllegalArgumentException("Key length must be >= 1 and <= " + Integer.MAX_VALUE);
|
||||
}
|
||||
if (saltLength < 1 || saltLength > Integer.MAX_VALUE) {
|
||||
throw new IllegalArgumentException("Salt length must be >= 1 and <= " + Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
this.cpuCost = cpuCost;
|
||||
this.memoryCost = memoryCost;
|
||||
this.parallelization = parallelization;
|
||||
this.keyLength = keyLength;
|
||||
this.saltGenerator = KeyGenerators.secureRandom(saltLength);
|
||||
}
|
||||
|
||||
public String encode(CharSequence rawPassword) {
|
||||
return digest(rawPassword, saltGenerator.generateKey());
|
||||
}
|
||||
|
||||
public boolean matches(CharSequence rawPassword, String encodedPassword) {
|
||||
if (encodedPassword == null || encodedPassword.length() < keyLength) {
|
||||
logger.warn("Empty encoded password");
|
||||
return false;
|
||||
}
|
||||
return decodeAndCheckMatches(rawPassword, encodedPassword);
|
||||
}
|
||||
|
||||
private boolean decodeAndCheckMatches(CharSequence rawPassword, String encodedPassword) {
|
||||
String[] parts = encodedPassword.split("\\$");
|
||||
|
||||
if (parts.length != 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
long params = Long.parseLong(parts[1], 16);
|
||||
byte[] salt = decodePart(parts[2]);
|
||||
byte[] derived = decodePart(parts[3]);
|
||||
|
||||
int cpuCost = (int) Math.pow(2, params >> 16 & 0xffff);
|
||||
int memoryCost = (int) params >> 8 & 0xff;
|
||||
int parallelization = (int) params & 0xff;
|
||||
|
||||
byte[] generated = SCrypt.generate(Utf8.encode(rawPassword), salt, cpuCost, memoryCost, parallelization,
|
||||
keyLength);
|
||||
|
||||
if (derived.length != generated.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
for (int i = 0; i < derived.length; i++) {
|
||||
result |= derived[i] ^ generated[i];
|
||||
}
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
private String digest(CharSequence rawPassword, byte[] salt) {
|
||||
byte[] derived = SCrypt.generate(Utf8.encode(rawPassword), salt, cpuCost, memoryCost, parallelization, keyLength);
|
||||
|
||||
String params = Long
|
||||
.toString(((int) (Math.log(cpuCost) / Math.log(2)) << 16L) | memoryCost << 8 | parallelization, 16);
|
||||
|
||||
StringBuilder sb = new StringBuilder((salt.length + derived.length) * 2);
|
||||
sb.append("$").append(params).append('$');
|
||||
sb.append(encodePart(salt)).append('$');
|
||||
sb.append(encodePart(derived));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private byte[] decodePart(String part) {
|
||||
return Base64.decode(Utf8.encode(part));
|
||||
}
|
||||
|
||||
private String encodePart(byte[] part) {
|
||||
return Utf8.decode(Base64.encode(part));
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.crypto.scrypt;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.bouncycastle.crypto.generators.SCrypt;
|
||||
import org.springframework.security.crypto.codec.Utf8;
|
||||
import org.springframework.security.crypto.keygen.BytesKeyGenerator;
|
||||
import org.springframework.security.crypto.keygen.KeyGenerators;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Implementation of PasswordEncoder that uses the SCrypt hashing function.
|
||||
* Clients can optionally supply a cpu cost parameter, a memory cost parameter
|
||||
* and a parallelization parameter.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* A few <a href=
|
||||
* "http://bouncy-castle.1462172.n4.nabble.com/Java-Bouncy-Castle-scrypt-implementation-td4656832.html">
|
||||
* warnings</a>:
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>The currently implementation uses Bouncy castle which does not exploit
|
||||
* parallelism/optimizations that password crackers will, so there is an
|
||||
* unnecessary asymmetry between attacker and defender.</li>
|
||||
* <li>Scrypt is based on Salsa20 which performs poorly in Java (on par with
|
||||
* AES) but performs awesome (~4-5x faster) on SIMD capable platforms</li>
|
||||
* <li>While there are some that would disagree, consider reading -
|
||||
* <a href="http://blog.ircmaxell.com/2014/03/why-i-dont-recommend-scrypt.html">
|
||||
* Why I Don't Recommend Scrypt</a> (for password storage)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Shazin Sadakath
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class SCryptPasswordEncoder implements PasswordEncoder {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final int cpuCost;
|
||||
|
||||
private final int memoryCost;
|
||||
|
||||
private final int parallelization;
|
||||
|
||||
private final int keyLength;
|
||||
|
||||
private final BytesKeyGenerator saltGenerator;
|
||||
|
||||
public SCryptPasswordEncoder() {
|
||||
this(16384, 8, 1, 32, 64);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param cpuCost
|
||||
* cpu cost of the algorithm (as defined in scrypt this is N).
|
||||
* must be power of 2 greater than 1. Default is currently 16,348
|
||||
* or 2^14)
|
||||
* @param memoryCost
|
||||
* memory cost of the algorithm (as defined in scrypt this is r)
|
||||
* Default is currently 8.
|
||||
* @param parallelization
|
||||
* the parallelization of the algorithm (as defined in scrypt
|
||||
* this is p) Default is currently 1. Note that the
|
||||
* implementation does not currently take advantage of
|
||||
* parallelization.
|
||||
* @param keyLength
|
||||
* key length for the algorithm (as defined in scrypt this is
|
||||
* dkLen). The default is currently 32.
|
||||
* @param saltLength
|
||||
* salt length (as defined in scrypt this is the length of S).
|
||||
* The default is currently 64.
|
||||
*/
|
||||
public SCryptPasswordEncoder(int cpuCost, int memoryCost, int parallelization, int keyLength, int saltLength) {
|
||||
if (cpuCost <= 1) {
|
||||
throw new IllegalArgumentException("Cpu cost parameter must be > 1.");
|
||||
}
|
||||
if (memoryCost == 1 && cpuCost > 65536) {
|
||||
throw new IllegalArgumentException("Cpu cost parameter must be > 1 and < 65536.");
|
||||
}
|
||||
if (memoryCost < 1) {
|
||||
throw new IllegalArgumentException("Memory cost must be >= 1.");
|
||||
}
|
||||
int maxParallel = Integer.MAX_VALUE / (128 * memoryCost * 8);
|
||||
if (parallelization < 1 || parallelization > maxParallel) {
|
||||
throw new IllegalArgumentException("Parallelisation parameter p must be >= 1 and <= " + maxParallel
|
||||
+ " (based on block size r of " + memoryCost + ")");
|
||||
}
|
||||
if (keyLength < 1 || keyLength > Integer.MAX_VALUE) {
|
||||
throw new IllegalArgumentException("Key length must be >= 1 and <= " + Integer.MAX_VALUE);
|
||||
}
|
||||
if (saltLength < 1 || saltLength > Integer.MAX_VALUE) {
|
||||
throw new IllegalArgumentException("Salt length must be >= 1 and <= " + Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
this.cpuCost = cpuCost;
|
||||
this.memoryCost = memoryCost;
|
||||
this.parallelization = parallelization;
|
||||
this.keyLength = keyLength;
|
||||
this.saltGenerator = KeyGenerators.secureRandom(saltLength);
|
||||
}
|
||||
|
||||
public String encode(CharSequence rawPassword) {
|
||||
return digest(rawPassword, saltGenerator.generateKey());
|
||||
}
|
||||
|
||||
public boolean matches(CharSequence rawPassword, String encodedPassword) {
|
||||
if (encodedPassword == null || encodedPassword.length() < keyLength) {
|
||||
logger.warn("Empty encoded password");
|
||||
return false;
|
||||
}
|
||||
return decodeAndCheckMatches(rawPassword, encodedPassword);
|
||||
}
|
||||
|
||||
private boolean decodeAndCheckMatches(CharSequence rawPassword, String encodedPassword) {
|
||||
String[] parts = encodedPassword.split("\\$");
|
||||
|
||||
if (parts.length != 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
long params = Long.parseLong(parts[1], 16);
|
||||
byte[] salt = decodePart(parts[2]);
|
||||
byte[] derived = decodePart(parts[3]);
|
||||
|
||||
int cpuCost = (int) Math.pow(2, params >> 16 & 0xffff);
|
||||
int memoryCost = (int) params >> 8 & 0xff;
|
||||
int parallelization = (int) params & 0xff;
|
||||
|
||||
byte[] generated = SCrypt.generate(Utf8.encode(rawPassword), salt, cpuCost, memoryCost, parallelization,
|
||||
keyLength);
|
||||
|
||||
if (derived.length != generated.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
for (int i = 0; i < derived.length; i++) {
|
||||
result |= derived[i] ^ generated[i];
|
||||
}
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
private String digest(CharSequence rawPassword, byte[] salt) {
|
||||
byte[] derived = SCrypt.generate(Utf8.encode(rawPassword), salt, cpuCost, memoryCost, parallelization, keyLength);
|
||||
|
||||
String params = Long
|
||||
.toString(((int) (Math.log(cpuCost) / Math.log(2)) << 16L) | memoryCost << 8 | parallelization, 16);
|
||||
|
||||
StringBuilder sb = new StringBuilder((salt.length + derived.length) * 2);
|
||||
sb.append("$").append(params).append('$');
|
||||
sb.append(encodePart(salt)).append('$');
|
||||
sb.append(encodePart(derived));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private byte[] decodePart(String part) {
|
||||
return Base64.getDecoder().decode(Utf8.encode(part));
|
||||
}
|
||||
|
||||
private String encodePart(byte[] part) {
|
||||
return Utf8.decode(Base64.getEncoder().encode(part));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.crypto.codec;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class Base64Tests {
|
||||
|
||||
@Test
|
||||
public void isBase64ReturnsTrueForValidBase64() {
|
||||
new Base64(); // unused
|
||||
|
||||
assertThat(Base64.isBase64(new byte[] { (byte) 'A', (byte) 'B', (byte) 'C',
|
||||
(byte) 'D' })).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isBase64ReturnsFalseForInvalidBase64() throws Exception {
|
||||
// Include invalid '`' character
|
||||
assertThat(Base64.isBase64(new byte[] { (byte) 'A', (byte) 'B', (byte) 'C',
|
||||
(byte) '`' })).isFalse();
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void isBase64RejectsNull() {
|
||||
Base64.isBase64(null);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void isBase64RejectsInvalidLength() {
|
||||
Base64.isBase64(new byte[] { (byte) 'A' });
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
dependencies {
|
||||
compile project(':spring-security-core'),
|
||||
springCoreDependency,
|
||||
"org.springframework.data:spring-data-commons:$springDataCommonsVersion"
|
||||
|
||||
}
|
||||
-128
@@ -1,128 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-data</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<name>spring-security-data</name>
|
||||
<description>spring-security-data</description>
|
||||
<url>http://spring.io/spring-security</url>
|
||||
<organization>
|
||||
<name>spring.io</name>
|
||||
<url>http://spring.io/</url>
|
||||
</organization>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>rwinch</id>
|
||||
<name>Rob Winch</name>
|
||||
<email>rwinch@gopivotal.com</email>
|
||||
</developer>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/spring-projects/spring-security</connection>
|
||||
<developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
|
||||
<url>https://github.com/spring-projects/spring-security</url>
|
||||
</scm>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>4.3.5.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-commons</artifactId>
|
||||
<version>1.12.2.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>4.2.3.BUILD-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>1.2</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>2.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>1.7.7</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshot</id>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,7 @@
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
|
||||
dependencies {
|
||||
compile project(':spring-security-core')
|
||||
compile 'org.springframework.data:spring-data-commons'
|
||||
compile 'org.springframework:spring-core'
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
// Docbook and Javadoc building and uploading tasks
|
||||
apply plugin: 'base'
|
||||
|
||||
task docs {
|
||||
dependsOn 'manual:reference', 'apidocs', 'guides:asciidoctor'
|
||||
}
|
||||
|
||||
project('manual') {
|
||||
apply plugin: 'base'
|
||||
apply plugin: 'org.asciidoctor.gradle.asciidoctor'
|
||||
apply plugin: 'docbook-reference'
|
||||
|
||||
ext.expandPlaceholders = ""
|
||||
|
||||
asciidoctorj {
|
||||
version = '1.5.2'
|
||||
}
|
||||
|
||||
asciidoctor {
|
||||
backends = ['docbook5']
|
||||
def ghTag = snapshotBuild ? 'master' : project.version
|
||||
def ghUrl = "https://github.com/spring-projects/spring-security/tree/$ghTag"
|
||||
options = [
|
||||
eruby: 'erubis',
|
||||
attributes: [
|
||||
copycss : '',
|
||||
icons : 'font',
|
||||
'source-highlighter': 'prettify',
|
||||
sectanchors : '',
|
||||
toc2: '',
|
||||
idprefix: '',
|
||||
idseparator: '-',
|
||||
doctype: 'book',
|
||||
numbered: '',
|
||||
'spring-security-version' : project.version,
|
||||
'spring-version' : springVersion,
|
||||
revnumber : project.version,
|
||||
'gh-url': ghUrl,
|
||||
'gh-samples-url': "$ghUrl/samples",
|
||||
docinfo : ""
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
reference {
|
||||
sourceDir = new File(asciidoctor.outputDir , 'docbook5')
|
||||
pdfFilename = "spring-security-reference.pdf"
|
||||
epubFilename = "spring-security-reference.epub"
|
||||
expandPlaceholders = ""
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
tasks.findAll { it.name.startsWith("reference") }.each{ it.dependsOn.add("asciidoctor") }
|
||||
}
|
||||
|
||||
|
||||
ext.spec = copySpec {
|
||||
from (reference) {
|
||||
into 'reference'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task apidocs(type: Javadoc) {
|
||||
destinationDir = new File(buildDir, 'apidocs')
|
||||
title = "Spring Security $version API"
|
||||
logging.captureStandardError LogLevel.INFO
|
||||
logging.captureStandardOutput LogLevel.INFO
|
||||
|
||||
source coreModuleProjects.collect { project ->
|
||||
project.sourceSets.main.allJava
|
||||
}
|
||||
|
||||
classpath = files(coreModuleProjects.collect { project ->
|
||||
project.sourceSets.main.compileClasspath
|
||||
})
|
||||
options {
|
||||
outputLevel = org.gradle.external.javadoc.JavadocOutputLevel.QUIET
|
||||
links = [
|
||||
"http://static.springframework.org/spring/docs/3.2.x/javadoc-api",
|
||||
"http://static.springsource.org/spring-ldap/docs/1.3.x/apidocs/",
|
||||
"http://download.oracle.com/javase/6/docs/api/"
|
||||
]
|
||||
groups = [
|
||||
'Spring Security Core':[
|
||||
'org.springframework.security.core*',
|
||||
'org.springframework.security.authentication*',
|
||||
'org.springframework.security.access*',
|
||||
'org.springframework.security.remoting*',
|
||||
'org.springframework.security.provisioning*',
|
||||
'org.springframework.security.util*'],
|
||||
'Spring Security Web':['org.springframework.security.web*'],
|
||||
'Spring Security LDAP':['org.springframework.security.ldap*'],
|
||||
'Spring Security Crypto':['org.springframework.security.crypto*'],
|
||||
'Spring Security OpenID':['org.springframework.security.openid*'],
|
||||
'Spring Security CAS':['org.springframework.security.cas*'],
|
||||
'Spring Security ACL':['org.springframework.security.acls*'],
|
||||
'Spring Security Config':['org.springframework.security.config*'],
|
||||
'Spring Security Taglibs':['org.springframework.security.taglibs*'],
|
||||
|
||||
]
|
||||
addStringOption('-quiet')
|
||||
}
|
||||
}
|
||||
|
||||
if (JavaVersion.current().isJava8Compatible()) {
|
||||
// Turn off doclint in JDK 8 Javadoc (too strict on checks)
|
||||
apidocs.options.addStringOption('Xdoclint:none', '-quiet')
|
||||
}
|
||||
|
||||
ext.apiSpec = copySpec {
|
||||
into('apidocs') {
|
||||
from(apidocs.destinationDir)
|
||||
}
|
||||
}
|
||||
|
||||
assemble.dependsOn = [apidocs, 'manual:asciidoctor']
|
||||
|
||||
task docsZip(type: Zip) {
|
||||
dependsOn docs
|
||||
evaluationDependsOn('guides')
|
||||
group = 'Distribution'
|
||||
baseName = rootProject.name
|
||||
classifier = 'docs'
|
||||
description = "Builds -${classifier} archive containing api and reference " +
|
||||
"for deployment at static.springframework.org/spring-security/site/docs."
|
||||
|
||||
with(project(':docs').apiSpec)
|
||||
with(project(':docs:manual').spec)
|
||||
with(project(':docs:guides').spec)
|
||||
}
|
||||
|
||||
task schemaZip(type: Zip) {
|
||||
group = 'Distribution'
|
||||
baseName = rootProject.name
|
||||
classifier = 'schema'
|
||||
description = "Builds -${classifier} archive containing all " +
|
||||
"XSDs for deployment at static.springframework.org/schema."
|
||||
|
||||
coreModuleProjects.each { module ->
|
||||
def Properties schemas = new Properties();
|
||||
|
||||
module.sourceSets.main.resources.find {
|
||||
it.path.endsWith('META-INF/spring.schemas')
|
||||
}?.withInputStream { schemas.load(it) }
|
||||
|
||||
for (def key : schemas.keySet()) {
|
||||
def shortName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1')
|
||||
assert shortName != key
|
||||
File xsdFile = module.sourceSets.main.resources.find {
|
||||
it.path.endsWith(schemas.get(key))
|
||||
}
|
||||
assert xsdFile != null
|
||||
into (shortName) {
|
||||
from xsdFile.path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
apply plugin: 'io.spring.convention.docs'
|
||||
|
||||
asciidoctor {
|
||||
def ghTag = snapshotBuild ? 'master' : project.version
|
||||
def ghUrl = "https://github.com/spring-projects/spring-security/tree/$ghTag"
|
||||
attributes 'spring-security-version' : project.version,
|
||||
'spring-version' : project(':spring-security-core').dependencyManagement.managedVersions['org.springframework:spring-core'],
|
||||
revnumber : project.version,
|
||||
'gh-url': ghUrl,
|
||||
'gh-samples-url': "$ghUrl/samples"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user