Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad00d78e1a | ||
|
|
5471c94615 | ||
|
|
84cdf82c0d | ||
|
|
45283b42b4 | ||
|
|
142876068d | ||
|
|
ca94d02abc | ||
|
|
628c8bece3 | ||
|
|
f0013fc062 | ||
|
|
aa5133e170 | ||
|
|
5c31fb1b7e | ||
|
|
e5fdee3034 | ||
|
|
ab090445b3 | ||
|
|
8541f6be69 | ||
|
|
ae20f73676 | ||
|
|
4091d69d0c | ||
|
|
c3b254579c | ||
|
|
22bf1eb951 | ||
|
|
35ecdae190 | ||
|
|
b12ffe2ae4 | ||
|
|
117b312ac4 | ||
|
|
f7c84957bb | ||
|
|
5a030568ce | ||
|
|
72ec2633f8 | ||
|
|
0b95672c47 | ||
|
|
d51f12f5d2 | ||
|
|
f3a27101be |
@@ -17,6 +17,8 @@ apply plugin: 'io.spring.convention.root'
|
||||
group = 'org.springframework.security.experimental'
|
||||
description = 'Spring Authorization Server'
|
||||
|
||||
ext.snapshotBuild = version.contains("SNAPSHOT")
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch:0.4.2.RELEASE
|
||||
@@ -0,0 +1,3 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
3
docs/manual/gradle/dependency-locks/compileOnly.lockfile
Normal file
3
docs/manual/gradle/dependency-locks/compileOnly.lockfile
Normal file
@@ -0,0 +1,3 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
3
docs/manual/gradle/dependency-locks/default.lockfile
Normal file
3
docs/manual/gradle/dependency-locks/default.lockfile
Normal file
@@ -0,0 +1,3 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
@@ -0,0 +1,4 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
io.spring.docresources:spring-doc-resources:0.2.1.RELEASE
|
||||
3
docs/manual/gradle/dependency-locks/runtime.lockfile
Normal file
3
docs/manual/gradle/dependency-locks/runtime.lockfile
Normal file
@@ -0,0 +1,3 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
@@ -0,0 +1,3 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
@@ -0,0 +1,3 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
13
docs/manual/gradle/dependency-locks/testCompile.lockfile
Normal file
13
docs/manual/gradle/dependency-locks/testCompile.lockfile
Normal file
@@ -0,0 +1,13 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
junit:junit:4.13.1
|
||||
net.bytebuddy:byte-buddy-agent:1.10.15
|
||||
net.bytebuddy:byte-buddy:1.10.15
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.mockito:mockito-core:3.5.13
|
||||
org.objenesis:objenesis:3.1
|
||||
org.springframework:spring-core:5.2.9.RELEASE
|
||||
org.springframework:spring-jcl:5.2.9.RELEASE
|
||||
org.springframework:spring-test:5.2.9.RELEASE
|
||||
@@ -0,0 +1,13 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
junit:junit:4.13.1
|
||||
net.bytebuddy:byte-buddy-agent:1.10.15
|
||||
net.bytebuddy:byte-buddy:1.10.15
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.mockito:mockito-core:3.5.13
|
||||
org.objenesis:objenesis:3.1
|
||||
org.springframework:spring-core:5.2.9.RELEASE
|
||||
org.springframework:spring-jcl:5.2.9.RELEASE
|
||||
org.springframework:spring-test:5.2.9.RELEASE
|
||||
@@ -0,0 +1,3 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
13
docs/manual/gradle/dependency-locks/testRuntime.lockfile
Normal file
13
docs/manual/gradle/dependency-locks/testRuntime.lockfile
Normal file
@@ -0,0 +1,13 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
junit:junit:4.13.1
|
||||
net.bytebuddy:byte-buddy-agent:1.10.15
|
||||
net.bytebuddy:byte-buddy:1.10.15
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.mockito:mockito-core:3.5.13
|
||||
org.objenesis:objenesis:3.1
|
||||
org.springframework:spring-core:5.2.9.RELEASE
|
||||
org.springframework:spring-jcl:5.2.9.RELEASE
|
||||
org.springframework:spring-test:5.2.9.RELEASE
|
||||
@@ -0,0 +1,13 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
junit:junit:4.13.1
|
||||
net.bytebuddy:byte-buddy-agent:1.10.15
|
||||
net.bytebuddy:byte-buddy:1.10.15
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.mockito:mockito-core:3.5.13
|
||||
org.objenesis:objenesis:3.1
|
||||
org.springframework:spring-core:5.2.9.RELEASE
|
||||
org.springframework:spring-jcl:5.2.9.RELEASE
|
||||
org.springframework:spring-test:5.2.9.RELEASE
|
||||
@@ -0,0 +1,33 @@
|
||||
apply plugin: 'io.spring.convention.docs'
|
||||
apply plugin: 'io.spring.convention.springdependencymangement'
|
||||
apply plugin: 'io.spring.convention.dependency-set'
|
||||
apply plugin: 'io.spring.convention.repository'
|
||||
apply plugin: 'java'
|
||||
|
||||
asciidoctor {
|
||||
attributes([stylesheet: 'css/style.css'])
|
||||
resources {
|
||||
from(sourceDir) {
|
||||
include "css/**"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
asciidoctorj {
|
||||
def ghTag = snapshotBuild ? 'master' : project.version
|
||||
def ghUrl = "https://github.com/spring-projects-experimental/spring-authorization-server/tree/$ghTag"
|
||||
attributes 'spring-authorization-server-version' : project.version,
|
||||
'spring-boot-version' : springBootVersion,
|
||||
revnumber : project.version,
|
||||
'gh-url': ghUrl,
|
||||
'gh-samples-url': "$ghUrl/samples"
|
||||
attributeProvider resolvedVersions(project.configurations.testCompile)
|
||||
}
|
||||
|
||||
def resolvedVersions(Configuration configuration) {
|
||||
return {
|
||||
configuration.resolvedConfiguration
|
||||
.resolvedArtifacts
|
||||
.collectEntries { [(it.name + "-version"): it.moduleVersion.id.version] }
|
||||
}
|
||||
}
|
||||
5
docs/manual/src/docs/asciidoc/css/style.css
Normal file
5
docs/manual/src/docs/asciidoc/css/style.css
Normal file
@@ -0,0 +1,5 @@
|
||||
@import 'spring.css';
|
||||
|
||||
a code {
|
||||
color: #097dff;
|
||||
}
|
||||
15
docs/manual/src/docs/asciidoc/index.adoc
Normal file
15
docs/manual/src/docs/asciidoc/index.adoc
Normal file
@@ -0,0 +1,15 @@
|
||||
= Spring Authorization Server Reference
|
||||
Joe Grandja
|
||||
:include-dir: _includes
|
||||
:security-api-url: https://docs.spring.io/spring-authorization-server/site/docs/current/api/
|
||||
:source-indent: 0
|
||||
:tabsize: 4
|
||||
:toc: left
|
||||
|
||||
== Preface
|
||||
|
||||
#TODO:# Document preface
|
||||
|
||||
== Introduction
|
||||
|
||||
#TODO:# Document introduction
|
||||
@@ -1,5 +1,5 @@
|
||||
version=0.0.1
|
||||
springBootVersion=2.4.0-M2
|
||||
version=0.0.2
|
||||
springBootVersion=2.4.0-M3
|
||||
org.gradle.jvmargs=-Xmx3g -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError
|
||||
org.gradle.parallel=true
|
||||
org.gradle.caching=true
|
||||
|
||||
@@ -3,7 +3,7 @@ if (!project.hasProperty("springVersion")) {
|
||||
}
|
||||
|
||||
if (!project.hasProperty("springSecurityVersion")) {
|
||||
ext.springSecurityVersion = "5.3.+"
|
||||
ext.springSecurityVersion = "5.4.+"
|
||||
}
|
||||
|
||||
if (!project.hasProperty("reactorVersion")) {
|
||||
@@ -21,12 +21,12 @@ dependencyManagement {
|
||||
mavenBom "org.springframework:spring-framework-bom:$springVersion"
|
||||
mavenBom "org.springframework.security:spring-security-bom:$springSecurityVersion"
|
||||
mavenBom "io.projectreactor:reactor-bom:$reactorVersion"
|
||||
mavenBom "com.fasterxml.jackson:jackson-bom:2.+"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
dependency "com.nimbusds:oauth2-oidc-sdk:latest.release"
|
||||
dependency "com.nimbusds:nimbus-jose-jwt:latest.release"
|
||||
dependency "com.fasterxml.jackson.core:jackson-databind:2.+"
|
||||
dependency "javax.servlet:javax.servlet-api:4.+"
|
||||
dependency 'junit:junit:latest.release'
|
||||
dependency 'org.assertj:assertj-core:latest.release'
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-core:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-databind:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-core:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-databind:2.12.0-rc1
|
||||
com.fasterxml.jackson:jackson-bom:2.12.0-rc1
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.springframework.security:spring-security-config:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-jose:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-web:5.3.4.RELEASE
|
||||
org.springframework:spring-aop:5.2.8.RELEASE
|
||||
org.springframework:spring-beans:5.2.8.RELEASE
|
||||
org.springframework:spring-context:5.2.8.RELEASE
|
||||
org.springframework:spring-core:5.2.8.RELEASE
|
||||
org.springframework:spring-expression:5.2.8.RELEASE
|
||||
org.springframework:spring-jcl:5.2.8.RELEASE
|
||||
org.springframework:spring-web:5.2.8.RELEASE
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
org.springframework.security:spring-security-config:5.4.1
|
||||
org.springframework.security:spring-security-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.1
|
||||
org.springframework.security:spring-security-web:5.4.1
|
||||
org.springframework:spring-aop:5.2.9.RELEASE
|
||||
org.springframework:spring-beans:5.2.9.RELEASE
|
||||
org.springframework:spring-context:5.2.9.RELEASE
|
||||
org.springframework:spring-core:5.2.9.RELEASE
|
||||
org.springframework:spring-expression:5.2.9.RELEASE
|
||||
org.springframework:spring-jcl:5.2.9.RELEASE
|
||||
org.springframework:spring-web:5.2.9.RELEASE
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-core:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-databind:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-core:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-databind:2.12.0-rc1
|
||||
com.fasterxml.jackson:jackson-bom:2.12.0-rc1
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.springframework.security:spring-security-config:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-jose:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-web:5.3.4.RELEASE
|
||||
org.springframework:spring-aop:5.2.8.RELEASE
|
||||
org.springframework:spring-beans:5.2.8.RELEASE
|
||||
org.springframework:spring-context:5.2.8.RELEASE
|
||||
org.springframework:spring-core:5.2.8.RELEASE
|
||||
org.springframework:spring-expression:5.2.8.RELEASE
|
||||
org.springframework:spring-jcl:5.2.8.RELEASE
|
||||
org.springframework:spring-web:5.2.8.RELEASE
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
org.springframework.security:spring-security-config:5.4.1
|
||||
org.springframework.security:spring-security-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.1
|
||||
org.springframework.security:spring-security-web:5.4.1
|
||||
org.springframework:spring-aop:5.2.9.RELEASE
|
||||
org.springframework:spring-beans:5.2.9.RELEASE
|
||||
org.springframework:spring-context:5.2.9.RELEASE
|
||||
org.springframework:spring-core:5.2.9.RELEASE
|
||||
org.springframework:spring-expression:5.2.9.RELEASE
|
||||
org.springframework:spring-jcl:5.2.9.RELEASE
|
||||
org.springframework:spring-web:5.2.9.RELEASE
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-core:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-databind:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-core:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-databind:2.12.0-rc1
|
||||
com.fasterxml.jackson:jackson-bom:2.12.0-rc1
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.springframework.security:spring-security-config:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-jose:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-web:5.3.4.RELEASE
|
||||
org.springframework:spring-aop:5.2.8.RELEASE
|
||||
org.springframework:spring-beans:5.2.8.RELEASE
|
||||
org.springframework:spring-context:5.2.8.RELEASE
|
||||
org.springframework:spring-core:5.2.8.RELEASE
|
||||
org.springframework:spring-expression:5.2.8.RELEASE
|
||||
org.springframework:spring-jcl:5.2.8.RELEASE
|
||||
org.springframework:spring-web:5.2.8.RELEASE
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
org.springframework.security:spring-security-config:5.4.1
|
||||
org.springframework.security:spring-security-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.1
|
||||
org.springframework.security:spring-security-web:5.4.1
|
||||
org.springframework:spring-aop:5.2.9.RELEASE
|
||||
org.springframework:spring-beans:5.2.9.RELEASE
|
||||
org.springframework:spring-context:5.2.9.RELEASE
|
||||
org.springframework:spring-core:5.2.9.RELEASE
|
||||
org.springframework:spring-expression:5.2.9.RELEASE
|
||||
org.springframework:spring-jcl:5.2.9.RELEASE
|
||||
org.springframework:spring-web:5.2.9.RELEASE
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-core:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-databind:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-core:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-databind:2.12.0-rc1
|
||||
com.fasterxml.jackson:jackson-bom:2.12.0-rc1
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.springframework.security:spring-security-config:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-jose:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-web:5.3.4.RELEASE
|
||||
org.springframework:spring-aop:5.2.8.RELEASE
|
||||
org.springframework:spring-beans:5.2.8.RELEASE
|
||||
org.springframework:spring-context:5.2.8.RELEASE
|
||||
org.springframework:spring-core:5.2.8.RELEASE
|
||||
org.springframework:spring-expression:5.2.8.RELEASE
|
||||
org.springframework:spring-jcl:5.2.8.RELEASE
|
||||
org.springframework:spring-web:5.2.8.RELEASE
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
org.springframework.security:spring-security-config:5.4.1
|
||||
org.springframework.security:spring-security-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.1
|
||||
org.springframework.security:spring-security-web:5.4.1
|
||||
org.springframework:spring-aop:5.2.9.RELEASE
|
||||
org.springframework:spring-beans:5.2.9.RELEASE
|
||||
org.springframework:spring-context:5.2.9.RELEASE
|
||||
org.springframework:spring-core:5.2.9.RELEASE
|
||||
org.springframework:spring-expression:5.2.9.RELEASE
|
||||
org.springframework:spring-jcl:5.2.9.RELEASE
|
||||
org.springframework:spring-web:5.2.9.RELEASE
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-core:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-databind:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-core:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-databind:2.12.0-rc1
|
||||
com.fasterxml.jackson:jackson-bom:2.12.0-rc1
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.springframework.security:spring-security-config:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-jose:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-web:5.3.4.RELEASE
|
||||
org.springframework:spring-aop:5.2.8.RELEASE
|
||||
org.springframework:spring-beans:5.2.8.RELEASE
|
||||
org.springframework:spring-context:5.2.8.RELEASE
|
||||
org.springframework:spring-core:5.2.8.RELEASE
|
||||
org.springframework:spring-expression:5.2.8.RELEASE
|
||||
org.springframework:spring-jcl:5.2.8.RELEASE
|
||||
org.springframework:spring-web:5.2.8.RELEASE
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
org.springframework.security:spring-security-config:5.4.1
|
||||
org.springframework.security:spring-security-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.1
|
||||
org.springframework.security:spring-security-web:5.4.1
|
||||
org.springframework:spring-aop:5.2.9.RELEASE
|
||||
org.springframework:spring-beans:5.2.9.RELEASE
|
||||
org.springframework:spring-context:5.2.9.RELEASE
|
||||
org.springframework:spring-core:5.2.9.RELEASE
|
||||
org.springframework:spring-expression:5.2.9.RELEASE
|
||||
org.springframework:spring-jcl:5.2.9.RELEASE
|
||||
org.springframework:spring-web:5.2.9.RELEASE
|
||||
|
||||
@@ -1,35 +1,36 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-core:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-databind:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-core:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-databind:2.12.0-rc1
|
||||
com.fasterxml.jackson:jackson-bom:2.12.0-rc1
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.jayway.jsonpath:json-path:2.4.0
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
junit:junit:4.13
|
||||
net.bytebuddy:byte-buddy-agent:1.10.13
|
||||
net.bytebuddy:byte-buddy:1.10.13
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
junit:junit:4.13.1
|
||||
net.bytebuddy:byte-buddy-agent:1.10.15
|
||||
net.bytebuddy:byte-buddy:1.10.15
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.assertj:assertj-core:3.16.1
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.mockito:mockito-core:3.5.2
|
||||
org.mockito:mockito-core:3.5.13
|
||||
org.objenesis:objenesis:3.1
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.slf4j:slf4j-api:1.7.25
|
||||
org.springframework.security:spring-security-config:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-jose:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-test:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-web:5.3.4.RELEASE
|
||||
org.springframework:spring-aop:5.2.8.RELEASE
|
||||
org.springframework:spring-beans:5.2.8.RELEASE
|
||||
org.springframework:spring-context:5.2.8.RELEASE
|
||||
org.springframework:spring-core:5.2.8.RELEASE
|
||||
org.springframework:spring-expression:5.2.8.RELEASE
|
||||
org.springframework:spring-jcl:5.2.8.RELEASE
|
||||
org.springframework:spring-test:5.2.8.RELEASE
|
||||
org.springframework:spring-web:5.2.8.RELEASE
|
||||
org.springframework:spring-webmvc:5.2.8.RELEASE
|
||||
org.springframework.security:spring-security-config:5.4.1
|
||||
org.springframework.security:spring-security-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.1
|
||||
org.springframework.security:spring-security-test:5.4.1
|
||||
org.springframework.security:spring-security-web:5.4.1
|
||||
org.springframework:spring-aop:5.2.9.RELEASE
|
||||
org.springframework:spring-beans:5.2.9.RELEASE
|
||||
org.springframework:spring-context:5.2.9.RELEASE
|
||||
org.springframework:spring-core:5.2.9.RELEASE
|
||||
org.springframework:spring-expression:5.2.9.RELEASE
|
||||
org.springframework:spring-jcl:5.2.9.RELEASE
|
||||
org.springframework:spring-test:5.2.9.RELEASE
|
||||
org.springframework:spring-web:5.2.9.RELEASE
|
||||
org.springframework:spring-webmvc:5.2.9.RELEASE
|
||||
|
||||
@@ -1,35 +1,36 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-core:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-databind:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-core:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-databind:2.12.0-rc1
|
||||
com.fasterxml.jackson:jackson-bom:2.12.0-rc1
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.jayway.jsonpath:json-path:2.4.0
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
junit:junit:4.13
|
||||
net.bytebuddy:byte-buddy-agent:1.10.13
|
||||
net.bytebuddy:byte-buddy:1.10.13
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
junit:junit:4.13.1
|
||||
net.bytebuddy:byte-buddy-agent:1.10.15
|
||||
net.bytebuddy:byte-buddy:1.10.15
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.assertj:assertj-core:3.16.1
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.mockito:mockito-core:3.5.2
|
||||
org.mockito:mockito-core:3.5.13
|
||||
org.objenesis:objenesis:3.1
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.slf4j:slf4j-api:1.7.25
|
||||
org.springframework.security:spring-security-config:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-jose:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-test:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-web:5.3.4.RELEASE
|
||||
org.springframework:spring-aop:5.2.8.RELEASE
|
||||
org.springframework:spring-beans:5.2.8.RELEASE
|
||||
org.springframework:spring-context:5.2.8.RELEASE
|
||||
org.springframework:spring-core:5.2.8.RELEASE
|
||||
org.springframework:spring-expression:5.2.8.RELEASE
|
||||
org.springframework:spring-jcl:5.2.8.RELEASE
|
||||
org.springframework:spring-test:5.2.8.RELEASE
|
||||
org.springframework:spring-web:5.2.8.RELEASE
|
||||
org.springframework:spring-webmvc:5.2.8.RELEASE
|
||||
org.springframework.security:spring-security-config:5.4.1
|
||||
org.springframework.security:spring-security-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.1
|
||||
org.springframework.security:spring-security-test:5.4.1
|
||||
org.springframework.security:spring-security-web:5.4.1
|
||||
org.springframework:spring-aop:5.2.9.RELEASE
|
||||
org.springframework:spring-beans:5.2.9.RELEASE
|
||||
org.springframework:spring-context:5.2.9.RELEASE
|
||||
org.springframework:spring-core:5.2.9.RELEASE
|
||||
org.springframework:spring-expression:5.2.9.RELEASE
|
||||
org.springframework:spring-jcl:5.2.9.RELEASE
|
||||
org.springframework:spring-test:5.2.9.RELEASE
|
||||
org.springframework:spring-web:5.2.9.RELEASE
|
||||
org.springframework:spring-webmvc:5.2.9.RELEASE
|
||||
|
||||
@@ -1,35 +1,36 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-core:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-databind:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-core:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-databind:2.12.0-rc1
|
||||
com.fasterxml.jackson:jackson-bom:2.12.0-rc1
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.jayway.jsonpath:json-path:2.4.0
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
junit:junit:4.13
|
||||
net.bytebuddy:byte-buddy-agent:1.10.13
|
||||
net.bytebuddy:byte-buddy:1.10.13
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
junit:junit:4.13.1
|
||||
net.bytebuddy:byte-buddy-agent:1.10.15
|
||||
net.bytebuddy:byte-buddy:1.10.15
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.assertj:assertj-core:3.16.1
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.mockito:mockito-core:3.5.2
|
||||
org.mockito:mockito-core:3.5.13
|
||||
org.objenesis:objenesis:3.1
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.slf4j:slf4j-api:1.7.25
|
||||
org.springframework.security:spring-security-config:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-jose:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-test:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-web:5.3.4.RELEASE
|
||||
org.springframework:spring-aop:5.2.8.RELEASE
|
||||
org.springframework:spring-beans:5.2.8.RELEASE
|
||||
org.springframework:spring-context:5.2.8.RELEASE
|
||||
org.springframework:spring-core:5.2.8.RELEASE
|
||||
org.springframework:spring-expression:5.2.8.RELEASE
|
||||
org.springframework:spring-jcl:5.2.8.RELEASE
|
||||
org.springframework:spring-test:5.2.8.RELEASE
|
||||
org.springframework:spring-web:5.2.8.RELEASE
|
||||
org.springframework:spring-webmvc:5.2.8.RELEASE
|
||||
org.springframework.security:spring-security-config:5.4.1
|
||||
org.springframework.security:spring-security-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.1
|
||||
org.springframework.security:spring-security-test:5.4.1
|
||||
org.springframework.security:spring-security-web:5.4.1
|
||||
org.springframework:spring-aop:5.2.9.RELEASE
|
||||
org.springframework:spring-beans:5.2.9.RELEASE
|
||||
org.springframework:spring-context:5.2.9.RELEASE
|
||||
org.springframework:spring-core:5.2.9.RELEASE
|
||||
org.springframework:spring-expression:5.2.9.RELEASE
|
||||
org.springframework:spring-jcl:5.2.9.RELEASE
|
||||
org.springframework:spring-test:5.2.9.RELEASE
|
||||
org.springframework:spring-web:5.2.9.RELEASE
|
||||
org.springframework:spring-webmvc:5.2.9.RELEASE
|
||||
|
||||
@@ -1,35 +1,36 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-core:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-databind:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-core:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-databind:2.12.0-rc1
|
||||
com.fasterxml.jackson:jackson-bom:2.12.0-rc1
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.jayway.jsonpath:json-path:2.4.0
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
junit:junit:4.13
|
||||
net.bytebuddy:byte-buddy-agent:1.10.13
|
||||
net.bytebuddy:byte-buddy:1.10.13
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
junit:junit:4.13.1
|
||||
net.bytebuddy:byte-buddy-agent:1.10.15
|
||||
net.bytebuddy:byte-buddy:1.10.15
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.assertj:assertj-core:3.16.1
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.mockito:mockito-core:3.5.2
|
||||
org.mockito:mockito-core:3.5.13
|
||||
org.objenesis:objenesis:3.1
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.slf4j:slf4j-api:1.7.25
|
||||
org.springframework.security:spring-security-config:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-jose:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-test:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-web:5.3.4.RELEASE
|
||||
org.springframework:spring-aop:5.2.8.RELEASE
|
||||
org.springframework:spring-beans:5.2.8.RELEASE
|
||||
org.springframework:spring-context:5.2.8.RELEASE
|
||||
org.springframework:spring-core:5.2.8.RELEASE
|
||||
org.springframework:spring-expression:5.2.8.RELEASE
|
||||
org.springframework:spring-jcl:5.2.8.RELEASE
|
||||
org.springframework:spring-test:5.2.8.RELEASE
|
||||
org.springframework:spring-web:5.2.8.RELEASE
|
||||
org.springframework:spring-webmvc:5.2.8.RELEASE
|
||||
org.springframework.security:spring-security-config:5.4.1
|
||||
org.springframework.security:spring-security-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.1
|
||||
org.springframework.security:spring-security-test:5.4.1
|
||||
org.springframework.security:spring-security-web:5.4.1
|
||||
org.springframework:spring-aop:5.2.9.RELEASE
|
||||
org.springframework:spring-beans:5.2.9.RELEASE
|
||||
org.springframework:spring-context:5.2.9.RELEASE
|
||||
org.springframework:spring-core:5.2.9.RELEASE
|
||||
org.springframework:spring-expression:5.2.9.RELEASE
|
||||
org.springframework:spring-jcl:5.2.9.RELEASE
|
||||
org.springframework:spring-test:5.2.9.RELEASE
|
||||
org.springframework:spring-web:5.2.9.RELEASE
|
||||
org.springframework:spring-webmvc:5.2.9.RELEASE
|
||||
|
||||
@@ -1,35 +1,36 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-core:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-databind:2.11.2
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-core:2.12.0-rc1
|
||||
com.fasterxml.jackson.core:jackson-databind:2.12.0-rc1
|
||||
com.fasterxml.jackson:jackson-bom:2.12.0-rc1
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.jayway.jsonpath:json-path:2.4.0
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
junit:junit:4.13
|
||||
net.bytebuddy:byte-buddy-agent:1.10.13
|
||||
net.bytebuddy:byte-buddy:1.10.13
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
junit:junit:4.13.1
|
||||
net.bytebuddy:byte-buddy-agent:1.10.15
|
||||
net.bytebuddy:byte-buddy:1.10.15
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.assertj:assertj-core:3.16.1
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.mockito:mockito-core:3.5.2
|
||||
org.mockito:mockito-core:3.5.13
|
||||
org.objenesis:objenesis:3.1
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.slf4j:slf4j-api:1.7.25
|
||||
org.springframework.security:spring-security-config:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-core:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-oauth2-jose:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-test:5.3.4.RELEASE
|
||||
org.springframework.security:spring-security-web:5.3.4.RELEASE
|
||||
org.springframework:spring-aop:5.2.8.RELEASE
|
||||
org.springframework:spring-beans:5.2.8.RELEASE
|
||||
org.springframework:spring-context:5.2.8.RELEASE
|
||||
org.springframework:spring-core:5.2.8.RELEASE
|
||||
org.springframework:spring-expression:5.2.8.RELEASE
|
||||
org.springframework:spring-jcl:5.2.8.RELEASE
|
||||
org.springframework:spring-test:5.2.8.RELEASE
|
||||
org.springframework:spring-web:5.2.8.RELEASE
|
||||
org.springframework:spring-webmvc:5.2.8.RELEASE
|
||||
org.springframework.security:spring-security-config:5.4.1
|
||||
org.springframework.security:spring-security-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.1
|
||||
org.springframework.security:spring-security-test:5.4.1
|
||||
org.springframework.security:spring-security-web:5.4.1
|
||||
org.springframework:spring-aop:5.2.9.RELEASE
|
||||
org.springframework:spring-beans:5.2.9.RELEASE
|
||||
org.springframework:spring-context:5.2.9.RELEASE
|
||||
org.springframework:spring-core:5.2.9.RELEASE
|
||||
org.springframework:spring-expression:5.2.9.RELEASE
|
||||
org.springframework:spring-jcl:5.2.9.RELEASE
|
||||
org.springframework:spring-test:5.2.9.RELEASE
|
||||
org.springframework:spring-web:5.2.9.RELEASE
|
||||
org.springframework:spring-webmvc:5.2.9.RELEASE
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
* @author Joe Grandja
|
||||
* @since 0.0.1
|
||||
*/
|
||||
@Configuration
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class OAuth2AuthorizationServerConfiguration {
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -15,11 +15,10 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configuration;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OAuth2AuthorizationServerConfigurer;
|
||||
import org.springframework.security.oauth2.server.authorization.web.OAuth2TokenEndpointFilter;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
|
||||
@@ -31,29 +30,29 @@ import static org.springframework.security.config.Customizer.withDefaults;
|
||||
* @author Joe Grandja
|
||||
* @since 0.0.1
|
||||
*/
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public class OAuth2AuthorizationServerSecurity extends WebSecurityConfigurerAdapter {
|
||||
|
||||
// @formatter:off
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
applyDefaultConfiguration(http);
|
||||
}
|
||||
|
||||
// @formatter:off
|
||||
public static void applyDefaultConfiguration(HttpSecurity http) throws Exception {
|
||||
OAuth2AuthorizationServerConfigurer<HttpSecurity> authorizationServerConfigurer =
|
||||
new OAuth2AuthorizationServerConfigurer<>();
|
||||
RequestMatcher[] endpointMatchers = authorizationServerConfigurer
|
||||
.getEndpointMatchers().toArray(new RequestMatcher[0]);
|
||||
|
||||
http
|
||||
.requestMatcher(new OrRequestMatcher(authorizationServerConfigurer.getEndpointMatchers()))
|
||||
.requestMatcher(new OrRequestMatcher(endpointMatchers))
|
||||
.authorizeRequests(authorizeRequests ->
|
||||
authorizeRequests
|
||||
.anyRequest().authenticated()
|
||||
authorizeRequests.anyRequest().authenticated()
|
||||
)
|
||||
.formLogin(withDefaults())
|
||||
.csrf(csrf -> csrf.ignoringRequestMatchers(tokenEndpointMatcher()))
|
||||
.csrf(csrf -> csrf.ignoringRequestMatchers(endpointMatchers))
|
||||
.apply(authorizationServerConfigurer);
|
||||
}
|
||||
// @formatter:on
|
||||
|
||||
private static RequestMatcher tokenEndpointMatcher() {
|
||||
return new AntPathRequestMatcher(
|
||||
OAuth2TokenEndpointFilter.DEFAULT_TOKEN_ENDPOINT_URI,
|
||||
HttpMethod.POST.name());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
|
||||
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
|
||||
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -63,8 +64,13 @@ import java.util.Map;
|
||||
public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
extends AbstractHttpConfigurer<OAuth2AuthorizationServerConfigurer<B>, B> {
|
||||
|
||||
private final RequestMatcher authorizationEndpointMatcher = new AntPathRequestMatcher(
|
||||
OAuth2AuthorizationEndpointFilter.DEFAULT_AUTHORIZATION_ENDPOINT_URI, HttpMethod.GET.name());
|
||||
private final RequestMatcher authorizationEndpointMatcher = new OrRequestMatcher(
|
||||
new AntPathRequestMatcher(
|
||||
OAuth2AuthorizationEndpointFilter.DEFAULT_AUTHORIZATION_ENDPOINT_URI,
|
||||
HttpMethod.GET.name()),
|
||||
new AntPathRequestMatcher(
|
||||
OAuth2AuthorizationEndpointFilter.DEFAULT_AUTHORIZATION_ENDPOINT_URI,
|
||||
HttpMethod.POST.name()));
|
||||
private final RequestMatcher tokenEndpointMatcher = new AntPathRequestMatcher(
|
||||
OAuth2TokenEndpointFilter.DEFAULT_TOKEN_ENDPOINT_URI, HttpMethod.POST.name());
|
||||
private final RequestMatcher jwkSetEndpointMatcher = new AntPathRequestMatcher(
|
||||
@@ -120,7 +126,8 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
|
||||
public void init(B builder) {
|
||||
OAuth2ClientAuthenticationProvider clientAuthenticationProvider =
|
||||
new OAuth2ClientAuthenticationProvider(
|
||||
getRegisteredClientRepository(builder));
|
||||
getRegisteredClientRepository(builder),
|
||||
getAuthorizationService(builder));
|
||||
builder.authenticationProvider(postProcess(clientAuthenticationProvider));
|
||||
|
||||
NimbusJwsEncoder jwtEncoder = new NimbusJwsEncoder(getKeyManager(builder));
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
package org.springframework.security.crypto.keys;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion2;
|
||||
import org.springframework.security.oauth2.server.authorization.Version;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
@@ -35,7 +35,7 @@ import java.util.Objects;
|
||||
* @see KeyManager
|
||||
*/
|
||||
public final class ManagedKey implements Serializable {
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion2.SERIAL_VERSION_UID;
|
||||
private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
|
||||
private Key key;
|
||||
private PublicKey publicKey;
|
||||
private String keyId;
|
||||
|
||||
@@ -28,7 +28,6 @@ import com.nimbusds.jose.util.Base64;
|
||||
import com.nimbusds.jose.util.Base64URL;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
import net.minidev.json.JSONObject;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.security.crypto.keys.KeyManager;
|
||||
import org.springframework.security.crypto.keys.ManagedKey;
|
||||
@@ -213,7 +212,7 @@ public final class NimbusJwsEncoder implements JwtEncoder {
|
||||
Map<String, Object> jwk = headers.getJwk();
|
||||
if (!CollectionUtils.isEmpty(jwk)) {
|
||||
try {
|
||||
builder.jwk(JWK.parse(new JSONObject(jwk)));
|
||||
builder.jwk(JWK.parse(jwk));
|
||||
} catch (Exception ex) {
|
||||
throw new JwtEncodingException(String.format(
|
||||
ENCODING_ERROR_MESSAGE_TEMPLATE,
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
package org.springframework.security.oauth2.server.authorization;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion2;
|
||||
import org.springframework.security.oauth2.server.authorization.Version;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -43,6 +43,14 @@ public final class InMemoryOAuth2AuthorizationService implements OAuth2Authoriza
|
||||
this.authorizations.put(authorizationId, authorization);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(OAuth2Authorization authorization) {
|
||||
Assert.notNull(authorization, "authorization cannot be null");
|
||||
OAuth2AuthorizationId authorizationId = new OAuth2AuthorizationId(
|
||||
authorization.getRegisteredClientId(), authorization.getPrincipalName());
|
||||
this.authorizations.remove(authorizationId, authorization);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2Authorization findByToken(String token, @Nullable TokenType tokenType) {
|
||||
Assert.hasText(token, "token cannot be empty");
|
||||
@@ -53,7 +61,9 @@ public final class InMemoryOAuth2AuthorizationService implements OAuth2Authoriza
|
||||
}
|
||||
|
||||
private boolean hasToken(OAuth2Authorization authorization, String token, TokenType tokenType) {
|
||||
if (TokenType.AUTHORIZATION_CODE.equals(tokenType)) {
|
||||
if (OAuth2AuthorizationAttributeNames.STATE.equals(tokenType.getValue())) {
|
||||
return token.equals(authorization.getAttribute(OAuth2AuthorizationAttributeNames.STATE));
|
||||
} else if (TokenType.AUTHORIZATION_CODE.equals(tokenType)) {
|
||||
return token.equals(authorization.getAttribute(OAuth2AuthorizationAttributeNames.CODE));
|
||||
} else if (TokenType.ACCESS_TOKEN.equals(tokenType)) {
|
||||
return authorization.getAccessToken() != null &&
|
||||
@@ -63,7 +73,7 @@ public final class InMemoryOAuth2AuthorizationService implements OAuth2Authoriza
|
||||
}
|
||||
|
||||
private static class OAuth2AuthorizationId implements Serializable {
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion2.SERIAL_VERSION_UID;
|
||||
private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
|
||||
private final String registeredClientId;
|
||||
private final String principalName;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.security.oauth2.server.authorization;
|
||||
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion2;
|
||||
import org.springframework.security.oauth2.server.authorization.Version;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -39,7 +39,7 @@ import java.util.function.Consumer;
|
||||
* @see OAuth2AccessToken
|
||||
*/
|
||||
public class OAuth2Authorization implements Serializable {
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion2.SERIAL_VERSION_UID;
|
||||
private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
|
||||
private String registeredClientId;
|
||||
private String principalName;
|
||||
private OAuth2AccessToken accessToken;
|
||||
@@ -146,7 +146,7 @@ public class OAuth2Authorization implements Serializable {
|
||||
* A builder for {@link OAuth2Authorization}.
|
||||
*/
|
||||
public static class Builder implements Serializable {
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion2.SERIAL_VERSION_UID;
|
||||
private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
|
||||
private String registeredClientId;
|
||||
private String principalName;
|
||||
private OAuth2AccessToken accessToken;
|
||||
|
||||
@@ -30,6 +30,11 @@ import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
*/
|
||||
public interface OAuth2AuthorizationAttributeNames {
|
||||
|
||||
/**
|
||||
* The name of the attribute used for correlating the user consent request/response.
|
||||
*/
|
||||
String STATE = OAuth2Authorization.class.getName().concat(".STATE");
|
||||
|
||||
/**
|
||||
* The name of the attribute used for the {@link OAuth2ParameterNames#CODE} parameter.
|
||||
*/
|
||||
@@ -40,6 +45,11 @@ public interface OAuth2AuthorizationAttributeNames {
|
||||
*/
|
||||
String AUTHORIZATION_REQUEST = OAuth2Authorization.class.getName().concat(".AUTHORIZATION_REQUEST");
|
||||
|
||||
/**
|
||||
* The name of the attribute used for the authorized scope(s).
|
||||
*/
|
||||
String AUTHORIZED_SCOPES = OAuth2Authorization.class.getName().concat(".AUTHORIZED_SCOPES");
|
||||
|
||||
/**
|
||||
* The name of the attribute used for the attributes/claims of the {@link OAuth2AccessToken}.
|
||||
*/
|
||||
|
||||
@@ -34,6 +34,13 @@ public interface OAuth2AuthorizationService {
|
||||
*/
|
||||
void save(OAuth2Authorization authorization);
|
||||
|
||||
/**
|
||||
* Removes the {@link OAuth2Authorization}.
|
||||
*
|
||||
* @param authorization the {@link OAuth2Authorization}
|
||||
*/
|
||||
void remove(OAuth2Authorization authorization);
|
||||
|
||||
/**
|
||||
* Returns the {@link OAuth2Authorization} containing the provided {@code token},
|
||||
* or {@code null} if not found.
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.security.oauth2.server.authorization;
|
||||
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion2;
|
||||
import org.springframework.security.oauth2.server.authorization.Version;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -24,7 +24,7 @@ import java.io.Serializable;
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
public final class TokenType implements Serializable {
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion2.SERIAL_VERSION_UID;
|
||||
private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
|
||||
public static final TokenType ACCESS_TOKEN = new TokenType("access_token");
|
||||
public static final TokenType AUTHORIZATION_CODE = new TokenType("authorization_code");
|
||||
private final String value;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.core;
|
||||
package org.springframework.security.oauth2.server.authorization;
|
||||
|
||||
/**
|
||||
* Internal class used for serialization across Spring Security Authorization Server classes.
|
||||
@@ -21,10 +21,10 @@ package org.springframework.security.core;
|
||||
* @author Anoop Garlapati
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public final class SpringSecurityCoreVersion2 {
|
||||
public final class Version {
|
||||
private static final int MAJOR = 0;
|
||||
private static final int MINOR = 0;
|
||||
private static final int PATCH = 1;
|
||||
private static final int PATCH = 2;
|
||||
|
||||
/**
|
||||
* Global Serialization value for Spring Security Authorization Server classes.
|
||||
@@ -17,7 +17,7 @@ package org.springframework.security.oauth2.server.authorization.authentication;
|
||||
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion2;
|
||||
import org.springframework.security.oauth2.server.authorization.Version;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -37,7 +37,7 @@ import java.util.Collections;
|
||||
* @see OAuth2ClientAuthenticationToken
|
||||
*/
|
||||
public class OAuth2AccessTokenAuthenticationToken extends AbstractAuthenticationToken {
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion2.SERIAL_VERSION_UID;
|
||||
private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
|
||||
private final RegisteredClient registeredClient;
|
||||
private final Authentication clientPrincipal;
|
||||
private final OAuth2AccessToken accessToken;
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.springframework.security.oauth2.server.authorization.OAuth2Authorizat
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationAttributeNames;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||
import org.springframework.security.oauth2.server.authorization.TokenType;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -43,11 +44,13 @@ import java.net.URL;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* An {@link AuthenticationProvider} implementation for the OAuth 2.0 Authorization Code Grant.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @author Daniel Garnier-Moiroux
|
||||
* @since 0.0.1
|
||||
* @see OAuth2AuthorizationCodeAuthenticationToken
|
||||
* @see OAuth2AccessTokenAuthenticationToken
|
||||
@@ -91,26 +94,21 @@ public class OAuth2AuthorizationCodeAuthenticationProvider implements Authentica
|
||||
if (clientPrincipal == null || !clientPrincipal.isAuthenticated()) {
|
||||
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_CLIENT));
|
||||
}
|
||||
|
||||
// TODO Authenticate public client
|
||||
// A client MAY use the "client_id" request parameter to identify itself
|
||||
// when sending requests to the token endpoint.
|
||||
// In the "authorization_code" "grant_type" request to the token endpoint,
|
||||
// an unauthenticated client MUST send its "client_id" to prevent itself
|
||||
// from inadvertently accepting a code intended for a client with a different "client_id".
|
||||
// This protects the client from substitution of the authentication code.
|
||||
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
|
||||
|
||||
OAuth2Authorization authorization = this.authorizationService.findByToken(
|
||||
authorizationCodeAuthentication.getCode(), TokenType.AUTHORIZATION_CODE);
|
||||
if (authorization == null) {
|
||||
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT));
|
||||
}
|
||||
if (!clientPrincipal.getRegisteredClient().getId().equals(authorization.getRegisteredClientId())) {
|
||||
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT));
|
||||
}
|
||||
|
||||
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(
|
||||
OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST);
|
||||
|
||||
if (!registeredClient.getClientId().equals(authorizationRequest.getClientId())) {
|
||||
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT));
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(authorizationRequest.getRedirectUri()) &&
|
||||
!authorizationRequest.getRedirectUri().equals(authorizationCodeAuthentication.getRedirectUri())) {
|
||||
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT));
|
||||
@@ -126,15 +124,16 @@ public class OAuth2AuthorizationCodeAuthenticationProvider implements Authentica
|
||||
|
||||
Instant issuedAt = Instant.now();
|
||||
Instant expiresAt = issuedAt.plus(1, ChronoUnit.HOURS); // TODO Allow configuration for access token time-to-live
|
||||
Set<String> authorizedScopes = authorization.getAttribute(OAuth2AuthorizationAttributeNames.AUTHORIZED_SCOPES);
|
||||
|
||||
JwtClaimsSet jwtClaimsSet = JwtClaimsSet.withClaims()
|
||||
.issuer(issuer)
|
||||
.subject(authorization.getPrincipalName())
|
||||
.audience(Collections.singletonList(clientPrincipal.getRegisteredClient().getClientId()))
|
||||
.audience(Collections.singletonList(registeredClient.getClientId()))
|
||||
.issuedAt(issuedAt)
|
||||
.expiresAt(expiresAt)
|
||||
.notBefore(issuedAt)
|
||||
.claim(OAuth2ParameterNames.SCOPE, authorizationRequest.getScopes())
|
||||
.claim(OAuth2ParameterNames.SCOPE, authorizedScopes)
|
||||
.build();
|
||||
|
||||
Jwt jwt = this.jwtEncoder.encode(joseHeader, jwtClaimsSet);
|
||||
@@ -148,8 +147,7 @@ public class OAuth2AuthorizationCodeAuthenticationProvider implements Authentica
|
||||
.build();
|
||||
this.authorizationService.save(authorization);
|
||||
|
||||
return new OAuth2AccessTokenAuthenticationToken(
|
||||
clientPrincipal.getRegisteredClient(), clientPrincipal, accessToken);
|
||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,27 +18,29 @@ package org.springframework.security.oauth2.server.authorization.authentication;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion2;
|
||||
import org.springframework.security.oauth2.server.authorization.Version;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An {@link Authentication} implementation used for the OAuth 2.0 Authorization Code Grant.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @author Madhu Bhat
|
||||
* @author Daniel Garnier-Moiroux
|
||||
* @since 0.0.1
|
||||
* @see AbstractAuthenticationToken
|
||||
* @see OAuth2AuthorizationCodeAuthenticationProvider
|
||||
* @see OAuth2ClientAuthenticationToken
|
||||
*/
|
||||
public class OAuth2AuthorizationCodeAuthenticationToken extends AbstractAuthenticationToken {
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion2.SERIAL_VERSION_UID;
|
||||
private String code;
|
||||
private Authentication clientPrincipal;
|
||||
private String clientId;
|
||||
private String redirectUri;
|
||||
private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
|
||||
private final String code;
|
||||
private final Authentication clientPrincipal;
|
||||
private final String redirectUri;
|
||||
private final Map<String, Object> additionalParameters;
|
||||
|
||||
/**
|
||||
* Constructs an {@code OAuth2AuthorizationCodeAuthenticationToken} using the provided parameters.
|
||||
@@ -46,37 +48,25 @@ public class OAuth2AuthorizationCodeAuthenticationToken extends AbstractAuthenti
|
||||
* @param code the authorization code
|
||||
* @param clientPrincipal the authenticated client principal
|
||||
* @param redirectUri the redirect uri
|
||||
* @param additionalParameters the additional parameters
|
||||
*/
|
||||
public OAuth2AuthorizationCodeAuthenticationToken(String code,
|
||||
Authentication clientPrincipal, @Nullable String redirectUri) {
|
||||
public OAuth2AuthorizationCodeAuthenticationToken(String code, Authentication clientPrincipal,
|
||||
@Nullable String redirectUri, @Nullable Map<String, Object> additionalParameters) {
|
||||
super(Collections.emptyList());
|
||||
Assert.hasText(code, "code cannot be empty");
|
||||
Assert.notNull(clientPrincipal, "clientPrincipal cannot be null");
|
||||
this.code = code;
|
||||
this.clientPrincipal = clientPrincipal;
|
||||
this.redirectUri = redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an {@code OAuth2AuthorizationCodeAuthenticationToken} using the provided parameters.
|
||||
*
|
||||
* @param code the authorization code
|
||||
* @param clientId the client identifier
|
||||
* @param redirectUri the redirect uri
|
||||
*/
|
||||
public OAuth2AuthorizationCodeAuthenticationToken(String code,
|
||||
String clientId, @Nullable String redirectUri) {
|
||||
super(Collections.emptyList());
|
||||
Assert.hasText(code, "code cannot be empty");
|
||||
Assert.hasText(clientId, "clientId cannot be empty");
|
||||
this.code = code;
|
||||
this.clientId = clientId;
|
||||
this.redirectUri = redirectUri;
|
||||
this.additionalParameters = Collections.unmodifiableMap(
|
||||
additionalParameters != null ?
|
||||
additionalParameters :
|
||||
Collections.emptyMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return this.clientPrincipal != null ? this.clientPrincipal : this.clientId;
|
||||
return this.clientPrincipal;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -101,4 +91,13 @@ public class OAuth2AuthorizationCodeAuthenticationToken extends AbstractAuthenti
|
||||
public @Nullable String getRedirectUri() {
|
||||
return this.redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the additional parameters
|
||||
*
|
||||
* @return the additional parameters
|
||||
*/
|
||||
public Map<String, Object> getAdditionalParameters() {
|
||||
return this.additionalParameters;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,49 +18,80 @@ package org.springframework.security.oauth2.server.authorization.authentication;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.core.endpoint.PkceParameterNames;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationAttributeNames;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||
import org.springframework.security.oauth2.server.authorization.TokenType;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An {@link AuthenticationProvider} implementation that validates {@link OAuth2ClientAuthenticationToken}'s.
|
||||
* An {@link AuthenticationProvider} implementation used for authenticating an OAuth 2.0 Client.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @author Patryk Kostrzewa
|
||||
* @author Daniel Garnier-Moiroux
|
||||
* @since 0.0.1
|
||||
* @see AuthenticationProvider
|
||||
* @see OAuth2ClientAuthenticationToken
|
||||
* @see RegisteredClientRepository
|
||||
* @see OAuth2AuthorizationService
|
||||
*/
|
||||
public class OAuth2ClientAuthenticationProvider implements AuthenticationProvider {
|
||||
private final RegisteredClientRepository registeredClientRepository;
|
||||
private final OAuth2AuthorizationService authorizationService;
|
||||
|
||||
/**
|
||||
* Constructs an {@code OAuth2ClientAuthenticationProvider} using the provided parameters.
|
||||
*
|
||||
* @param registeredClientRepository the repository of registered clients
|
||||
* @param authorizationService the authorization service
|
||||
*/
|
||||
public OAuth2ClientAuthenticationProvider(RegisteredClientRepository registeredClientRepository) {
|
||||
public OAuth2ClientAuthenticationProvider(RegisteredClientRepository registeredClientRepository,
|
||||
OAuth2AuthorizationService authorizationService) {
|
||||
Assert.notNull(registeredClientRepository, "registeredClientRepository cannot be null");
|
||||
Assert.notNull(authorizationService, "authorizationService cannot be null");
|
||||
this.registeredClientRepository = registeredClientRepository;
|
||||
this.authorizationService = authorizationService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
String clientId = authentication.getPrincipal().toString();
|
||||
OAuth2ClientAuthenticationToken clientAuthentication =
|
||||
(OAuth2ClientAuthenticationToken) authentication;
|
||||
|
||||
String clientId = clientAuthentication.getPrincipal().toString();
|
||||
RegisteredClient registeredClient = this.registeredClientRepository.findByClientId(clientId);
|
||||
if (registeredClient == null) {
|
||||
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_CLIENT));
|
||||
throwInvalidClient();
|
||||
}
|
||||
|
||||
String clientSecret = authentication.getCredentials().toString();
|
||||
if (!registeredClient.getClientSecret().equals(clientSecret)) {
|
||||
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_CLIENT));
|
||||
if (clientAuthentication.getCredentials() != null) {
|
||||
String clientSecret = clientAuthentication.getCredentials().toString();
|
||||
// TODO Use PasswordEncoder.matches()
|
||||
if (!registeredClient.getClientSecret().equals(clientSecret)) {
|
||||
throwInvalidClient();
|
||||
}
|
||||
}
|
||||
|
||||
authenticatePkceIfAvailable(clientAuthentication, registeredClient);
|
||||
|
||||
return new OAuth2ClientAuthenticationToken(registeredClient);
|
||||
}
|
||||
|
||||
@@ -68,4 +99,65 @@ public class OAuth2ClientAuthenticationProvider implements AuthenticationProvide
|
||||
public boolean supports(Class<?> authentication) {
|
||||
return OAuth2ClientAuthenticationToken.class.isAssignableFrom(authentication);
|
||||
}
|
||||
|
||||
private void authenticatePkceIfAvailable(OAuth2ClientAuthenticationToken clientAuthentication,
|
||||
RegisteredClient registeredClient) {
|
||||
|
||||
Map<String, Object> parameters = clientAuthentication.getAdditionalParameters();
|
||||
if (CollectionUtils.isEmpty(parameters) || !authorizationCodeGrant(parameters)) {
|
||||
return;
|
||||
}
|
||||
|
||||
OAuth2Authorization authorization = this.authorizationService.findByToken(
|
||||
(String) parameters.get(OAuth2ParameterNames.CODE),
|
||||
TokenType.AUTHORIZATION_CODE);
|
||||
if (authorization == null) {
|
||||
throwInvalidClient();
|
||||
}
|
||||
|
||||
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(
|
||||
OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST);
|
||||
|
||||
String codeChallenge = (String) authorizationRequest.getAdditionalParameters()
|
||||
.get(PkceParameterNames.CODE_CHALLENGE);
|
||||
if (StringUtils.hasText(codeChallenge)) {
|
||||
String codeChallengeMethod = (String) authorizationRequest.getAdditionalParameters()
|
||||
.get(PkceParameterNames.CODE_CHALLENGE_METHOD);
|
||||
String codeVerifier = (String) parameters.get(PkceParameterNames.CODE_VERIFIER);
|
||||
if (!codeVerifierValid(codeVerifier, codeChallenge, codeChallengeMethod)) {
|
||||
throwInvalidClient();
|
||||
}
|
||||
} else if (registeredClient.getClientSettings().requireProofKey()) {
|
||||
throwInvalidClient();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean authorizationCodeGrant(Map<String, Object> parameters) {
|
||||
return AuthorizationGrantType.AUTHORIZATION_CODE.getValue().equals(
|
||||
parameters.get(OAuth2ParameterNames.GRANT_TYPE)) &&
|
||||
parameters.get(OAuth2ParameterNames.CODE) != null;
|
||||
}
|
||||
|
||||
private static boolean codeVerifierValid(String codeVerifier, String codeChallenge, String codeChallengeMethod) {
|
||||
if (!StringUtils.hasText(codeVerifier)) {
|
||||
return false;
|
||||
} else if (!StringUtils.hasText(codeChallengeMethod) || "plain".equals(codeChallengeMethod)) {
|
||||
return codeVerifier.equals(codeChallenge);
|
||||
} else if ("S256".equals(codeChallengeMethod)) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
byte[] digest = md.digest(codeVerifier.getBytes(StandardCharsets.US_ASCII));
|
||||
String encodedVerifier = Base64.getUrlEncoder().withoutPadding().encodeToString(digest);
|
||||
return encodedVerifier.equals(codeChallenge);
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
// It is unlikely that SHA-256 is not available on the server. If it is not available,
|
||||
// there will likely be bigger issues as well. We default to SERVER_ERROR.
|
||||
}
|
||||
}
|
||||
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.SERVER_ERROR));
|
||||
}
|
||||
|
||||
private static void throwInvalidClient() {
|
||||
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_CLIENT));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,12 @@ package org.springframework.security.oauth2.server.authorization.authentication;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion2;
|
||||
import org.springframework.security.oauth2.server.authorization.Version;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An {@link Authentication} implementation used for OAuth 2.0 Client Authentication.
|
||||
@@ -35,9 +36,10 @@ import java.util.Collections;
|
||||
* @see OAuth2ClientAuthenticationProvider
|
||||
*/
|
||||
public class OAuth2ClientAuthenticationToken extends AbstractAuthenticationToken {
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion2.SERIAL_VERSION_UID;
|
||||
private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
|
||||
private String clientId;
|
||||
private String clientSecret;
|
||||
private Map<String, Object> additionalParameters;
|
||||
private RegisteredClient registeredClient;
|
||||
|
||||
/**
|
||||
@@ -45,13 +47,28 @@ public class OAuth2ClientAuthenticationToken extends AbstractAuthenticationToken
|
||||
*
|
||||
* @param clientId the client identifier
|
||||
* @param clientSecret the client secret
|
||||
* @param additionalParameters the additional parameters
|
||||
*/
|
||||
public OAuth2ClientAuthenticationToken(String clientId, String clientSecret) {
|
||||
public OAuth2ClientAuthenticationToken(String clientId, String clientSecret,
|
||||
@Nullable Map<String, Object> additionalParameters) {
|
||||
this(clientId, additionalParameters);
|
||||
Assert.hasText(clientSecret, "clientSecret cannot be empty");
|
||||
this.clientSecret = clientSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an {@code OAuth2ClientAuthenticationToken} using the provided parameters.
|
||||
*
|
||||
* @param clientId the client identifier
|
||||
* @param additionalParameters the additional parameters
|
||||
*/
|
||||
public OAuth2ClientAuthenticationToken(String clientId,
|
||||
@Nullable Map<String, Object> additionalParameters) {
|
||||
super(Collections.emptyList());
|
||||
Assert.hasText(clientId, "clientId cannot be empty");
|
||||
Assert.hasText(clientSecret, "clientSecret cannot be empty");
|
||||
this.clientId = clientId;
|
||||
this.clientSecret = clientSecret;
|
||||
this.additionalParameters = additionalParameters != null ?
|
||||
Collections.unmodifiableMap(additionalParameters) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,6 +95,15 @@ public class OAuth2ClientAuthenticationToken extends AbstractAuthenticationToken
|
||||
return this.clientSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the additional parameters
|
||||
*
|
||||
* @return the additional parameters
|
||||
*/
|
||||
public @Nullable Map<String, Object> getAdditionalParameters() {
|
||||
return this.additionalParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link RegisteredClient registered client}.
|
||||
*
|
||||
|
||||
@@ -17,7 +17,7 @@ package org.springframework.security.oauth2.server.authorization.authentication;
|
||||
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion2;
|
||||
import org.springframework.security.oauth2.server.authorization.Version;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -34,7 +34,7 @@ import java.util.Set;
|
||||
* @see OAuth2ClientAuthenticationToken
|
||||
*/
|
||||
public class OAuth2ClientCredentialsAuthenticationToken extends AbstractAuthenticationToken {
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion2.SERIAL_VERSION_UID;
|
||||
private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
|
||||
private final Authentication clientPrincipal;
|
||||
private final Set<String> scopes;
|
||||
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
*/
|
||||
package org.springframework.security.oauth2.server.authorization.client;
|
||||
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion2;
|
||||
import org.springframework.security.oauth2.server.authorization.Version;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||
import org.springframework.security.oauth2.server.authorization.config.ClientSettings;
|
||||
import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@@ -38,7 +40,7 @@ import java.util.function.Consumer;
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public class RegisteredClient implements Serializable {
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion2.SERIAL_VERSION_UID;
|
||||
private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
|
||||
private String id;
|
||||
private String clientId;
|
||||
private String clientSecret;
|
||||
@@ -46,6 +48,8 @@ public class RegisteredClient implements Serializable {
|
||||
private Set<AuthorizationGrantType> authorizationGrantTypes;
|
||||
private Set<String> redirectUris;
|
||||
private Set<String> scopes;
|
||||
private ClientSettings clientSettings;
|
||||
private TokenSettings tokenSettings;
|
||||
|
||||
protected RegisteredClient() {
|
||||
}
|
||||
@@ -114,6 +118,24 @@ public class RegisteredClient implements Serializable {
|
||||
return this.scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ClientSettings client configuration settings}.
|
||||
*
|
||||
* @return the {@link ClientSettings}
|
||||
*/
|
||||
public ClientSettings getClientSettings() {
|
||||
return this.clientSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link TokenSettings token configuration settings}.
|
||||
*
|
||||
* @return the {@link TokenSettings}
|
||||
*/
|
||||
public TokenSettings getTokenSettings() {
|
||||
return this.tokenSettings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RegisteredClient{" +
|
||||
@@ -152,7 +174,7 @@ public class RegisteredClient implements Serializable {
|
||||
* A builder for {@link RegisteredClient}.
|
||||
*/
|
||||
public static class Builder implements Serializable {
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion2.SERIAL_VERSION_UID;
|
||||
private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
|
||||
private String id;
|
||||
private String clientId;
|
||||
private String clientSecret;
|
||||
@@ -160,6 +182,8 @@ public class RegisteredClient implements Serializable {
|
||||
private Set<AuthorizationGrantType> authorizationGrantTypes = new LinkedHashSet<>();
|
||||
private Set<String> redirectUris = new LinkedHashSet<>();
|
||||
private Set<String> scopes = new LinkedHashSet<>();
|
||||
private ClientSettings clientSettings = new ClientSettings();
|
||||
private TokenSettings tokenSettings = new TokenSettings();
|
||||
|
||||
protected Builder(String id) {
|
||||
this.id = id;
|
||||
@@ -181,6 +205,8 @@ public class RegisteredClient implements Serializable {
|
||||
if (!CollectionUtils.isEmpty(registeredClient.scopes)) {
|
||||
this.scopes.addAll(registeredClient.scopes);
|
||||
}
|
||||
this.clientSettings = new ClientSettings(registeredClient.clientSettings.settings());
|
||||
this.tokenSettings = new TokenSettings(registeredClient.tokenSettings.settings());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,6 +336,30 @@ public class RegisteredClient implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link Consumer} of the client configuration settings,
|
||||
* allowing the ability to add, replace, or remove.
|
||||
*
|
||||
* @param clientSettingsConsumer a {@link Consumer} of the client configuration settings
|
||||
* @return the {@link Builder}
|
||||
*/
|
||||
public Builder clientSettings(Consumer<ClientSettings> clientSettingsConsumer) {
|
||||
clientSettingsConsumer.accept(this.clientSettings);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link Consumer} of the token configuration settings,
|
||||
* allowing the ability to add, replace, or remove.
|
||||
*
|
||||
* @param tokenSettingsConsumer a {@link Consumer} of the token configuration settings
|
||||
* @return the {@link Builder}
|
||||
*/
|
||||
public Builder tokenSettings(Consumer<TokenSettings> tokenSettingsConsumer) {
|
||||
tokenSettingsConsumer.accept(this.tokenSettings);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a new {@link RegisteredClient}.
|
||||
*
|
||||
@@ -319,7 +369,6 @@ public class RegisteredClient implements Serializable {
|
||||
Assert.hasText(this.clientId, "clientId cannot be empty");
|
||||
Assert.notEmpty(this.authorizationGrantTypes, "authorizationGrantTypes cannot be empty");
|
||||
if (this.authorizationGrantTypes.contains(AuthorizationGrantType.AUTHORIZATION_CODE)) {
|
||||
Assert.hasText(this.clientSecret, "clientSecret cannot be empty");
|
||||
Assert.notEmpty(this.redirectUris, "redirectUris cannot be empty");
|
||||
}
|
||||
if (CollectionUtils.isEmpty(this.clientAuthenticationMethods)) {
|
||||
@@ -341,6 +390,8 @@ public class RegisteredClient implements Serializable {
|
||||
registeredClient.authorizationGrantTypes = Collections.unmodifiableSet(this.authorizationGrantTypes);
|
||||
registeredClient.redirectUris = Collections.unmodifiableSet(this.redirectUris);
|
||||
registeredClient.scopes = Collections.unmodifiableSet(this.scopes);
|
||||
registeredClient.clientSettings = this.clientSettings;
|
||||
registeredClient.tokenSettings = this.tokenSettings;
|
||||
|
||||
return registeredClient;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.oauth2.server.authorization.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A facility for client configuration settings.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @since 0.0.2
|
||||
* @see Settings
|
||||
*/
|
||||
public class ClientSettings extends Settings {
|
||||
private static final String CLIENT_SETTING_BASE = "spring.security.oauth2.authorization-server.client.";
|
||||
public static final String REQUIRE_PROOF_KEY = CLIENT_SETTING_BASE.concat("require-proof-key");
|
||||
public static final String REQUIRE_USER_CONSENT = CLIENT_SETTING_BASE.concat("require-user-consent");
|
||||
|
||||
/**
|
||||
* Constructs a {@code ClientSettings}.
|
||||
*/
|
||||
public ClientSettings() {
|
||||
this(defaultSettings());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code ClientSettings} using the provided parameters.
|
||||
*
|
||||
* @param settings the initial settings
|
||||
*/
|
||||
public ClientSettings(Map<String, Object> settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the client is required to provide a proof key challenge and verifier
|
||||
* when performing the Authorization Code Grant flow. The default is {@code false}.
|
||||
*
|
||||
* @return {@code true} if the client is required to provide a proof key challenge and verifier, {@code false} otherwise
|
||||
*/
|
||||
public boolean requireProofKey() {
|
||||
return setting(REQUIRE_PROOF_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to {@code true} if the client is required to provide a proof key challenge and verifier
|
||||
* when performing the Authorization Code Grant flow.
|
||||
*
|
||||
* @param requireProofKey {@code true} if the client is required to provide a proof key challenge and verifier, {@code false} otherwise
|
||||
* @return the {@link ClientSettings}
|
||||
*/
|
||||
public ClientSettings requireProofKey(boolean requireProofKey) {
|
||||
setting(REQUIRE_PROOF_KEY, requireProofKey);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the user's consent is required when the client requests access.
|
||||
* The default is {@code false}.
|
||||
*
|
||||
* @return {@code true} if the user's consent is required when the client requests access, {@code false} otherwise
|
||||
*/
|
||||
public boolean requireUserConsent() {
|
||||
return setting(REQUIRE_USER_CONSENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to {@code true} if the user's consent is required when the client requests access.
|
||||
* This applies to all interactive flows (e.g. {@code authorization_code} and {@code device_code}).
|
||||
*
|
||||
* @param requireUserConsent {@code true} if the user's consent is required when the client requests access, {@code false} otherwise
|
||||
* @return the {@link ClientSettings}
|
||||
*/
|
||||
public ClientSettings requireUserConsent(boolean requireUserConsent) {
|
||||
setting(REQUIRE_USER_CONSENT, requireUserConsent);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected static Map<String, Object> defaultSettings() {
|
||||
Map<String, Object> settings = new HashMap<>();
|
||||
settings.put(REQUIRE_PROOF_KEY, false);
|
||||
settings.put(REQUIRE_USER_CONSENT, false);
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.oauth2.server.authorization.config;
|
||||
|
||||
import org.springframework.security.oauth2.server.authorization.Version;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A facility for configuration settings.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @since 0.0.2
|
||||
*/
|
||||
public class Settings implements Serializable {
|
||||
private static final long serialVersionUID = Version.SERIAL_VERSION_UID;
|
||||
private final Map<String, Object> settings;
|
||||
|
||||
/**
|
||||
* Constructs a {@code Settings}.
|
||||
*/
|
||||
public Settings() {
|
||||
this.settings = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code Settings} using the provided parameters.
|
||||
*
|
||||
* @param settings the initial settings
|
||||
*/
|
||||
public Settings(Map<String, Object> settings) {
|
||||
Assert.notNull(settings, "settings cannot be null");
|
||||
this.settings = new HashMap<>(settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a configuration setting.
|
||||
*
|
||||
* @param name the name of the setting
|
||||
* @param <T> the type of the setting
|
||||
* @return the value of the setting, or {@code null} if not available
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T setting(String name) {
|
||||
Assert.hasText(name, "name cannot be empty");
|
||||
return (T) this.settings.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a configuration setting.
|
||||
*
|
||||
* @param name the name of the setting
|
||||
* @param value the value of the setting
|
||||
* @param <T> the type of the {@link Settings}
|
||||
* @return the {@link Settings}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Settings> T setting(String name, Object value) {
|
||||
Assert.hasText(name, "name cannot be empty");
|
||||
Assert.notNull(value, "value cannot be null");
|
||||
this.settings.put(name, value);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Map} of the configuration settings.
|
||||
*
|
||||
* @return a {@code Map} of the configuration settings
|
||||
*/
|
||||
public Map<String, Object> settings() {
|
||||
return this.settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@code Consumer} of the configuration settings {@code Map}
|
||||
* allowing the ability to add, replace, or remove.
|
||||
*
|
||||
* @param settingsConsumer a {@link Consumer} of the configuration settings {@code Map}
|
||||
* @param <T> the type of the {@link Settings}
|
||||
* @return the {@link Settings}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Settings> T settings(Consumer<Map<String, Object>> settingsConsumer) {
|
||||
settingsConsumer.accept(this.settings);
|
||||
return (T) this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.oauth2.server.authorization.config;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A facility for token configuration settings.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @since 0.0.2
|
||||
* @see Settings
|
||||
*/
|
||||
public class TokenSettings extends Settings {
|
||||
private static final String TOKEN_SETTING_BASE = "spring.security.oauth2.authorization-server.token.";
|
||||
public static final String ACCESS_TOKEN_TIME_TO_LIVE = TOKEN_SETTING_BASE.concat("access-token-time-to-live");
|
||||
|
||||
/**
|
||||
* Constructs a {@code TokenSettings}.
|
||||
*/
|
||||
public TokenSettings() {
|
||||
this(defaultSettings());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code TokenSettings} using the provided parameters.
|
||||
*
|
||||
* @param settings the initial settings
|
||||
*/
|
||||
public TokenSettings(Map<String, Object> settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time-to-live for an access token. The default is 5 minutes.
|
||||
*
|
||||
* @return the time-to-live for an access token
|
||||
*/
|
||||
public Duration accessTokenTimeToLive() {
|
||||
return setting(ACCESS_TOKEN_TIME_TO_LIVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time-to-live for an access token.
|
||||
*
|
||||
* @param accessTokenTimeToLive the time-to-live for an access token
|
||||
* @return the {@link TokenSettings}
|
||||
*/
|
||||
public TokenSettings accessTokenTimeToLive(Duration accessTokenTimeToLive) {
|
||||
setting(ACCESS_TOKEN_TIME_TO_LIVE, accessTokenTimeToLive);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected static Map<String, Object> defaultSettings() {
|
||||
Map<String, Object> settings = new HashMap<>();
|
||||
settings.put(ACCESS_TOKEN_TIME_TO_LIVE, Duration.ofMinutes(5));
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,9 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Attempts to extract HTTP Basic credentials from {@link HttpServletRequest}
|
||||
@@ -82,6 +85,15 @@ public class ClientSecretBasicAuthenticationConverter implements AuthenticationC
|
||||
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST), ex);
|
||||
}
|
||||
|
||||
return new OAuth2ClientAuthenticationToken(clientID, clientSecret);
|
||||
return new OAuth2ClientAuthenticationToken(clientID, clientSecret, extractAdditionalParameters(request));
|
||||
}
|
||||
|
||||
private static Map<String, Object> extractAdditionalParameters(HttpServletRequest request) {
|
||||
Map<String, Object> additionalParameters = Collections.emptyMap();
|
||||
if (OAuth2EndpointUtils.matchesPkceTokenRequest(request)) {
|
||||
// Confidential clients can also leverage PKCE
|
||||
additionalParameters = new HashMap<>(OAuth2EndpointUtils.getParameters(request).toSingleValueMap());
|
||||
}
|
||||
return additionalParameters;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.oauth2.server.authorization.web;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* An {@link AuthenticationConverter} that simply delegates to it's
|
||||
* internal {@code List} of {@link AuthenticationConverter}(s).
|
||||
* <p>
|
||||
* Each {@link AuthenticationConverter} is given a chance to
|
||||
* {@link AuthenticationConverter#convert(HttpServletRequest)}
|
||||
* with the first {@code non-null} {@link Authentication} being returned.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @since 0.0.2
|
||||
* @see AuthenticationConverter
|
||||
*/
|
||||
public final class DelegatingAuthenticationConverter implements AuthenticationConverter {
|
||||
private final List<AuthenticationConverter> converters;
|
||||
|
||||
/**
|
||||
* Constructs a {@code DelegatingAuthenticationConverter} using the provided parameters.
|
||||
*
|
||||
* @param converters a {@code List} of {@link AuthenticationConverter}(s)
|
||||
*/
|
||||
public DelegatingAuthenticationConverter(List<AuthenticationConverter> converters) {
|
||||
Assert.notEmpty(converters, "converters cannot be empty");
|
||||
this.converters = Collections.unmodifiableList(new LinkedList<>(converters));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Authentication convert(HttpServletRequest request) {
|
||||
Assert.notNull(request, "request cannot be null");
|
||||
// @formatter:off
|
||||
return this.converters.stream()
|
||||
.map(converter -> converter.convert(request))
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
// @formatter:on
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.security.oauth2.server.authorization.web;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
@@ -48,6 +49,7 @@ public final class DelegatingAuthorizationGrantAuthenticationConverter implement
|
||||
this.converters = Collections.unmodifiableMap(new HashMap<>(converters));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Authentication convert(HttpServletRequest request) {
|
||||
Assert.notNull(request, "request cannot be null");
|
||||
|
||||
@@ -95,7 +95,7 @@ public class JwkSetEndpointFilter extends OncePerRequestFilter {
|
||||
|
||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
try (Writer writer = response.getWriter()) {
|
||||
writer.write(jwkSet.toJSONObject().toString());
|
||||
writer.write(jwkSet.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.security.oauth2.server.authorization.web;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
@@ -28,9 +29,11 @@ import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponseType;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.core.endpoint.PkceParameterNames;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationAttributeNames;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||
import org.springframework.security.oauth2.server.authorization.TokenType;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||
import org.springframework.security.web.DefaultRedirectStrategy;
|
||||
@@ -38,6 +41,7 @@ import org.springframework.security.web.RedirectStrategy;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
@@ -48,10 +52,12 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -60,12 +66,14 @@ import java.util.Set;
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @author Paurav Munshi
|
||||
* @author Daniel Garnier-Moiroux
|
||||
* @since 0.0.1
|
||||
* @see RegisteredClientRepository
|
||||
* @see OAuth2AuthorizationService
|
||||
* @see OAuth2Authorization
|
||||
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1">Section 4.1 Authorization Code Grant</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>
|
||||
*/
|
||||
public class OAuth2AuthorizationEndpointFilter extends OncePerRequestFilter {
|
||||
/**
|
||||
@@ -73,10 +81,14 @@ public class OAuth2AuthorizationEndpointFilter extends OncePerRequestFilter {
|
||||
*/
|
||||
public static final String DEFAULT_AUTHORIZATION_ENDPOINT_URI = "/oauth2/authorize";
|
||||
|
||||
private static final String PKCE_ERROR_URI = "https://tools.ietf.org/html/rfc7636#section-4.4.1";
|
||||
|
||||
private final RegisteredClientRepository registeredClientRepository;
|
||||
private final OAuth2AuthorizationService authorizationService;
|
||||
private final RequestMatcher authorizationEndpointMatcher;
|
||||
private final StringKeyGenerator codeGenerator = new Base64StringKeyGenerator(Base64.getUrlEncoder());
|
||||
private final RequestMatcher authorizationRequestMatcher;
|
||||
private final RequestMatcher userConsentMatcher;
|
||||
private final StringKeyGenerator codeGenerator = new Base64StringKeyGenerator(Base64.getUrlEncoder().withoutPadding(), 96);
|
||||
private final StringKeyGenerator stateGenerator = new Base64StringKeyGenerator(Base64.getUrlEncoder());
|
||||
private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
|
||||
|
||||
/**
|
||||
@@ -104,73 +116,42 @@ public class OAuth2AuthorizationEndpointFilter extends OncePerRequestFilter {
|
||||
Assert.hasText(authorizationEndpointUri, "authorizationEndpointUri cannot be empty");
|
||||
this.registeredClientRepository = registeredClientRepository;
|
||||
this.authorizationService = authorizationService;
|
||||
this.authorizationEndpointMatcher = new AntPathRequestMatcher(
|
||||
this.authorizationRequestMatcher = new AntPathRequestMatcher(
|
||||
authorizationEndpointUri, HttpMethod.GET.name());
|
||||
this.userConsentMatcher = new AntPathRequestMatcher(
|
||||
authorizationEndpointUri, HttpMethod.POST.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
if (!this.authorizationEndpointMatcher.matches(request)) {
|
||||
if (this.authorizationRequestMatcher.matches(request)) {
|
||||
processAuthorizationRequest(request, response, filterChain);
|
||||
} else if (this.userConsentMatcher.matches(request)) {
|
||||
processUserConsent(request, response);
|
||||
} else {
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------
|
||||
// Validate the request to ensure that all required parameters are present and valid
|
||||
// ---------------
|
||||
private void processAuthorizationRequest(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
MultiValueMap<String, String> parameters = OAuth2EndpointUtils.getParameters(request);
|
||||
String stateParameter = parameters.getFirst(OAuth2ParameterNames.STATE);
|
||||
OAuth2AuthorizationRequestContext authorizationRequestContext =
|
||||
new OAuth2AuthorizationRequestContext(
|
||||
request.getRequestURL().toString(),
|
||||
OAuth2EndpointUtils.getParameters(request));
|
||||
|
||||
// client_id (REQUIRED)
|
||||
String clientId = parameters.getFirst(OAuth2ParameterNames.CLIENT_ID);
|
||||
if (!StringUtils.hasText(clientId) ||
|
||||
parameters.get(OAuth2ParameterNames.CLIENT_ID).size() != 1) {
|
||||
OAuth2Error error = createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.CLIENT_ID);
|
||||
sendErrorResponse(request, response, error, stateParameter, null); // when redirectUri is null then don't redirect
|
||||
return;
|
||||
}
|
||||
RegisteredClient registeredClient = this.registeredClientRepository.findByClientId(clientId);
|
||||
if (registeredClient == null) {
|
||||
OAuth2Error error = createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.CLIENT_ID);
|
||||
sendErrorResponse(request, response, error, stateParameter, null); // when redirectUri is null then don't redirect
|
||||
return;
|
||||
} else if (!registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.AUTHORIZATION_CODE)) {
|
||||
OAuth2Error error = createError(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT, OAuth2ParameterNames.CLIENT_ID);
|
||||
sendErrorResponse(request, response, error, stateParameter, null); // when redirectUri is null then don't redirect
|
||||
return;
|
||||
}
|
||||
validateAuthorizationRequest(authorizationRequestContext);
|
||||
|
||||
// redirect_uri (OPTIONAL)
|
||||
String redirectUriParameter = parameters.getFirst(OAuth2ParameterNames.REDIRECT_URI);
|
||||
if (StringUtils.hasText(redirectUriParameter)) {
|
||||
if (!registeredClient.getRedirectUris().contains(redirectUriParameter) ||
|
||||
parameters.get(OAuth2ParameterNames.REDIRECT_URI).size() != 1) {
|
||||
OAuth2Error error = createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.REDIRECT_URI);
|
||||
sendErrorResponse(request, response, error, stateParameter, null); // when redirectUri is null then don't redirect
|
||||
return;
|
||||
if (authorizationRequestContext.hasError()) {
|
||||
if (authorizationRequestContext.isRedirectOnError()) {
|
||||
sendErrorResponse(request, response, authorizationRequestContext.resolveRedirectUri(),
|
||||
authorizationRequestContext.getError(), authorizationRequestContext.getState());
|
||||
} else {
|
||||
sendErrorResponse(response, authorizationRequestContext.getError());
|
||||
}
|
||||
} else if (registeredClient.getRedirectUris().size() != 1) {
|
||||
OAuth2Error error = createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.REDIRECT_URI);
|
||||
sendErrorResponse(request, response, error, stateParameter, null); // when redirectUri is null then don't redirect
|
||||
return;
|
||||
}
|
||||
|
||||
String redirectUri = StringUtils.hasText(redirectUriParameter) ?
|
||||
redirectUriParameter : registeredClient.getRedirectUris().iterator().next();
|
||||
|
||||
// response_type (REQUIRED)
|
||||
String responseType = parameters.getFirst(OAuth2ParameterNames.RESPONSE_TYPE);
|
||||
if (!StringUtils.hasText(responseType) ||
|
||||
parameters.get(OAuth2ParameterNames.RESPONSE_TYPE).size() != 1) {
|
||||
OAuth2Error error = createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.RESPONSE_TYPE);
|
||||
sendErrorResponse(request, response, error, stateParameter, redirectUri);
|
||||
return;
|
||||
} else if (!responseType.equals(OAuth2AuthorizationResponseType.CODE.getValue())) {
|
||||
OAuth2Error error = createError(OAuth2ErrorCodes.UNSUPPORTED_RESPONSE_TYPE, OAuth2ParameterNames.RESPONSE_TYPE);
|
||||
sendErrorResponse(request, response, error, stateParameter, redirectUri);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -186,48 +167,241 @@ public class OAuth2AuthorizationEndpointFilter extends OncePerRequestFilter {
|
||||
return;
|
||||
}
|
||||
|
||||
String code = this.codeGenerator.generateKey();
|
||||
OAuth2AuthorizationRequest authorizationRequest = convertAuthorizationRequest(request);
|
||||
|
||||
OAuth2Authorization authorization = OAuth2Authorization.withRegisteredClient(registeredClient)
|
||||
RegisteredClient registeredClient = authorizationRequestContext.getRegisteredClient();
|
||||
OAuth2AuthorizationRequest authorizationRequest = authorizationRequestContext.buildAuthorizationRequest();
|
||||
OAuth2Authorization.Builder builder = OAuth2Authorization.withRegisteredClient(registeredClient)
|
||||
.principalName(principal.getName())
|
||||
.attribute(OAuth2AuthorizationAttributeNames.CODE, code)
|
||||
.attribute(OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST, authorizationRequest)
|
||||
.build();
|
||||
.attribute(OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST, authorizationRequest);
|
||||
|
||||
if (registeredClient.getClientSettings().requireUserConsent()) {
|
||||
String state = this.stateGenerator.generateKey();
|
||||
OAuth2Authorization authorization = builder
|
||||
.attribute(OAuth2AuthorizationAttributeNames.STATE, state)
|
||||
.build();
|
||||
this.authorizationService.save(authorization);
|
||||
|
||||
// TODO Need to remove 'in-flight' authorization if consent step is not completed (e.g. approved or cancelled)
|
||||
|
||||
UserConsentPage.displayConsent(request, response, registeredClient, authorization);
|
||||
} else {
|
||||
String code = this.codeGenerator.generateKey();
|
||||
OAuth2Authorization authorization = builder
|
||||
.attribute(OAuth2AuthorizationAttributeNames.CODE, code)
|
||||
.attribute(OAuth2AuthorizationAttributeNames.AUTHORIZED_SCOPES, authorizationRequest.getScopes())
|
||||
.build();
|
||||
this.authorizationService.save(authorization);
|
||||
|
||||
// TODO security checks for code parameter
|
||||
// The authorization code MUST expire shortly after it is issued to mitigate the risk of leaks.
|
||||
// A maximum authorization code lifetime of 10 minutes is RECOMMENDED.
|
||||
// The client MUST NOT use the authorization code more than once.
|
||||
// If an authorization code is used more than once, the authorization server MUST deny the request
|
||||
// and SHOULD revoke (when possible) all tokens previously issued based on that authorization code.
|
||||
// The authorization code is bound to the client identifier and redirection URI.
|
||||
|
||||
sendAuthorizationResponse(request, response,
|
||||
authorizationRequestContext.resolveRedirectUri(), code, authorizationRequest.getState());
|
||||
}
|
||||
}
|
||||
|
||||
private void processUserConsent(HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException {
|
||||
|
||||
UserConsentRequestContext userConsentRequestContext =
|
||||
new UserConsentRequestContext(
|
||||
request.getRequestURL().toString(),
|
||||
OAuth2EndpointUtils.getParameters(request));
|
||||
|
||||
validateUserConsentRequest(userConsentRequestContext);
|
||||
|
||||
if (userConsentRequestContext.hasError()) {
|
||||
if (userConsentRequestContext.isRedirectOnError()) {
|
||||
sendErrorResponse(request, response, userConsentRequestContext.resolveRedirectUri(),
|
||||
userConsentRequestContext.getError(), userConsentRequestContext.getState());
|
||||
} else {
|
||||
sendErrorResponse(response, userConsentRequestContext.getError());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!UserConsentPage.isConsentApproved(request)) {
|
||||
this.authorizationService.remove(userConsentRequestContext.getAuthorization());
|
||||
OAuth2Error error = createError(OAuth2ErrorCodes.ACCESS_DENIED, OAuth2ParameterNames.CLIENT_ID);
|
||||
sendErrorResponse(request, response, userConsentRequestContext.resolveRedirectUri(),
|
||||
error, userConsentRequestContext.getAuthorizationRequest().getState());
|
||||
return;
|
||||
}
|
||||
|
||||
String code = this.codeGenerator.generateKey();
|
||||
OAuth2Authorization authorization = OAuth2Authorization.from(userConsentRequestContext.getAuthorization())
|
||||
.attributes(attrs -> {
|
||||
attrs.remove(OAuth2AuthorizationAttributeNames.STATE);
|
||||
attrs.put(OAuth2AuthorizationAttributeNames.CODE, code);
|
||||
attrs.put(OAuth2AuthorizationAttributeNames.AUTHORIZED_SCOPES, userConsentRequestContext.getScopes());
|
||||
})
|
||||
.build();
|
||||
this.authorizationService.save(authorization);
|
||||
|
||||
// TODO security checks for code parameter
|
||||
// The authorization code MUST expire shortly after it is issued to mitigate the risk of leaks.
|
||||
// A maximum authorization code lifetime of 10 minutes is RECOMMENDED.
|
||||
// The client MUST NOT use the authorization code more than once.
|
||||
// If an authorization code is used more than once, the authorization server MUST deny the request
|
||||
// and SHOULD revoke (when possible) all tokens previously issued based on that authorization code.
|
||||
// The authorization code is bound to the client identifier and redirection URI.
|
||||
sendAuthorizationResponse(request, response, userConsentRequestContext.resolveRedirectUri(),
|
||||
code, userConsentRequestContext.getAuthorizationRequest().getState());
|
||||
}
|
||||
|
||||
sendAuthorizationResponse(request, response, authorizationRequest, code, redirectUri);
|
||||
private void validateAuthorizationRequest(OAuth2AuthorizationRequestContext authorizationRequestContext) {
|
||||
// ---------------
|
||||
// Validate the request to ensure all required parameters are present and valid
|
||||
// ---------------
|
||||
|
||||
// client_id (REQUIRED)
|
||||
if (!StringUtils.hasText(authorizationRequestContext.getClientId()) ||
|
||||
authorizationRequestContext.getParameters().get(OAuth2ParameterNames.CLIENT_ID).size() != 1) {
|
||||
authorizationRequestContext.setError(
|
||||
createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.CLIENT_ID));
|
||||
return;
|
||||
}
|
||||
RegisteredClient registeredClient = this.registeredClientRepository.findByClientId(
|
||||
authorizationRequestContext.getClientId());
|
||||
if (registeredClient == null) {
|
||||
authorizationRequestContext.setError(
|
||||
createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.CLIENT_ID));
|
||||
return;
|
||||
} else if (!registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.AUTHORIZATION_CODE)) {
|
||||
authorizationRequestContext.setError(
|
||||
createError(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT, OAuth2ParameterNames.CLIENT_ID));
|
||||
return;
|
||||
}
|
||||
authorizationRequestContext.setRegisteredClient(registeredClient);
|
||||
|
||||
// redirect_uri (OPTIONAL)
|
||||
if (StringUtils.hasText(authorizationRequestContext.getRedirectUri())) {
|
||||
if (!registeredClient.getRedirectUris().contains(authorizationRequestContext.getRedirectUri()) ||
|
||||
authorizationRequestContext.getParameters().get(OAuth2ParameterNames.REDIRECT_URI).size() != 1) {
|
||||
authorizationRequestContext.setError(
|
||||
createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.REDIRECT_URI));
|
||||
return;
|
||||
}
|
||||
} else if (registeredClient.getRedirectUris().size() != 1) {
|
||||
authorizationRequestContext.setError(
|
||||
createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.REDIRECT_URI));
|
||||
return;
|
||||
}
|
||||
authorizationRequestContext.setRedirectOnError(true);
|
||||
|
||||
// response_type (REQUIRED)
|
||||
if (!StringUtils.hasText(authorizationRequestContext.getResponseType()) ||
|
||||
authorizationRequestContext.getParameters().get(OAuth2ParameterNames.RESPONSE_TYPE).size() != 1) {
|
||||
authorizationRequestContext.setError(
|
||||
createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.RESPONSE_TYPE));
|
||||
return;
|
||||
} else if (!authorizationRequestContext.getResponseType().equals(OAuth2AuthorizationResponseType.CODE.getValue())) {
|
||||
authorizationRequestContext.setError(
|
||||
createError(OAuth2ErrorCodes.UNSUPPORTED_RESPONSE_TYPE, OAuth2ParameterNames.RESPONSE_TYPE));
|
||||
return;
|
||||
}
|
||||
|
||||
// scope (OPTIONAL)
|
||||
Set<String> requestedScopes = authorizationRequestContext.getScopes();
|
||||
Set<String> allowedScopes = registeredClient.getScopes();
|
||||
if (!requestedScopes.isEmpty() && !allowedScopes.containsAll(requestedScopes)) {
|
||||
authorizationRequestContext.setError(
|
||||
createError(OAuth2ErrorCodes.INVALID_SCOPE, OAuth2ParameterNames.SCOPE));
|
||||
return;
|
||||
}
|
||||
|
||||
// code_challenge (REQUIRED for public clients) - RFC 7636 (PKCE)
|
||||
String codeChallenge = authorizationRequestContext.getParameters().getFirst(PkceParameterNames.CODE_CHALLENGE);
|
||||
if (StringUtils.hasText(codeChallenge)) {
|
||||
if (authorizationRequestContext.getParameters().get(PkceParameterNames.CODE_CHALLENGE).size() != 1) {
|
||||
authorizationRequestContext.setError(
|
||||
createError(OAuth2ErrorCodes.INVALID_REQUEST, PkceParameterNames.CODE_CHALLENGE, PKCE_ERROR_URI));
|
||||
return;
|
||||
}
|
||||
|
||||
String codeChallengeMethod = authorizationRequestContext.getParameters().getFirst(PkceParameterNames.CODE_CHALLENGE_METHOD);
|
||||
if (StringUtils.hasText(codeChallengeMethod)) {
|
||||
if (authorizationRequestContext.getParameters().get(PkceParameterNames.CODE_CHALLENGE_METHOD).size() != 1 ||
|
||||
(!"S256".equals(codeChallengeMethod) && !"plain".equals(codeChallengeMethod))) {
|
||||
authorizationRequestContext.setError(
|
||||
createError(OAuth2ErrorCodes.INVALID_REQUEST, PkceParameterNames.CODE_CHALLENGE_METHOD, PKCE_ERROR_URI));
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (registeredClient.getClientSettings().requireProofKey()) {
|
||||
authorizationRequestContext.setError(
|
||||
createError(OAuth2ErrorCodes.INVALID_REQUEST, PkceParameterNames.CODE_CHALLENGE, PKCE_ERROR_URI));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void validateUserConsentRequest(UserConsentRequestContext userConsentRequestContext) {
|
||||
// ---------------
|
||||
// Validate the request to ensure all required parameters are present and valid
|
||||
// ---------------
|
||||
|
||||
// state (REQUIRED)
|
||||
if (!StringUtils.hasText(userConsentRequestContext.getState()) ||
|
||||
userConsentRequestContext.getParameters().get(OAuth2ParameterNames.STATE).size() != 1) {
|
||||
userConsentRequestContext.setError(
|
||||
createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.STATE));
|
||||
return;
|
||||
}
|
||||
OAuth2Authorization authorization = this.authorizationService.findByToken(
|
||||
userConsentRequestContext.getState(), new TokenType(OAuth2AuthorizationAttributeNames.STATE));
|
||||
if (authorization == null) {
|
||||
userConsentRequestContext.setError(
|
||||
createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.STATE));
|
||||
return;
|
||||
}
|
||||
userConsentRequestContext.setAuthorization(authorization);
|
||||
|
||||
// The 'in-flight' authorization must be associated to the current principal
|
||||
Authentication principal = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (!isPrincipalAuthenticated(principal) || !principal.getName().equals(authorization.getPrincipalName())) {
|
||||
userConsentRequestContext.setError(
|
||||
createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.STATE));
|
||||
return;
|
||||
}
|
||||
|
||||
// client_id (REQUIRED)
|
||||
if (!StringUtils.hasText(userConsentRequestContext.getClientId()) ||
|
||||
userConsentRequestContext.getParameters().get(OAuth2ParameterNames.CLIENT_ID).size() != 1) {
|
||||
userConsentRequestContext.setError(
|
||||
createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.CLIENT_ID));
|
||||
return;
|
||||
}
|
||||
RegisteredClient registeredClient = this.registeredClientRepository.findByClientId(
|
||||
userConsentRequestContext.getClientId());
|
||||
if (registeredClient == null || !registeredClient.getId().equals(authorization.getRegisteredClientId())) {
|
||||
userConsentRequestContext.setError(
|
||||
createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.CLIENT_ID));
|
||||
return;
|
||||
}
|
||||
userConsentRequestContext.setRegisteredClient(registeredClient);
|
||||
userConsentRequestContext.setRedirectOnError(true);
|
||||
|
||||
// scope (OPTIONAL)
|
||||
Set<String> requestedScopes = userConsentRequestContext.getAuthorizationRequest().getScopes();
|
||||
Set<String> authorizedScopes = userConsentRequestContext.getScopes();
|
||||
if (!authorizedScopes.isEmpty() && !requestedScopes.containsAll(authorizedScopes)) {
|
||||
userConsentRequestContext.setError(
|
||||
createError(OAuth2ErrorCodes.INVALID_SCOPE, OAuth2ParameterNames.SCOPE));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void sendAuthorizationResponse(HttpServletRequest request, HttpServletResponse response,
|
||||
OAuth2AuthorizationRequest authorizationRequest, String code, String redirectUri) throws IOException {
|
||||
String redirectUri, String code, String state) throws IOException {
|
||||
|
||||
UriComponentsBuilder uriBuilder = UriComponentsBuilder
|
||||
.fromUriString(redirectUri)
|
||||
.queryParam(OAuth2ParameterNames.CODE, code);
|
||||
if (StringUtils.hasText(authorizationRequest.getState())) {
|
||||
uriBuilder.queryParam(OAuth2ParameterNames.STATE, authorizationRequest.getState());
|
||||
if (StringUtils.hasText(state)) {
|
||||
uriBuilder.queryParam(OAuth2ParameterNames.STATE, state);
|
||||
}
|
||||
this.redirectStrategy.sendRedirect(request, response, uriBuilder.toUriString());
|
||||
}
|
||||
|
||||
private void sendErrorResponse(HttpServletRequest request, HttpServletResponse response,
|
||||
OAuth2Error error, String state, String redirectUri) throws IOException {
|
||||
|
||||
if (redirectUri == null) {
|
||||
// TODO Send default html error response
|
||||
response.sendError(HttpStatus.BAD_REQUEST.value(), error.toString());
|
||||
return;
|
||||
}
|
||||
String redirectUri, OAuth2Error error, String state) throws IOException {
|
||||
|
||||
UriComponentsBuilder uriBuilder = UriComponentsBuilder
|
||||
.fromUriString(redirectUri)
|
||||
@@ -244,9 +418,17 @@ public class OAuth2AuthorizationEndpointFilter extends OncePerRequestFilter {
|
||||
this.redirectStrategy.sendRedirect(request, response, uriBuilder.toUriString());
|
||||
}
|
||||
|
||||
private void sendErrorResponse(HttpServletResponse response, OAuth2Error error) throws IOException {
|
||||
// TODO Send default html error response
|
||||
response.sendError(HttpStatus.BAD_REQUEST.value(), error.toString());
|
||||
}
|
||||
|
||||
private static OAuth2Error createError(String errorCode, String parameterName) {
|
||||
return new OAuth2Error(errorCode, "OAuth 2.0 Parameter: " + parameterName,
|
||||
"https://tools.ietf.org/html/rfc6749#section-4.1.2.1");
|
||||
return createError(errorCode, parameterName, "https://tools.ietf.org/html/rfc6749#section-4.1.2.1");
|
||||
}
|
||||
|
||||
private static OAuth2Error createError(String errorCode, String parameterName, String errorUri) {
|
||||
return new OAuth2Error(errorCode, "OAuth 2.0 Parameter: " + parameterName, errorUri);
|
||||
}
|
||||
|
||||
private static boolean isPrincipalAuthenticated(Authentication principal) {
|
||||
@@ -255,29 +437,254 @@ public class OAuth2AuthorizationEndpointFilter extends OncePerRequestFilter {
|
||||
principal.isAuthenticated();
|
||||
}
|
||||
|
||||
private static OAuth2AuthorizationRequest convertAuthorizationRequest(HttpServletRequest request) {
|
||||
MultiValueMap<String, String> parameters = OAuth2EndpointUtils.getParameters(request);
|
||||
private static class OAuth2AuthorizationRequestContext extends AbstractRequestContext {
|
||||
private final String responseType;
|
||||
private final String redirectUri;
|
||||
|
||||
Set<String> scopes = Collections.emptySet();
|
||||
if (parameters.containsKey(OAuth2ParameterNames.SCOPE)) {
|
||||
String scope = parameters.getFirst(OAuth2ParameterNames.SCOPE);
|
||||
scopes = new HashSet<>(Arrays.asList(StringUtils.delimitedListToStringArray(scope, " ")));
|
||||
private OAuth2AuthorizationRequestContext(
|
||||
String authorizationUri, MultiValueMap<String, String> parameters) {
|
||||
super(authorizationUri, parameters,
|
||||
parameters.getFirst(OAuth2ParameterNames.CLIENT_ID),
|
||||
parameters.getFirst(OAuth2ParameterNames.STATE),
|
||||
extractScopes(parameters));
|
||||
this.responseType = parameters.getFirst(OAuth2ParameterNames.RESPONSE_TYPE);
|
||||
this.redirectUri = parameters.getFirst(OAuth2ParameterNames.REDIRECT_URI);
|
||||
}
|
||||
|
||||
return OAuth2AuthorizationRequest.authorizationCode()
|
||||
.authorizationUri(request.getRequestURL().toString())
|
||||
.clientId(parameters.getFirst(OAuth2ParameterNames.CLIENT_ID))
|
||||
.redirectUri(parameters.getFirst(OAuth2ParameterNames.REDIRECT_URI))
|
||||
.scopes(scopes)
|
||||
.state(parameters.getFirst(OAuth2ParameterNames.STATE))
|
||||
.additionalParameters(additionalParameters ->
|
||||
parameters.entrySet().stream()
|
||||
.filter(e -> !e.getKey().equals(OAuth2ParameterNames.RESPONSE_TYPE) &&
|
||||
!e.getKey().equals(OAuth2ParameterNames.CLIENT_ID) &&
|
||||
!e.getKey().equals(OAuth2ParameterNames.REDIRECT_URI) &&
|
||||
!e.getKey().equals(OAuth2ParameterNames.SCOPE) &&
|
||||
!e.getKey().equals(OAuth2ParameterNames.STATE))
|
||||
.forEach(e -> additionalParameters.put(e.getKey(), e.getValue().get(0))))
|
||||
.build();
|
||||
private static Set<String> extractScopes(MultiValueMap<String, String> parameters) {
|
||||
String scope = parameters.getFirst(OAuth2ParameterNames.SCOPE);
|
||||
return StringUtils.hasText(scope) ?
|
||||
new HashSet<>(Arrays.asList(StringUtils.delimitedListToStringArray(scope, " "))) :
|
||||
Collections.emptySet();
|
||||
}
|
||||
|
||||
private String getResponseType() {
|
||||
return this.responseType;
|
||||
}
|
||||
|
||||
private String getRedirectUri() {
|
||||
return this.redirectUri;
|
||||
}
|
||||
|
||||
protected String resolveRedirectUri() {
|
||||
return StringUtils.hasText(getRedirectUri()) ?
|
||||
getRedirectUri() :
|
||||
getRegisteredClient().getRedirectUris().iterator().next();
|
||||
}
|
||||
|
||||
private OAuth2AuthorizationRequest buildAuthorizationRequest() {
|
||||
return OAuth2AuthorizationRequest.authorizationCode()
|
||||
.authorizationUri(getAuthorizationUri())
|
||||
.clientId(getClientId())
|
||||
.redirectUri(getRedirectUri())
|
||||
.scopes(getScopes())
|
||||
.state(getState())
|
||||
.additionalParameters(additionalParameters ->
|
||||
getParameters().entrySet().stream()
|
||||
.filter(e -> !e.getKey().equals(OAuth2ParameterNames.RESPONSE_TYPE) &&
|
||||
!e.getKey().equals(OAuth2ParameterNames.CLIENT_ID) &&
|
||||
!e.getKey().equals(OAuth2ParameterNames.REDIRECT_URI) &&
|
||||
!e.getKey().equals(OAuth2ParameterNames.SCOPE) &&
|
||||
!e.getKey().equals(OAuth2ParameterNames.STATE))
|
||||
.forEach(e -> additionalParameters.put(e.getKey(), e.getValue().get(0))))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
private static class UserConsentRequestContext extends AbstractRequestContext {
|
||||
private OAuth2Authorization authorization;
|
||||
|
||||
private UserConsentRequestContext(
|
||||
String authorizationUri, MultiValueMap<String, String> parameters) {
|
||||
super(authorizationUri, parameters,
|
||||
parameters.getFirst(OAuth2ParameterNames.CLIENT_ID),
|
||||
parameters.getFirst(OAuth2ParameterNames.STATE),
|
||||
extractScopes(parameters));
|
||||
}
|
||||
|
||||
private static Set<String> extractScopes(MultiValueMap<String, String> parameters) {
|
||||
List<String> scope = parameters.get(OAuth2ParameterNames.SCOPE);
|
||||
return !CollectionUtils.isEmpty(scope) ? new HashSet<>(scope) : Collections.emptySet();
|
||||
}
|
||||
|
||||
private OAuth2Authorization getAuthorization() {
|
||||
return this.authorization;
|
||||
}
|
||||
|
||||
private void setAuthorization(OAuth2Authorization authorization) {
|
||||
this.authorization = authorization;
|
||||
}
|
||||
|
||||
protected String resolveRedirectUri() {
|
||||
OAuth2AuthorizationRequest authorizationRequest = getAuthorizationRequest();
|
||||
return StringUtils.hasText(authorizationRequest.getRedirectUri()) ?
|
||||
authorizationRequest.getRedirectUri() :
|
||||
getRegisteredClient().getRedirectUris().iterator().next();
|
||||
}
|
||||
|
||||
private OAuth2AuthorizationRequest getAuthorizationRequest() {
|
||||
return getAuthorization().getAttribute(OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
private abstract static class AbstractRequestContext {
|
||||
private final String authorizationUri;
|
||||
private final MultiValueMap<String, String> parameters;
|
||||
private final String clientId;
|
||||
private final String state;
|
||||
private final Set<String> scopes;
|
||||
private RegisteredClient registeredClient;
|
||||
private OAuth2Error error;
|
||||
private boolean redirectOnError;
|
||||
|
||||
protected AbstractRequestContext(String authorizationUri, MultiValueMap<String, String> parameters,
|
||||
String clientId, String state, Set<String> scopes) {
|
||||
this.authorizationUri = authorizationUri;
|
||||
this.parameters = parameters;
|
||||
this.clientId = clientId;
|
||||
this.state = state;
|
||||
this.scopes = scopes;
|
||||
}
|
||||
|
||||
protected String getAuthorizationUri() {
|
||||
return this.authorizationUri;
|
||||
}
|
||||
|
||||
protected MultiValueMap<String, String> getParameters() {
|
||||
return this.parameters;
|
||||
}
|
||||
|
||||
protected String getClientId() {
|
||||
return this.clientId;
|
||||
}
|
||||
|
||||
protected String getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
protected Set<String> getScopes() {
|
||||
return this.scopes;
|
||||
}
|
||||
|
||||
protected RegisteredClient getRegisteredClient() {
|
||||
return this.registeredClient;
|
||||
}
|
||||
|
||||
protected void setRegisteredClient(RegisteredClient registeredClient) {
|
||||
this.registeredClient = registeredClient;
|
||||
}
|
||||
|
||||
protected OAuth2Error getError() {
|
||||
return this.error;
|
||||
}
|
||||
|
||||
protected void setError(OAuth2Error error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
protected boolean hasError() {
|
||||
return getError() != null;
|
||||
}
|
||||
|
||||
protected boolean isRedirectOnError() {
|
||||
return this.redirectOnError;
|
||||
}
|
||||
|
||||
protected void setRedirectOnError(boolean redirectOnError) {
|
||||
this.redirectOnError = redirectOnError;
|
||||
}
|
||||
|
||||
protected abstract String resolveRedirectUri();
|
||||
}
|
||||
|
||||
private static class UserConsentPage {
|
||||
private static final MediaType TEXT_HTML_UTF8 = new MediaType("text", "html", StandardCharsets.UTF_8);
|
||||
private static final String CONSENT_ACTION_PARAMETER_NAME = "consent_action";
|
||||
private static final String CONSENT_ACTION_APPROVE = "approve";
|
||||
private static final String CONSENT_ACTION_CANCEL = "cancel";
|
||||
|
||||
private static void displayConsent(HttpServletRequest request, HttpServletResponse response,
|
||||
RegisteredClient registeredClient, OAuth2Authorization authorization) throws IOException {
|
||||
|
||||
String consentPage = generateConsentPage(request, registeredClient, authorization);
|
||||
response.setContentType(TEXT_HTML_UTF8.toString());
|
||||
response.setContentLength(consentPage.getBytes(StandardCharsets.UTF_8).length);
|
||||
response.getWriter().write(consentPage);
|
||||
}
|
||||
|
||||
private static boolean isConsentApproved(HttpServletRequest request) {
|
||||
return CONSENT_ACTION_APPROVE.equalsIgnoreCase(request.getParameter(CONSENT_ACTION_PARAMETER_NAME));
|
||||
}
|
||||
|
||||
private static boolean isConsentCancelled(HttpServletRequest request) {
|
||||
return CONSENT_ACTION_CANCEL.equalsIgnoreCase(request.getParameter(CONSENT_ACTION_PARAMETER_NAME));
|
||||
}
|
||||
|
||||
private static String generateConsentPage(HttpServletRequest request,
|
||||
RegisteredClient registeredClient, OAuth2Authorization authorization) {
|
||||
|
||||
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(
|
||||
OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST);
|
||||
String state = authorization.getAttribute(
|
||||
OAuth2AuthorizationAttributeNames.STATE);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append("<!DOCTYPE html>");
|
||||
builder.append("<html lang=\"en\">");
|
||||
builder.append("<head>");
|
||||
builder.append(" <meta charset=\"utf-8\">");
|
||||
builder.append(" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">");
|
||||
builder.append(" <link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css\" integrity=\"sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z\" crossorigin=\"anonymous\">");
|
||||
builder.append(" <title>Consent required</title>");
|
||||
builder.append("</head>");
|
||||
builder.append("<body>");
|
||||
builder.append("<div class=\"container\">");
|
||||
builder.append(" <div class=\"py-5\">");
|
||||
builder.append(" <h1 class=\"text-center\">Consent required</h1>");
|
||||
builder.append(" </div>");
|
||||
builder.append(" <div class=\"row\">");
|
||||
builder.append(" <div class=\"col text-center\">");
|
||||
builder.append(" <p><span class=\"font-weight-bold text-primary\">" + registeredClient.getClientId() + "</span> wants to access your account <span class=\"font-weight-bold\">" + authorization.getPrincipalName() + "</span></p>");
|
||||
builder.append(" </div>");
|
||||
builder.append(" </div>");
|
||||
builder.append(" <div class=\"row pb-3\">");
|
||||
builder.append(" <div class=\"col text-center\">");
|
||||
builder.append(" <p>The following permissions are requested by the above app.<br/>Please review these and consent if you approve.</p>");
|
||||
builder.append(" </div>");
|
||||
builder.append(" </div>");
|
||||
builder.append(" <div class=\"row\">");
|
||||
builder.append(" <div class=\"col text-center\">");
|
||||
builder.append(" <form method=\"post\" action=\"" + request.getRequestURI() + "\">");
|
||||
builder.append(" <input type=\"hidden\" name=\"client_id\" value=\"" + registeredClient.getClientId() + "\">");
|
||||
builder.append(" <input type=\"hidden\" name=\"state\" value=\"" + state + "\">");
|
||||
|
||||
for (String scope : authorizationRequest.getScopes()) {
|
||||
builder.append(" <div class=\"form-group form-check py-1\">");
|
||||
builder.append(" <input class=\"form-check-input\" type=\"checkbox\" name=\"scope\" value=\"" + scope + "\" id=\"" + scope + "\" checked>");
|
||||
builder.append(" <label class=\"form-check-label\" for=\"" + scope + "\">" + scope + "</label>");
|
||||
builder.append(" </div>");
|
||||
}
|
||||
|
||||
builder.append(" <div class=\"form-group pt-3\">");
|
||||
builder.append(" <button class=\"btn btn-primary btn-lg\" type=\"submit\" name=\"consent_action\" value=\"approve\">Submit Consent</button>");
|
||||
builder.append(" </div>");
|
||||
builder.append(" <div class=\"form-group\">");
|
||||
builder.append(" <button class=\"btn btn-link regular\" type=\"submit\" name=\"consent_action\" value=\"cancel\">Cancel</button>");
|
||||
builder.append(" </div>");
|
||||
builder.append(" </form>");
|
||||
builder.append(" </div>");
|
||||
builder.append(" </div>");
|
||||
builder.append(" <div class=\"row pt-4\">");
|
||||
builder.append(" <div class=\"col text-center\">");
|
||||
builder.append(" <p><small>Your consent to provide access is required.<br/>If you do not approve, click Cancel, in which case no information will be shared with the app.</small></p>");
|
||||
builder.append(" </div>");
|
||||
builder.append(" </div>");
|
||||
builder.append("</div>");
|
||||
builder.append("</body>");
|
||||
builder.append("</html>");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* A {@code Filter} that processes an authentication request for an OAuth 2.0 Client.
|
||||
@@ -73,7 +74,10 @@ public class OAuth2ClientAuthenticationFilter extends OncePerRequestFilter {
|
||||
Assert.notNull(requestMatcher, "requestMatcher cannot be null");
|
||||
this.authenticationManager = authenticationManager;
|
||||
this.requestMatcher = requestMatcher;
|
||||
this.authenticationConverter = new ClientSecretBasicAuthenticationConverter();
|
||||
this.authenticationConverter = new DelegatingAuthenticationConverter(
|
||||
Arrays.asList(
|
||||
new ClientSecretBasicAuthenticationConverter(),
|
||||
new PublicClientAuthenticationConverter()));
|
||||
this.authenticationSuccessHandler = this::onAuthenticationSuccess;
|
||||
this.authenticationFailureHandler = this::onAuthenticationFailure;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package org.springframework.security.oauth2.server.authorization.web;
|
||||
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.core.endpoint.PkceParameterNames;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
@@ -46,4 +49,11 @@ final class OAuth2EndpointUtils {
|
||||
});
|
||||
return parameters;
|
||||
}
|
||||
|
||||
static boolean matchesPkceTokenRequest(HttpServletRequest request) {
|
||||
return AuthorizationGrantType.AUTHORIZATION_CODE.getValue().equals(
|
||||
request.getParameter(OAuth2ParameterNames.GRANT_TYPE)) &&
|
||||
request.getParameter(OAuth2ParameterNames.CODE) != null &&
|
||||
request.getParameter(PkceParameterNames.CODE_VERIFIER) != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A {@code Filter} for the OAuth 2.0 Authorization Code Grant,
|
||||
@@ -77,6 +78,7 @@ import java.util.Set;
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @author Madhu Bhat
|
||||
* @author Daniel Garnier-Moiroux
|
||||
* @since 0.0.1
|
||||
* @see AuthenticationManager
|
||||
* @see OAuth2AuthorizationService
|
||||
@@ -195,18 +197,9 @@ public class OAuth2TokenEndpointFilter extends OncePerRequestFilter {
|
||||
return null;
|
||||
}
|
||||
|
||||
MultiValueMap<String, String> parameters = OAuth2EndpointUtils.getParameters(request);
|
||||
Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
// client_id (REQUIRED)
|
||||
String clientId = parameters.getFirst(OAuth2ParameterNames.CLIENT_ID);
|
||||
Authentication clientPrincipal = null;
|
||||
if (StringUtils.hasText(clientId)) {
|
||||
if (parameters.get(OAuth2ParameterNames.CLIENT_ID).size() != 1) {
|
||||
throwError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.CLIENT_ID);
|
||||
}
|
||||
} else {
|
||||
clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
|
||||
}
|
||||
MultiValueMap<String, String> parameters = OAuth2EndpointUtils.getParameters(request);
|
||||
|
||||
// code (REQUIRED)
|
||||
String code = parameters.getFirst(OAuth2ParameterNames.CODE);
|
||||
@@ -223,9 +216,16 @@ public class OAuth2TokenEndpointFilter extends OncePerRequestFilter {
|
||||
throwError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.REDIRECT_URI);
|
||||
}
|
||||
|
||||
return clientPrincipal != null ?
|
||||
new OAuth2AuthorizationCodeAuthenticationToken(code, clientPrincipal, redirectUri) :
|
||||
new OAuth2AuthorizationCodeAuthenticationToken(code, clientId, redirectUri);
|
||||
Map<String, Object> additionalParameters = parameters
|
||||
.entrySet()
|
||||
.stream()
|
||||
.filter(e -> !e.getKey().equals(OAuth2ParameterNames.GRANT_TYPE) &&
|
||||
!e.getKey().equals(OAuth2ParameterNames.CLIENT_ID) &&
|
||||
!e.getKey().equals(OAuth2ParameterNames.CODE) &&
|
||||
!e.getKey().equals(OAuth2ParameterNames.REDIRECT_URI))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0)));
|
||||
|
||||
return new OAuth2AuthorizationCodeAuthenticationToken(code, clientPrincipal, redirectUri, additionalParameters);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.oauth2.server.authorization.web;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.core.endpoint.PkceParameterNames;
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
|
||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Attempts to extract the parameters from {@link HttpServletRequest}
|
||||
* used for authenticating public clients using Proof Key for Code Exchange (PKCE).
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @since 0.0.2
|
||||
* @see AuthenticationConverter
|
||||
* @see OAuth2ClientAuthenticationToken
|
||||
* @see OAuth2ClientAuthenticationFilter
|
||||
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc7636">Proof Key for Code Exchange by OAuth Public Clients</a>
|
||||
*/
|
||||
public class PublicClientAuthenticationConverter implements AuthenticationConverter {
|
||||
|
||||
@Override
|
||||
public Authentication convert(HttpServletRequest request) {
|
||||
if (!OAuth2EndpointUtils.matchesPkceTokenRequest(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MultiValueMap<String, String> parameters = OAuth2EndpointUtils.getParameters(request);
|
||||
|
||||
// client_id (REQUIRED for public clients)
|
||||
String clientId = parameters.getFirst(OAuth2ParameterNames.CLIENT_ID);
|
||||
if (!StringUtils.hasText(clientId)) {
|
||||
return null;
|
||||
}
|
||||
if (parameters.get(OAuth2ParameterNames.CLIENT_ID).size() != 1) {
|
||||
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST));
|
||||
}
|
||||
|
||||
// code_verifier (REQUIRED)
|
||||
if (parameters.get(PkceParameterNames.CODE_VERIFIER).size() != 1) {
|
||||
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST));
|
||||
}
|
||||
|
||||
parameters.remove(OAuth2ParameterNames.CLIENT_ID);
|
||||
|
||||
return new OAuth2ClientAuthenticationToken(
|
||||
clientId, new HashMap<>(parameters.toSingleValueMap()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.configuration;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.OrderUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link OAuth2AuthorizationServerSecurity}.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
public class OAuth2AuthorizationServerSecurityTests {
|
||||
|
||||
@Test
|
||||
public void assertOrderHighestPrecedence() {
|
||||
Integer authorizationServerSecurityOrder = OrderUtils.getOrder(OAuth2AuthorizationServerSecurity.class);
|
||||
Integer defaultSecurityOrder = OrderUtils.getOrder(WebSecurityConfigurerAdapter.class);
|
||||
assertThat(authorizationServerSecurityOrder).isNotEqualTo(defaultSecurityOrder);
|
||||
assertThat(authorizationServerSecurityOrder).isEqualTo(Ordered.HIGHEST_PRECEDENCE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
@@ -31,6 +32,7 @@ import org.springframework.security.crypto.keys.StaticKeyGeneratingKeyManager;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponseType;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.core.endpoint.PkceParameterNames;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationAttributeNames;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||
@@ -58,20 +60,29 @@ import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
/**
|
||||
* Integration tests for the OAuth 2.0 Authorization Code Grant.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @author Daniel Garnier-Moiroux
|
||||
*/
|
||||
public class OAuth2AuthorizationCodeGrantTests {
|
||||
// See RFC 7636: Appendix B. Example for the S256 code_challenge_method
|
||||
// https://tools.ietf.org/html/rfc7636#appendix-B
|
||||
private static final String S256_CODE_VERIFIER = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk";
|
||||
private static final String S256_CODE_CHALLENGE = "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM";
|
||||
|
||||
private static RegisteredClientRepository registeredClientRepository;
|
||||
private static OAuth2AuthorizationService authorizationService;
|
||||
private static KeyManager keyManager;
|
||||
@@ -161,6 +172,51 @@ public class OAuth2AuthorizationCodeGrantTests {
|
||||
verify(authorizationService).save(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenPublicClientWithPkceThenReturnAccessToken() throws Exception {
|
||||
this.spring.register(AuthorizationServerConfiguration.class).autowire();
|
||||
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.clientSecret(null)
|
||||
.clientSettings(clientSettings -> clientSettings.requireProofKey(true))
|
||||
.build();
|
||||
when(registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
MvcResult mvcResult = this.mvc.perform(get(OAuth2AuthorizationEndpointFilter.DEFAULT_AUTHORIZATION_ENDPOINT_URI)
|
||||
.params(getAuthorizationRequestParameters(registeredClient))
|
||||
.param(PkceParameterNames.CODE_CHALLENGE, S256_CODE_CHALLENGE)
|
||||
.param(PkceParameterNames.CODE_CHALLENGE_METHOD, "S256")
|
||||
.with(user("user")))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andReturn();
|
||||
assertThat(mvcResult.getResponse().getRedirectedUrl()).matches("https://example.com\\?code=.{15,}&state=state");
|
||||
|
||||
verify(registeredClientRepository).findByClientId(eq(registeredClient.getClientId()));
|
||||
|
||||
ArgumentCaptor<OAuth2Authorization> authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class);
|
||||
verify(authorizationService).save(authorizationCaptor.capture());
|
||||
OAuth2Authorization authorization = authorizationCaptor.getValue();
|
||||
|
||||
when(authorizationService.findByToken(
|
||||
eq(authorization.getAttribute(OAuth2AuthorizationAttributeNames.CODE)),
|
||||
eq(TokenType.AUTHORIZATION_CODE)))
|
||||
.thenReturn(authorization);
|
||||
|
||||
this.mvc.perform(post(OAuth2TokenEndpointFilter.DEFAULT_TOKEN_ENDPOINT_URI)
|
||||
.params(getTokenRequestParameters(registeredClient, authorization))
|
||||
.param(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId())
|
||||
.param(PkceParameterNames.CODE_VERIFIER, S256_CODE_VERIFIER))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.access_token").isNotEmpty());
|
||||
|
||||
verify(registeredClientRepository, times(2)).findByClientId(eq(registeredClient.getClientId()));
|
||||
verify(authorizationService, times(2)).findByToken(
|
||||
eq(authorization.getAttribute(OAuth2AuthorizationAttributeNames.CODE)),
|
||||
eq(TokenType.AUTHORIZATION_CODE));
|
||||
verify(authorizationService, times(2)).save(any());
|
||||
}
|
||||
|
||||
private static MultiValueMap<String, String> getAuthorizationRequestParameters(RegisteredClient registeredClient) {
|
||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
|
||||
parameters.set(OAuth2ParameterNames.RESPONSE_TYPE, OAuth2AuthorizationResponseType.CODE.getValue());
|
||||
|
||||
@@ -30,6 +30,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
* Tests for {@link InMemoryOAuth2AuthorizationService}.
|
||||
*
|
||||
* @author Krisztian Toth
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
public class InMemoryOAuth2AuthorizationServiceTests {
|
||||
private static final RegisteredClient REGISTERED_CLIENT = TestRegisteredClients.registeredClient().build();
|
||||
@@ -63,14 +64,53 @@ public class InMemoryOAuth2AuthorizationServiceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByTokenAndTokenTypeWhenTokenNullThenThrowIllegalArgumentException() {
|
||||
public void removeWhenAuthorizationNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> this.authorizationService.remove(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("authorization cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeWhenAuthorizationProvidedThenRemoved() {
|
||||
OAuth2Authorization expectedAuthorization = OAuth2Authorization.withRegisteredClient(REGISTERED_CLIENT)
|
||||
.principalName(PRINCIPAL_NAME)
|
||||
.attribute(OAuth2AuthorizationAttributeNames.CODE, AUTHORIZATION_CODE)
|
||||
.build();
|
||||
|
||||
this.authorizationService.save(expectedAuthorization);
|
||||
OAuth2Authorization authorization = this.authorizationService.findByToken(
|
||||
AUTHORIZATION_CODE, TokenType.AUTHORIZATION_CODE);
|
||||
assertThat(authorization).isEqualTo(expectedAuthorization);
|
||||
|
||||
this.authorizationService.remove(expectedAuthorization);
|
||||
authorization = this.authorizationService.findByToken(
|
||||
AUTHORIZATION_CODE, TokenType.AUTHORIZATION_CODE);
|
||||
assertThat(authorization).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByTokenWhenTokenNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> this.authorizationService.findByToken(null, TokenType.AUTHORIZATION_CODE))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("token cannot be empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByTokenAndTokenTypeWhenTokenTypeAuthorizationCodeThenFound() {
|
||||
public void findByTokenWhenTokenTypeStateThenFound() {
|
||||
String state = "state";
|
||||
OAuth2Authorization authorization = OAuth2Authorization.withRegisteredClient(REGISTERED_CLIENT)
|
||||
.principalName(PRINCIPAL_NAME)
|
||||
.attribute(OAuth2AuthorizationAttributeNames.STATE, state)
|
||||
.build();
|
||||
this.authorizationService.save(authorization);
|
||||
|
||||
OAuth2Authorization result = this.authorizationService.findByToken(
|
||||
state, new TokenType(OAuth2AuthorizationAttributeNames.STATE));
|
||||
assertThat(authorization).isEqualTo(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByTokenWhenTokenTypeAuthorizationCodeThenFound() {
|
||||
OAuth2Authorization authorization = OAuth2Authorization.withRegisteredClient(REGISTERED_CLIENT)
|
||||
.principalName(PRINCIPAL_NAME)
|
||||
.attribute(OAuth2AuthorizationAttributeNames.CODE, AUTHORIZATION_CODE)
|
||||
@@ -83,7 +123,7 @@ public class InMemoryOAuth2AuthorizationServiceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByTokenAndTokenTypeWhenTokenTypeAccessTokenThenFound() {
|
||||
public void findByTokenWhenTokenTypeAccessTokenThenFound() {
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
|
||||
"access-token", Instant.now().minusSeconds(60), Instant.now());
|
||||
OAuth2Authorization authorization = OAuth2Authorization.withRegisteredClient(REGISTERED_CLIENT)
|
||||
@@ -99,7 +139,7 @@ public class InMemoryOAuth2AuthorizationServiceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByTokenAndTokenTypeWhenTokenDoesNotExistThenNull() {
|
||||
public void findByTokenWhenTokenDoesNotExistThenNull() {
|
||||
OAuth2Authorization result = this.authorizationService.findByToken(
|
||||
"access-token", TokenType.ACCESS_TOKEN);
|
||||
assertThat(result).isNull();
|
||||
|
||||
@@ -21,9 +21,12 @@ import org.springframework.security.oauth2.server.authorization.client.Registere
|
||||
import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Joe Grandja
|
||||
* @author Daniel Garnier-Moiroux
|
||||
*/
|
||||
public class TestOAuth2Authorizations {
|
||||
|
||||
@@ -32,18 +35,26 @@ public class TestOAuth2Authorizations {
|
||||
}
|
||||
|
||||
public static OAuth2Authorization.Builder authorization(RegisteredClient registeredClient) {
|
||||
return authorization(registeredClient, Collections.emptyMap());
|
||||
}
|
||||
|
||||
public static OAuth2Authorization.Builder authorization(RegisteredClient registeredClient,
|
||||
Map<String, Object> authorizationRequestAdditionalParameters) {
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(
|
||||
OAuth2AccessToken.TokenType.BEARER, "access-token", Instant.now(), Instant.now().plusSeconds(300));
|
||||
OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest.authorizationCode()
|
||||
.authorizationUri("https://provider.com/oauth2/authorize")
|
||||
.clientId(registeredClient.getClientId())
|
||||
.redirectUri(registeredClient.getRedirectUris().iterator().next())
|
||||
.scopes(registeredClient.getScopes())
|
||||
.additionalParameters(authorizationRequestAdditionalParameters)
|
||||
.state("state")
|
||||
.build();
|
||||
return OAuth2Authorization.withRegisteredClient(registeredClient)
|
||||
.principalName("principal")
|
||||
.accessToken(accessToken)
|
||||
.attribute(OAuth2AuthorizationAttributeNames.CODE, "code")
|
||||
.attribute(OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST, authorizationRequest);
|
||||
.attribute(OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST, authorizationRequest)
|
||||
.attribute(OAuth2AuthorizationAttributeNames.AUTHORIZED_SCOPES, authorizationRequest.getScopes());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,11 @@ import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.jose.JoseHeaderNames;
|
||||
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
|
||||
import org.springframework.security.oauth2.jwt.JwtEncoder;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationAttributeNames;
|
||||
@@ -38,6 +40,7 @@ import org.springframework.security.oauth2.server.authorization.client.TestRegis
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
@@ -51,8 +54,10 @@ import static org.mockito.Mockito.when;
|
||||
* Tests for {@link OAuth2AuthorizationCodeAuthenticationProvider}.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @author Daniel Garnier-Moiroux
|
||||
*/
|
||||
public class OAuth2AuthorizationCodeAuthenticationProviderTests {
|
||||
private static final String AUTHORIZATION_CODE = "code";
|
||||
private RegisteredClient registeredClient;
|
||||
private RegisteredClientRepository registeredClientRepository;
|
||||
private OAuth2AuthorizationService authorizationService;
|
||||
@@ -100,7 +105,7 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests {
|
||||
TestingAuthenticationToken clientPrincipal = new TestingAuthenticationToken(
|
||||
this.registeredClient.getClientId(), this.registeredClient.getClientSecret());
|
||||
OAuth2AuthorizationCodeAuthenticationToken authentication =
|
||||
new OAuth2AuthorizationCodeAuthenticationToken("code", clientPrincipal, null);
|
||||
new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, null, null);
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
@@ -111,9 +116,9 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenClientPrincipalNotAuthenticatedThenThrowOAuth2AuthenticationException() {
|
||||
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||
this.registeredClient.getClientId(), this.registeredClient.getClientSecret());
|
||||
this.registeredClient.getClientId(), this.registeredClient.getClientSecret(), null);
|
||||
OAuth2AuthorizationCodeAuthenticationToken authentication =
|
||||
new OAuth2AuthorizationCodeAuthenticationToken("code", clientPrincipal, null);
|
||||
new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, null, null);
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
@@ -125,7 +130,7 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests {
|
||||
public void authenticateWhenInvalidCodeThenThrowOAuth2AuthenticationException() {
|
||||
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(this.registeredClient);
|
||||
OAuth2AuthorizationCodeAuthenticationToken authentication =
|
||||
new OAuth2AuthorizationCodeAuthenticationToken("code", clientPrincipal, null);
|
||||
new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, null, null);
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
@@ -136,13 +141,13 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenCodeIssuedToAnotherClientThenThrowOAuth2AuthenticationException() {
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization().build();
|
||||
when(this.authorizationService.findByToken(eq("code"), eq(TokenType.AUTHORIZATION_CODE)))
|
||||
when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(TokenType.AUTHORIZATION_CODE)))
|
||||
.thenReturn(authorization);
|
||||
|
||||
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||
TestRegisteredClients.registeredClient2().build());
|
||||
OAuth2AuthorizationCodeAuthenticationToken authentication =
|
||||
new OAuth2AuthorizationCodeAuthenticationToken("code", clientPrincipal, null);
|
||||
new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, null, null);
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
@@ -153,14 +158,14 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenInvalidRedirectUriThenThrowOAuth2AuthenticationException() {
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization().build();
|
||||
when(this.authorizationService.findByToken(eq("code"), eq(TokenType.AUTHORIZATION_CODE)))
|
||||
when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(TokenType.AUTHORIZATION_CODE)))
|
||||
.thenReturn(authorization);
|
||||
|
||||
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(this.registeredClient);
|
||||
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(
|
||||
OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST);
|
||||
OAuth2AuthorizationCodeAuthenticationToken authentication =
|
||||
new OAuth2AuthorizationCodeAuthenticationToken("code", clientPrincipal, authorizationRequest.getRedirectUri() + "-invalid");
|
||||
new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, authorizationRequest.getRedirectUri() + "-invalid", null);
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
@@ -171,27 +176,27 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenValidCodeThenReturnAccessToken() {
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization().build();
|
||||
when(this.authorizationService.findByToken(eq("code"), eq(TokenType.AUTHORIZATION_CODE)))
|
||||
when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(TokenType.AUTHORIZATION_CODE)))
|
||||
.thenReturn(authorization);
|
||||
|
||||
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(this.registeredClient);
|
||||
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(
|
||||
OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST);
|
||||
OAuth2AuthorizationCodeAuthenticationToken authentication =
|
||||
new OAuth2AuthorizationCodeAuthenticationToken("code", clientPrincipal, authorizationRequest.getRedirectUri());
|
||||
new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, authorizationRequest.getRedirectUri(), null);
|
||||
|
||||
Instant issuedAt = Instant.now();
|
||||
Instant expiresAt = issuedAt.plus(1, ChronoUnit.HOURS);
|
||||
Jwt jwt = Jwt.withTokenValue("token")
|
||||
.header(JoseHeaderNames.ALG, SignatureAlgorithm.RS256.getName())
|
||||
.issuedAt(issuedAt)
|
||||
.expiresAt(expiresAt)
|
||||
.build();
|
||||
when(this.jwtEncoder.encode(any(), any())).thenReturn(jwt);
|
||||
when(this.jwtEncoder.encode(any(), any())).thenReturn(createJwt());
|
||||
|
||||
OAuth2AccessTokenAuthenticationToken accessTokenAuthentication =
|
||||
(OAuth2AccessTokenAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
||||
|
||||
ArgumentCaptor<JwtClaimsSet> jwtClaimsSetCaptor = ArgumentCaptor.forClass(JwtClaimsSet.class);
|
||||
verify(this.jwtEncoder).encode(any(), jwtClaimsSetCaptor.capture());
|
||||
JwtClaimsSet jwtClaimsSet = jwtClaimsSetCaptor.getValue();
|
||||
|
||||
Set<String> scopes = jwtClaimsSet.getClaim(OAuth2ParameterNames.SCOPE);
|
||||
assertThat(scopes).isEqualTo(authorization.getAttribute(OAuth2AuthorizationAttributeNames.AUTHORIZED_SCOPES));
|
||||
|
||||
ArgumentCaptor<OAuth2Authorization> authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class);
|
||||
verify(this.authorizationService).save(authorizationCaptor.capture());
|
||||
OAuth2Authorization updatedAuthorization = authorizationCaptor.getValue();
|
||||
@@ -201,4 +206,14 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests {
|
||||
assertThat(updatedAuthorization.getAccessToken()).isNotNull();
|
||||
assertThat(accessTokenAuthentication.getAccessToken()).isEqualTo(updatedAuthorization.getAccessToken());
|
||||
}
|
||||
|
||||
private static Jwt createJwt() {
|
||||
Instant issuedAt = Instant.now();
|
||||
Instant expiresAt = issuedAt.plus(1, ChronoUnit.HOURS);
|
||||
return Jwt.withTokenValue("token")
|
||||
.header(JoseHeaderNames.ALG, SignatureAlgorithm.RS256.getName())
|
||||
.issuedAt(issuedAt)
|
||||
.expiresAt(expiresAt)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
package org.springframework.security.oauth2.server.authorization.authentication;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
@@ -26,52 +28,49 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
* Tests for {@link OAuth2AuthorizationCodeAuthenticationToken}.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @author Daniel Garnier-Moiroux
|
||||
*/
|
||||
public class OAuth2AuthorizationCodeAuthenticationTokenTests {
|
||||
private String code = "code";
|
||||
private OAuth2ClientAuthenticationToken clientPrincipal =
|
||||
new OAuth2ClientAuthenticationToken(TestRegisteredClients.registeredClient().build());
|
||||
private String clientId = "clientId";
|
||||
private OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||
TestRegisteredClients.registeredClient().build());
|
||||
private String redirectUri = "redirectUri";
|
||||
private Map<String, Object> additionalParameters = Collections.singletonMap("param1", "value1");
|
||||
|
||||
@Test
|
||||
public void constructorWhenCodeNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> new OAuth2AuthorizationCodeAuthenticationToken(null, this.clientPrincipal, this.redirectUri))
|
||||
assertThatThrownBy(() -> new OAuth2AuthorizationCodeAuthenticationToken(null, this.clientPrincipal, this.redirectUri, null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("code cannot be empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenClientPrincipalNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> new OAuth2AuthorizationCodeAuthenticationToken(this.code, (Authentication) null, this.redirectUri))
|
||||
assertThatThrownBy(() -> new OAuth2AuthorizationCodeAuthenticationToken(this.code, null, this.redirectUri, null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("clientPrincipal cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenClientIdNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> new OAuth2AuthorizationCodeAuthenticationToken(this.code, (String) null, this.redirectUri))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("clientId cannot be empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenClientPrincipalProvidedThenCreated() {
|
||||
OAuth2AuthorizationCodeAuthenticationToken authentication = new OAuth2AuthorizationCodeAuthenticationToken(
|
||||
this.code, this.clientPrincipal, this.redirectUri);
|
||||
this.code, this.clientPrincipal, this.redirectUri, this.additionalParameters);
|
||||
assertThat(authentication.getPrincipal()).isEqualTo(this.clientPrincipal);
|
||||
assertThat(authentication.getCredentials().toString()).isEmpty();
|
||||
assertThat(authentication.getCode()).isEqualTo(this.code);
|
||||
assertThat(authentication.getRedirectUri()).isEqualTo(this.redirectUri);
|
||||
assertThat(authentication.getAdditionalParameters()).isEqualTo(this.additionalParameters);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenClientIdProvidedThenCreated() {
|
||||
public void getAdditionalParametersWhenUpdateThenThrowUnsupportedOperationException() {
|
||||
OAuth2AuthorizationCodeAuthenticationToken authentication = new OAuth2AuthorizationCodeAuthenticationToken(
|
||||
this.code, this.clientId, this.redirectUri);
|
||||
assertThat(authentication.getPrincipal()).isEqualTo(this.clientId);
|
||||
assertThat(authentication.getCredentials().toString()).isEmpty();
|
||||
assertThat(authentication.getCode()).isEqualTo(this.code);
|
||||
assertThat(authentication.getRedirectUri()).isEqualTo(this.redirectUri);
|
||||
this.code, this.clientPrincipal, this.redirectUri, this.additionalParameters);
|
||||
assertThatThrownBy(() -> authentication.getAdditionalParameters().put("another_key", 1))
|
||||
.isInstanceOf(UnsupportedOperationException.class);
|
||||
assertThatThrownBy(() -> authentication.getAdditionalParameters().remove("some_key"))
|
||||
.isInstanceOf(UnsupportedOperationException.class);
|
||||
assertThatThrownBy(() -> authentication.getAdditionalParameters().clear())
|
||||
.isInstanceOf(UnsupportedOperationException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,41 +17,73 @@ package org.springframework.security.oauth2.server.authorization.authentication;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.core.endpoint.PkceParameterNames;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||
import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations;
|
||||
import org.springframework.security.oauth2.server.authorization.TokenType;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||
import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Tests for {@link OAuth2ClientAuthenticationProvider}.
|
||||
*
|
||||
* @author Patryk Kostrzewa
|
||||
* @author Joe Grandja
|
||||
* @author Daniel Garnier-Moiroux
|
||||
*/
|
||||
public class OAuth2ClientAuthenticationProviderTests {
|
||||
private RegisteredClient registeredClient;
|
||||
private static final String PLAIN_CODE_VERIFIER = "pkce-key";
|
||||
private static final String PLAIN_CODE_CHALLENGE = PLAIN_CODE_VERIFIER;
|
||||
|
||||
// See RFC 7636: Appendix B. Example for the S256 code_challenge_method
|
||||
// https://tools.ietf.org/html/rfc7636#appendix-B
|
||||
private static final String S256_CODE_VERIFIER = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk";
|
||||
private static final String S256_CODE_CHALLENGE = "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM";
|
||||
|
||||
private static final String AUTHORIZATION_CODE = "code";
|
||||
|
||||
private RegisteredClientRepository registeredClientRepository;
|
||||
private OAuth2AuthorizationService authorizationService;
|
||||
private OAuth2ClientAuthenticationProvider authenticationProvider;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
this.registeredClientRepository = new InMemoryRegisteredClientRepository(this.registeredClient);
|
||||
this.authenticationProvider = new OAuth2ClientAuthenticationProvider(this.registeredClientRepository);
|
||||
this.registeredClientRepository = mock(RegisteredClientRepository.class);
|
||||
this.authorizationService = mock(OAuth2AuthorizationService.class);
|
||||
this.authenticationProvider = new OAuth2ClientAuthenticationProvider(
|
||||
this.registeredClientRepository, this.authorizationService);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenRegisteredClientRepositoryNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> new OAuth2ClientAuthenticationProvider(null))
|
||||
assertThatThrownBy(() -> new OAuth2ClientAuthenticationProvider(null, this.authorizationService))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("registeredClientRepository cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenAuthorizationServiceNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> new OAuth2ClientAuthenticationProvider(this.registeredClientRepository, null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("authorizationService cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsWhenTypeOAuth2ClientAuthenticationTokenThenReturnTrue() {
|
||||
assertThat(this.authenticationProvider.supports(OAuth2ClientAuthenticationToken.class)).isTrue();
|
||||
@@ -59,8 +91,12 @@ public class OAuth2ClientAuthenticationProviderTests {
|
||||
|
||||
@Test
|
||||
public void authenticateWhenInvalidClientIdThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
||||
this.registeredClient.getClientId() + "-invalid", this.registeredClient.getClientSecret());
|
||||
registeredClient.getClientId() + "-invalid", registeredClient.getClientSecret(), null);
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
@@ -70,8 +106,12 @@ public class OAuth2ClientAuthenticationProviderTests {
|
||||
|
||||
@Test
|
||||
public void authenticateWhenInvalidClientSecretThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
||||
this.registeredClient.getClientId(), this.registeredClient.getClientSecret() + "-invalid");
|
||||
registeredClient.getClientId(), registeredClient.getClientSecret() + "-invalid", null);
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
@@ -81,13 +121,282 @@ public class OAuth2ClientAuthenticationProviderTests {
|
||||
|
||||
@Test
|
||||
public void authenticateWhenValidCredentialsThenAuthenticated() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
||||
this.registeredClient.getClientId(), this.registeredClient.getClientSecret());
|
||||
registeredClient.getClientId(), registeredClient.getClientSecret(), null);
|
||||
OAuth2ClientAuthenticationToken authenticationResult =
|
||||
(OAuth2ClientAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
||||
assertThat(authenticationResult.isAuthenticated()).isTrue();
|
||||
assertThat(authenticationResult.getPrincipal().toString()).isEqualTo(this.registeredClient.getClientId());
|
||||
assertThat(authenticationResult.getPrincipal().toString()).isEqualTo(registeredClient.getClientId());
|
||||
assertThat(authenticationResult.getCredentials()).isNull();
|
||||
assertThat(authenticationResult.getRegisteredClient()).isEqualTo(this.registeredClient);
|
||||
assertThat(authenticationResult.getRegisteredClient()).isEqualTo(registeredClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenNotPkceThenContinueAuthenticated() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken(
|
||||
registeredClient.getClientId(), registeredClient.getClientSecret(), null);
|
||||
OAuth2ClientAuthenticationToken authenticationResult =
|
||||
(OAuth2ClientAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
||||
assertThat(authenticationResult.isAuthenticated()).isTrue();
|
||||
|
||||
verifyNoInteractions(this.authorizationService);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenPkceAndInvalidCodeThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations
|
||||
.authorization(registeredClient, createPkceAuthorizationParametersPlain())
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(TokenType.AUTHORIZATION_CODE)))
|
||||
.thenReturn(authorization);
|
||||
|
||||
Map<String, Object> parameters = createPkceTokenParameters(PLAIN_CODE_VERIFIER);
|
||||
parameters.put(OAuth2ParameterNames.CODE, "invalid-code");
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication =
|
||||
new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), parameters);
|
||||
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.extracting("errorCode")
|
||||
.isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenPkceAndRequireProofKeyAndMissingCodeChallengeThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.clientSettings(clientSettings -> clientSettings.requireProofKey(true))
|
||||
.build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations
|
||||
.authorization(registeredClient)
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(TokenType.AUTHORIZATION_CODE)))
|
||||
.thenReturn(authorization);
|
||||
|
||||
Map<String, Object> parameters = createPkceTokenParameters(PLAIN_CODE_VERIFIER);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication =
|
||||
new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), parameters);
|
||||
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.extracting("errorCode")
|
||||
.isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenPkceAndMissingCodeVerifierThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations
|
||||
.authorization(registeredClient, createPkceAuthorizationParametersPlain())
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(TokenType.AUTHORIZATION_CODE)))
|
||||
.thenReturn(authorization);
|
||||
|
||||
Map<String, Object> parameters = createPkceTokenParameters(PLAIN_CODE_VERIFIER);
|
||||
parameters.remove(PkceParameterNames.CODE_VERIFIER);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication =
|
||||
new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), parameters);
|
||||
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.extracting("errorCode")
|
||||
.isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenPkceAndPlainMethodAndInvalidCodeVerifierThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations
|
||||
.authorization(registeredClient, createPkceAuthorizationParametersPlain())
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(TokenType.AUTHORIZATION_CODE)))
|
||||
.thenReturn(authorization);
|
||||
|
||||
Map<String, Object> parameters = createPkceTokenParameters("invalid-code-verifier");
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication =
|
||||
new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), parameters);
|
||||
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.extracting("errorCode")
|
||||
.isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenPkceAndS256MethodAndInvalidCodeVerifierThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations
|
||||
.authorization(registeredClient, createPkceAuthorizationParametersS256())
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(TokenType.AUTHORIZATION_CODE)))
|
||||
.thenReturn(authorization);
|
||||
|
||||
Map<String, Object> parameters = createPkceTokenParameters("invalid-code-verifier");
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication =
|
||||
new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), parameters);
|
||||
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.extracting("errorCode")
|
||||
.isEqualTo(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenPkceAndPlainMethodAndValidCodeVerifierThenAuthenticated() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations
|
||||
.authorization(registeredClient, createPkceAuthorizationParametersPlain())
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(TokenType.AUTHORIZATION_CODE)))
|
||||
.thenReturn(authorization);
|
||||
|
||||
Map<String, Object> parameters = createPkceTokenParameters(PLAIN_CODE_VERIFIER);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication =
|
||||
new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), parameters);
|
||||
|
||||
OAuth2ClientAuthenticationToken authenticationResult =
|
||||
(OAuth2ClientAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
||||
assertThat(authenticationResult.isAuthenticated()).isTrue();
|
||||
assertThat(authenticationResult.getPrincipal().toString()).isEqualTo(registeredClient.getClientId());
|
||||
assertThat(authenticationResult.getCredentials()).isNull();
|
||||
assertThat(authenticationResult.getRegisteredClient()).isEqualTo(registeredClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenPkceAndMissingMethodThenDefaultPlainMethodAndAuthenticated() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
Map<String, Object> authorizationRequestAdditionalParameters = createPkceAuthorizationParametersPlain();
|
||||
authorizationRequestAdditionalParameters.remove(PkceParameterNames.CODE_CHALLENGE_METHOD);
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations
|
||||
.authorization(registeredClient, authorizationRequestAdditionalParameters)
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(TokenType.AUTHORIZATION_CODE)))
|
||||
.thenReturn(authorization);
|
||||
|
||||
Map<String, Object> parameters = createPkceTokenParameters(PLAIN_CODE_VERIFIER);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication =
|
||||
new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), parameters);
|
||||
|
||||
OAuth2ClientAuthenticationToken authenticationResult =
|
||||
(OAuth2ClientAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
||||
assertThat(authenticationResult.isAuthenticated()).isTrue();
|
||||
assertThat(authenticationResult.getPrincipal().toString()).isEqualTo(registeredClient.getClientId());
|
||||
assertThat(authenticationResult.getCredentials()).isNull();
|
||||
assertThat(authenticationResult.getRegisteredClient()).isEqualTo(registeredClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenPkceAndS256MethodAndValidCodeVerifierThenAuthenticated() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations
|
||||
.authorization(registeredClient, createPkceAuthorizationParametersS256())
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(TokenType.AUTHORIZATION_CODE)))
|
||||
.thenReturn(authorization);
|
||||
|
||||
Map<String, Object> parameters = createPkceTokenParameters(S256_CODE_VERIFIER);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication =
|
||||
new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), parameters);
|
||||
|
||||
OAuth2ClientAuthenticationToken authenticationResult =
|
||||
(OAuth2ClientAuthenticationToken) this.authenticationProvider.authenticate(authentication);
|
||||
assertThat(authenticationResult.isAuthenticated()).isTrue();
|
||||
assertThat(authenticationResult.getPrincipal().toString()).isEqualTo(registeredClient.getClientId());
|
||||
assertThat(authenticationResult.getCredentials()).isNull();
|
||||
assertThat(authenticationResult.getRegisteredClient()).isEqualTo(registeredClient);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenPkceAndUnsupportedCodeChallengeMethodThenThrowOAuth2AuthenticationException() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
Map<String, Object> authorizationRequestAdditionalParameters = createPkceAuthorizationParametersPlain();
|
||||
// This should never happen: the Authorization endpoint should not allow it
|
||||
authorizationRequestAdditionalParameters.put(PkceParameterNames.CODE_CHALLENGE_METHOD, "unsupported-challenge-method");
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations
|
||||
.authorization(registeredClient, authorizationRequestAdditionalParameters)
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(TokenType.AUTHORIZATION_CODE)))
|
||||
.thenReturn(authorization);
|
||||
|
||||
Map<String, Object> parameters = createPkceTokenParameters(PLAIN_CODE_VERIFIER);
|
||||
|
||||
OAuth2ClientAuthenticationToken authentication =
|
||||
new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), parameters);
|
||||
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.extracting("errorCode")
|
||||
.isEqualTo(OAuth2ErrorCodes.SERVER_ERROR);
|
||||
}
|
||||
|
||||
private static Map<String, Object> createPkceTokenParameters(String codeVerifier) {
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
parameters.put(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue());
|
||||
parameters.put(OAuth2ParameterNames.CODE, AUTHORIZATION_CODE);
|
||||
parameters.put(PkceParameterNames.CODE_VERIFIER, codeVerifier);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private static Map<String, Object> createPkceAuthorizationParametersPlain() {
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
parameters.put(PkceParameterNames.CODE_CHALLENGE_METHOD, "plain");
|
||||
parameters.put(PkceParameterNames.CODE_CHALLENGE, PLAIN_CODE_CHALLENGE);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private static Map<String, Object> createPkceAuthorizationParametersS256() {
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
parameters.put(PkceParameterNames.CODE_CHALLENGE_METHOD, "S256");
|
||||
parameters.put(PkceParameterNames.CODE_CHALLENGE, S256_CODE_CHALLENGE);
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ import org.junit.Test;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
@@ -31,14 +34,14 @@ public class OAuth2ClientAuthenticationTokenTests {
|
||||
|
||||
@Test
|
||||
public void constructorWhenClientIdNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> new OAuth2ClientAuthenticationToken(null, "secret"))
|
||||
assertThatThrownBy(() -> new OAuth2ClientAuthenticationToken(null, "secret", null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("clientId cannot be empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenClientSecretNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> new OAuth2ClientAuthenticationToken("clientId", null))
|
||||
assertThatThrownBy(() -> new OAuth2ClientAuthenticationToken("clientId", null, null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("clientSecret cannot be empty");
|
||||
}
|
||||
@@ -52,13 +55,25 @@ public class OAuth2ClientAuthenticationTokenTests {
|
||||
|
||||
@Test
|
||||
public void constructorWhenClientCredentialsProvidedThenCreated() {
|
||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken("clientId", "secret");
|
||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken("clientId", "secret", null);
|
||||
assertThat(authentication.isAuthenticated()).isFalse();
|
||||
assertThat(authentication.getPrincipal().toString()).isEqualTo("clientId");
|
||||
assertThat(authentication.getCredentials()).isEqualTo("secret");
|
||||
assertThat(authentication.getRegisteredClient()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenClientIdProvidedThenCreated() {
|
||||
Map<String, Object> additionalParameters = new HashMap<>();
|
||||
additionalParameters.put("param1", "value1");
|
||||
OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken("clientId", additionalParameters);
|
||||
assertThat(authentication.isAuthenticated()).isFalse();
|
||||
assertThat(authentication.getPrincipal().toString()).isEqualTo("clientId");
|
||||
assertThat(authentication.getCredentials()).isNull();
|
||||
assertThat(authentication.getAdditionalParameters()).isEqualTo(additionalParameters);
|
||||
assertThat(authentication.getRegisteredClient()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenRegisteredClientProvidedThenCreated() {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
|
||||
@@ -103,7 +103,7 @@ public class OAuth2ClientCredentialsAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenClientPrincipalNotAuthenticatedThenThrowOAuth2AuthenticationException() {
|
||||
OAuth2ClientAuthenticationToken clientPrincipal = new OAuth2ClientAuthenticationToken(
|
||||
this.registeredClient.getClientId(), this.registeredClient.getClientSecret());
|
||||
this.registeredClient.getClientId(), this.registeredClient.getClientSecret(), null);
|
||||
OAuth2ClientCredentialsAuthenticationToken authentication = new OAuth2ClientCredentialsAuthenticationToken(clientPrincipal);
|
||||
|
||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
||||
|
||||
@@ -322,6 +322,9 @@ public class RegisteredClientTests {
|
||||
RegisteredClient registration = TestRegisteredClients.registeredClient().build();
|
||||
RegisteredClient updated = RegisteredClient.withRegisteredClient(registration).build();
|
||||
|
||||
assertThat(registration.getId()).isEqualTo(updated.getId());
|
||||
assertThat(registration.getClientId()).isEqualTo(updated.getClientId());
|
||||
assertThat(registration.getClientSecret()).isEqualTo(updated.getClientSecret());
|
||||
assertThat(registration.getClientAuthenticationMethods()).isEqualTo(updated.getClientAuthenticationMethods());
|
||||
assertThat(registration.getClientAuthenticationMethods()).isNotSameAs(updated.getClientAuthenticationMethods());
|
||||
assertThat(registration.getAuthorizationGrantTypes()).isEqualTo(updated.getAuthorizationGrantTypes());
|
||||
@@ -330,20 +333,10 @@ public class RegisteredClientTests {
|
||||
assertThat(registration.getRedirectUris()).isNotSameAs(updated.getRedirectUris());
|
||||
assertThat(registration.getScopes()).isEqualTo(updated.getScopes());
|
||||
assertThat(registration.getScopes()).isNotSameAs(updated.getScopes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildWhenRegisteredClientProvidedThenEachPropertyMatches() {
|
||||
RegisteredClient registration = TestRegisteredClients.registeredClient().build();
|
||||
RegisteredClient updated = RegisteredClient.withRegisteredClient(registration).build();
|
||||
|
||||
assertThat(registration.getId()).isEqualTo(updated.getId());
|
||||
assertThat(registration.getClientId()).isEqualTo(updated.getClientId());
|
||||
assertThat(registration.getClientSecret()).isEqualTo(updated.getClientSecret());
|
||||
assertThat(registration.getClientAuthenticationMethods()).isEqualTo(updated.getClientAuthenticationMethods());
|
||||
assertThat(registration.getAuthorizationGrantTypes()).isEqualTo(updated.getAuthorizationGrantTypes());
|
||||
assertThat(registration.getRedirectUris()).isEqualTo(updated.getRedirectUris());
|
||||
assertThat(registration.getScopes()).isEqualTo(updated.getScopes());
|
||||
assertThat(registration.getClientSettings().settings()).isEqualTo(updated.getClientSettings().settings());
|
||||
assertThat(registration.getClientSettings()).isNotSameAs(updated.getClientSettings());
|
||||
assertThat(registration.getTokenSettings().settings()).isEqualTo(updated.getTokenSettings().settings());
|
||||
assertThat(registration.getTokenSettings()).isNotSameAs(updated.getTokenSettings());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.oauth2.server.authorization.config;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* Tests for {@link ClientSettings}.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
public class ClientSettingsTests {
|
||||
|
||||
@Test
|
||||
public void constructorWhenDefaultThenDefaultsAreSet() {
|
||||
ClientSettings clientSettings = new ClientSettings();
|
||||
assertThat(clientSettings.settings()).hasSize(2);
|
||||
assertThat(clientSettings.requireProofKey()).isFalse();
|
||||
assertThat(clientSettings.requireUserConsent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> new ClientSettings(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("settings cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requireProofKeyWhenTrueThenSet() {
|
||||
ClientSettings clientSettings = new ClientSettings().requireProofKey(true);
|
||||
assertThat(clientSettings.requireProofKey()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requireUserConsentWhenTrueThenSet() {
|
||||
ClientSettings clientSettings = new ClientSettings().requireUserConsent(true);
|
||||
assertThat(clientSettings.requireUserConsent()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void settingWhenCalledThenReturnClientSettings() {
|
||||
ClientSettings clientSettings = new ClientSettings()
|
||||
.<ClientSettings>setting("name1", "value1")
|
||||
.requireProofKey(true)
|
||||
.<ClientSettings>settings(settings -> settings.put("name2", "value2"))
|
||||
.requireUserConsent(true);
|
||||
assertThat(clientSettings.settings()).hasSize(4);
|
||||
assertThat(clientSettings.requireProofKey()).isTrue();
|
||||
assertThat(clientSettings.requireUserConsent()).isTrue();
|
||||
assertThat(clientSettings.<String>setting("name1")).isEqualTo("value1");
|
||||
assertThat(clientSettings.<String>setting("name2")).isEqualTo("value2");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.oauth2.server.authorization.config;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
|
||||
/**
|
||||
* Tests for {@link Settings}.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
public class SettingsTests {
|
||||
|
||||
@Test
|
||||
public void constructorWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> new Settings(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("settings cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenSettingsProvidedThenSettingsAreSet() {
|
||||
Map<String, Object> initialSettings = new HashMap<>();
|
||||
initialSettings.put("setting1", "value1");
|
||||
initialSettings.put("setting2", "value2");
|
||||
|
||||
Settings settings = new Settings(initialSettings)
|
||||
.setting("setting3", "value3")
|
||||
.settings(s -> s.put("setting4", "value4"));
|
||||
|
||||
assertThat(settings.settings()).contains(
|
||||
entry("setting1", "value1"),
|
||||
entry("setting2", "value2"),
|
||||
entry("setting3", "value3"),
|
||||
entry("setting4", "value4"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSettingWhenNameNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> new Settings().setting(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("name cannot be empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setSettingWhenNameNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> new Settings().setting(null, "value"))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("name cannot be empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setSettingWhenValueNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> new Settings().setting("setting", null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("value cannot be null");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.oauth2.server.authorization.config;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* Tests for {@link TokenSettings}.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
public class TokenSettingsTests {
|
||||
|
||||
@Test
|
||||
public void constructorWhenDefaultThenDefaultsAreSet() {
|
||||
TokenSettings tokenSettings = new TokenSettings();
|
||||
assertThat(tokenSettings.settings()).hasSize(1);
|
||||
assertThat(tokenSettings.accessTokenTimeToLive()).isEqualTo(Duration.ofMinutes(5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> new TokenSettings(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("settings cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessTokenTimeToLiveWhenProvidedThenSet() {
|
||||
Duration accessTokenTimeToLive = Duration.ofMinutes(10);
|
||||
TokenSettings tokenSettings = new TokenSettings().accessTokenTimeToLive(accessTokenTimeToLive);
|
||||
assertThat(tokenSettings.accessTokenTimeToLive()).isEqualTo(accessTokenTimeToLive);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void settingWhenCalledThenReturnTokenSettings() {
|
||||
Duration accessTokenTimeToLive = Duration.ofMinutes(10);
|
||||
TokenSettings tokenSettings = new TokenSettings()
|
||||
.<TokenSettings>setting("name1", "value1")
|
||||
.accessTokenTimeToLive(accessTokenTimeToLive)
|
||||
.<TokenSettings>settings(settings -> settings.put("name2", "value2"));
|
||||
assertThat(tokenSettings.settings()).hasSize(3);
|
||||
assertThat(tokenSettings.accessTokenTimeToLive()).isEqualTo(accessTokenTimeToLive);
|
||||
assertThat(tokenSettings.<String>setting("name1")).isEqualTo("value1");
|
||||
assertThat(tokenSettings.<String>setting("name2")).isEqualTo("value2");
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,11 @@ import org.junit.Test;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.core.endpoint.PkceParameterNames;
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
@@ -29,6 +32,7 @@ import java.util.Base64;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
|
||||
/**
|
||||
* Tests for {@link ClientSecretBasicAuthenticationConverter}.
|
||||
@@ -96,6 +100,20 @@ public class ClientSecretBasicAuthenticationConverterTests {
|
||||
assertThat(authentication.getCredentials()).isEqualTo("secret");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertWhenConfidentialClientWithPkceParametersThenAdditionalParametersIncluded() throws Exception {
|
||||
MockHttpServletRequest request = createPkceTokenRequest();
|
||||
request.addHeader(HttpHeaders.AUTHORIZATION, "Basic " + encodeBasicAuth("clientId", "secret"));
|
||||
OAuth2ClientAuthenticationToken authentication = (OAuth2ClientAuthenticationToken) this.converter.convert(request);
|
||||
assertThat(authentication.getPrincipal()).isEqualTo("clientId");
|
||||
assertThat(authentication.getCredentials()).isEqualTo("secret");
|
||||
assertThat(authentication.getAdditionalParameters())
|
||||
.containsOnly(
|
||||
entry(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue()),
|
||||
entry(OAuth2ParameterNames.CODE, "code"),
|
||||
entry(PkceParameterNames.CODE_VERIFIER, "code-verifier-1"));
|
||||
}
|
||||
|
||||
private static String encodeBasicAuth(String clientId, String secret) throws Exception {
|
||||
clientId = URLEncoder.encode(clientId, StandardCharsets.UTF_8.name());
|
||||
secret = URLEncoder.encode(secret, StandardCharsets.UTF_8.name());
|
||||
@@ -103,4 +121,12 @@ public class ClientSecretBasicAuthenticationConverterTests {
|
||||
byte[] encodedBytes = Base64.getEncoder().encode(credentialsString.getBytes(StandardCharsets.UTF_8));
|
||||
return new String(encodedBytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static MockHttpServletRequest createPkceTokenRequest() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addParameter(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue());
|
||||
request.addParameter(OAuth2ParameterNames.CODE, "code");
|
||||
request.addParameter(PkceParameterNames.CODE_VERIFIER, "code-verifier-1");
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
@@ -30,9 +31,12 @@ import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponseType;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.core.endpoint.PkceParameterNames;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationAttributeNames;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||
import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations;
|
||||
import org.springframework.security.oauth2.server.authorization.TokenType;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||
import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
|
||||
@@ -41,6 +45,7 @@ import org.springframework.util.StringUtils;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -58,9 +63,12 @@ import static org.mockito.Mockito.when;
|
||||
*
|
||||
* @author Paurav Munshi
|
||||
* @author Joe Grandja
|
||||
* @author Daniel Garnier-Moiroux
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public class OAuth2AuthorizationEndpointFilterTests {
|
||||
private static final String DEFAULT_ERROR_URI = "https://tools.ietf.org/html/rfc6749%23section-4.1.2.1";
|
||||
private static final String PKCE_ERROR_URI = "https://tools.ietf.org/html/rfc7636%23section-4.4.1";
|
||||
private RegisteredClientRepository registeredClientRepository;
|
||||
private OAuth2AuthorizationService authorizationService;
|
||||
private OAuth2AuthorizationEndpointFilter filter;
|
||||
@@ -117,19 +125,6 @@ public class OAuth2AuthorizationEndpointFilterTests {
|
||||
verify(filterChain).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenAuthorizationRequestPostThenNotProcessed() throws Exception {
|
||||
String requestUri = OAuth2AuthorizationEndpointFilter.DEFAULT_AUTHORIZATION_ENDPOINT_URI;
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", requestUri);
|
||||
request.setServletPath(requestUri);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain filterChain = mock(FilterChain.class);
|
||||
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
verify(filterChain).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenAuthorizationRequestMissingClientIdThenInvalidRequestError() throws Exception {
|
||||
doFilterWhenAuthorizationRequestInvalidParameterThenError(
|
||||
@@ -217,21 +212,12 @@ public class OAuth2AuthorizationEndpointFilterTests {
|
||||
when(this.registeredClientRepository.findByClientId((eq(registeredClient.getClientId()))))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
MockHttpServletRequest request = createAuthorizationRequest(registeredClient);
|
||||
request.removeParameter(OAuth2ParameterNames.RESPONSE_TYPE);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain filterChain = mock(FilterChain.class);
|
||||
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
verifyNoInteractions(filterChain);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpStatus.FOUND.value());
|
||||
assertThat(response.getRedirectedUrl()).matches("https://example.com\\?" +
|
||||
"error=invalid_request&" +
|
||||
"error_description=OAuth%202.0%20Parameter:%20response_type&" +
|
||||
"error_uri=https://tools.ietf.org/html/rfc6749%23section-4.1.2.1&" +
|
||||
"state=state");
|
||||
doFilterWhenAuthorizationRequestInvalidParameterThenRedirect(
|
||||
registeredClient,
|
||||
OAuth2ParameterNames.RESPONSE_TYPE,
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
DEFAULT_ERROR_URI,
|
||||
request -> request.removeParameter(OAuth2ParameterNames.RESPONSE_TYPE));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -240,21 +226,12 @@ public class OAuth2AuthorizationEndpointFilterTests {
|
||||
when(this.registeredClientRepository.findByClientId((eq(registeredClient.getClientId()))))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
MockHttpServletRequest request = createAuthorizationRequest(registeredClient);
|
||||
request.addParameter(OAuth2ParameterNames.RESPONSE_TYPE, "id_token");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain filterChain = mock(FilterChain.class);
|
||||
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
verifyNoInteractions(filterChain);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpStatus.FOUND.value());
|
||||
assertThat(response.getRedirectedUrl()).matches("https://example.com\\?" +
|
||||
"error=invalid_request&" +
|
||||
"error_description=OAuth%202.0%20Parameter:%20response_type&" +
|
||||
"error_uri=https://tools.ietf.org/html/rfc6749%23section-4.1.2.1&" +
|
||||
"state=state");
|
||||
doFilterWhenAuthorizationRequestInvalidParameterThenRedirect(
|
||||
registeredClient,
|
||||
OAuth2ParameterNames.RESPONSE_TYPE,
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
DEFAULT_ERROR_URI,
|
||||
request -> request.addParameter(OAuth2ParameterNames.RESPONSE_TYPE, "id_token"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -263,21 +240,156 @@ public class OAuth2AuthorizationEndpointFilterTests {
|
||||
when(this.registeredClientRepository.findByClientId((eq(registeredClient.getClientId()))))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
MockHttpServletRequest request = createAuthorizationRequest(registeredClient);
|
||||
request.setParameter(OAuth2ParameterNames.RESPONSE_TYPE, "id_token");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain filterChain = mock(FilterChain.class);
|
||||
doFilterWhenAuthorizationRequestInvalidParameterThenRedirect(
|
||||
registeredClient,
|
||||
OAuth2ParameterNames.RESPONSE_TYPE,
|
||||
OAuth2ErrorCodes.UNSUPPORTED_RESPONSE_TYPE,
|
||||
DEFAULT_ERROR_URI,
|
||||
request -> request.setParameter(OAuth2ParameterNames.RESPONSE_TYPE, "id_token"));
|
||||
}
|
||||
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
@Test
|
||||
public void doFilterWhenAuthorizationRequestInvalidScopeThenInvalidScopeError() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId((eq(registeredClient.getClientId()))))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
verifyNoInteractions(filterChain);
|
||||
doFilterWhenAuthorizationRequestInvalidParameterThenRedirect(
|
||||
registeredClient,
|
||||
OAuth2ParameterNames.SCOPE,
|
||||
OAuth2ErrorCodes.INVALID_SCOPE,
|
||||
DEFAULT_ERROR_URI,
|
||||
request -> {
|
||||
String scope = request.getParameter(OAuth2ParameterNames.SCOPE);
|
||||
request.setParameter(OAuth2ParameterNames.SCOPE, scope + " invalid-scope");
|
||||
});
|
||||
}
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpStatus.FOUND.value());
|
||||
assertThat(response.getRedirectedUrl()).matches("https://example.com\\?" +
|
||||
"error=unsupported_response_type&" +
|
||||
"error_description=OAuth%202.0%20Parameter:%20response_type&" +
|
||||
"error_uri=https://tools.ietf.org/html/rfc6749%23section-4.1.2.1&" +
|
||||
"state=state");
|
||||
@Test
|
||||
public void doFilterWhenPkceRequiredAndMissingCodeChallengeThenInvalidRequestError() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.clientSettings(clientSettings -> clientSettings.requireProofKey(true))
|
||||
.build();
|
||||
when(this.registeredClientRepository.findByClientId((eq(registeredClient.getClientId()))))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
doFilterWhenAuthorizationRequestInvalidParameterThenRedirect(
|
||||
registeredClient,
|
||||
PkceParameterNames.CODE_CHALLENGE,
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
PKCE_ERROR_URI,
|
||||
request -> {
|
||||
addPkceParameters(request);
|
||||
request.removeParameter(PkceParameterNames.CODE_CHALLENGE);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenPkceRequiredAndMultipleCodeChallengeThenInvalidRequestError() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.clientSettings(clientSettings -> clientSettings.requireProofKey(true))
|
||||
.build();
|
||||
when(this.registeredClientRepository.findByClientId((eq(registeredClient.getClientId()))))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
doFilterWhenAuthorizationRequestInvalidParameterThenRedirect(
|
||||
registeredClient,
|
||||
PkceParameterNames.CODE_CHALLENGE,
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
PKCE_ERROR_URI,
|
||||
request -> {
|
||||
addPkceParameters(request);
|
||||
request.addParameter(PkceParameterNames.CODE_CHALLENGE, "another-code-challenge");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenPkceNotRequiredAndMultipleCodeChallengeThenInvalidRequestError() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId((eq(registeredClient.getClientId()))))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
doFilterWhenAuthorizationRequestInvalidParameterThenRedirect(
|
||||
registeredClient,
|
||||
PkceParameterNames.CODE_CHALLENGE,
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
PKCE_ERROR_URI,
|
||||
request -> {
|
||||
addPkceParameters(request);
|
||||
request.addParameter(PkceParameterNames.CODE_CHALLENGE, "another-code-challenge");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenPkceRequiredAndMultipleCodeChallengeMethodThenInvalidRequestError() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.clientSettings(clientSettings -> clientSettings.requireProofKey(true))
|
||||
.build();
|
||||
when(this.registeredClientRepository.findByClientId((eq(registeredClient.getClientId()))))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
doFilterWhenAuthorizationRequestInvalidParameterThenRedirect(
|
||||
registeredClient,
|
||||
PkceParameterNames.CODE_CHALLENGE_METHOD,
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
PKCE_ERROR_URI,
|
||||
request -> {
|
||||
addPkceParameters(request);
|
||||
request.addParameter(PkceParameterNames.CODE_CHALLENGE_METHOD, "plain");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenPkceNotRequiredAndMultipleCodeChallengeMethodThenInvalidRequestError() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId((eq(registeredClient.getClientId()))))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
doFilterWhenAuthorizationRequestInvalidParameterThenRedirect(
|
||||
registeredClient,
|
||||
PkceParameterNames.CODE_CHALLENGE_METHOD,
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
PKCE_ERROR_URI,
|
||||
request -> {
|
||||
addPkceParameters(request);
|
||||
request.addParameter(PkceParameterNames.CODE_CHALLENGE_METHOD, "plain");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenPkceRequiredAndUnsupportedCodeChallengeMethodThenInvalidRequestError() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.clientSettings(clientSettings -> clientSettings.requireProofKey(true))
|
||||
.build();
|
||||
when(this.registeredClientRepository.findByClientId((eq(registeredClient.getClientId()))))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
doFilterWhenAuthorizationRequestInvalidParameterThenRedirect(
|
||||
registeredClient,
|
||||
PkceParameterNames.CODE_CHALLENGE_METHOD,
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
PKCE_ERROR_URI,
|
||||
request -> {
|
||||
addPkceParameters(request);
|
||||
request.setParameter(PkceParameterNames.CODE_CHALLENGE_METHOD, "unsupported");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenPkceNotRequiredAndUnsupportedCodeChallengeMethodThenInvalidRequestError() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId((eq(registeredClient.getClientId()))))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
doFilterWhenAuthorizationRequestInvalidParameterThenRedirect(
|
||||
registeredClient,
|
||||
PkceParameterNames.CODE_CHALLENGE_METHOD,
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
PKCE_ERROR_URI,
|
||||
request -> {
|
||||
addPkceParameters(request);
|
||||
request.setParameter(PkceParameterNames.CODE_CHALLENGE_METHOD, "unsupported");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -327,6 +439,10 @@ public class OAuth2AuthorizationEndpointFilterTests {
|
||||
|
||||
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST);
|
||||
assertThat(authorizationRequest).isNotNull();
|
||||
|
||||
Set<String> authorizedScopes = authorization.getAttribute(OAuth2AuthorizationAttributeNames.AUTHORIZED_SCOPES);
|
||||
assertThat(authorizedScopes).isEqualTo(authorizationRequest.getScopes());
|
||||
|
||||
assertThat(authorizationRequest.getAuthorizationUri()).isEqualTo("http://localhost/oauth2/authorize");
|
||||
assertThat(authorizationRequest.getGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||
assertThat(authorizationRequest.getResponseType()).isEqualTo(OAuth2AuthorizationResponseType.CODE);
|
||||
@@ -337,6 +453,317 @@ public class OAuth2AuthorizationEndpointFilterTests {
|
||||
assertThat(authorizationRequest.getAdditionalParameters()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenPkceRequiredAndAuthorizationRequestValidThenAuthorizationResponse() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.clientSettings(clientSettings -> clientSettings.requireProofKey(true))
|
||||
.build();
|
||||
when(this.registeredClientRepository.findByClientId((eq(registeredClient.getClientId()))))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
MockHttpServletRequest request = createAuthorizationRequest(registeredClient);
|
||||
addPkceParameters(request);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain filterChain = mock(FilterChain.class);
|
||||
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
verifyNoInteractions(filterChain);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpStatus.FOUND.value());
|
||||
assertThat(response.getRedirectedUrl()).matches("https://example.com\\?code=.{15,}&state=state");
|
||||
|
||||
ArgumentCaptor<OAuth2Authorization> authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class);
|
||||
|
||||
verify(this.authorizationService).save(authorizationCaptor.capture());
|
||||
|
||||
OAuth2Authorization authorization = authorizationCaptor.getValue();
|
||||
assertThat(authorization.getRegisteredClientId()).isEqualTo(registeredClient.getId());
|
||||
assertThat(authorization.getPrincipalName()).isEqualTo(this.authentication.getPrincipal().toString());
|
||||
|
||||
String code = authorization.getAttribute(OAuth2AuthorizationAttributeNames.CODE);
|
||||
assertThat(code).isNotNull();
|
||||
|
||||
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST);
|
||||
assertThat(authorizationRequest).isNotNull();
|
||||
|
||||
Set<String> authorizedScopes = authorization.getAttribute(OAuth2AuthorizationAttributeNames.AUTHORIZED_SCOPES);
|
||||
assertThat(authorizedScopes).isEqualTo(authorizationRequest.getScopes());
|
||||
|
||||
assertThat(authorizationRequest.getClientId()).isEqualTo(registeredClient.getClientId());
|
||||
assertThat(authorizationRequest.getAdditionalParameters())
|
||||
.size()
|
||||
.isEqualTo(2)
|
||||
.returnToMap()
|
||||
.containsEntry(PkceParameterNames.CODE_CHALLENGE, "code-challenge")
|
||||
.containsEntry(PkceParameterNames.CODE_CHALLENGE_METHOD, "S256");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenUserConsentRequiredAndAuthorizationRequestValidThenUserConsentResponse() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient()
|
||||
.clientSettings(clientSettings -> clientSettings.requireUserConsent(true))
|
||||
.build();
|
||||
when(this.registeredClientRepository.findByClientId((eq(registeredClient.getClientId()))))
|
||||
.thenReturn(registeredClient);
|
||||
|
||||
MockHttpServletRequest request = createAuthorizationRequest(registeredClient);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain filterChain = mock(FilterChain.class);
|
||||
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
verifyNoInteractions(filterChain);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
|
||||
assertThat(response.getContentType().equals(new MediaType("text", "html", StandardCharsets.UTF_8).toString()));
|
||||
|
||||
ArgumentCaptor<OAuth2Authorization> authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class);
|
||||
|
||||
verify(this.authorizationService).save(authorizationCaptor.capture());
|
||||
|
||||
OAuth2Authorization authorization = authorizationCaptor.getValue();
|
||||
assertThat(authorization.getRegisteredClientId()).isEqualTo(registeredClient.getId());
|
||||
assertThat(authorization.getPrincipalName()).isEqualTo(this.authentication.getPrincipal().toString());
|
||||
|
||||
String state = authorization.getAttribute(OAuth2AuthorizationAttributeNames.STATE);
|
||||
assertThat(state).isNotNull();
|
||||
|
||||
Set<String> authorizedScopes = authorization.getAttribute(OAuth2AuthorizationAttributeNames.AUTHORIZED_SCOPES);
|
||||
assertThat(authorizedScopes).isNull();
|
||||
|
||||
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST);
|
||||
assertThat(authorizationRequest).isNotNull();
|
||||
assertThat(authorizationRequest.getAuthorizationUri()).isEqualTo("http://localhost/oauth2/authorize");
|
||||
assertThat(authorizationRequest.getGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);
|
||||
assertThat(authorizationRequest.getResponseType()).isEqualTo(OAuth2AuthorizationResponseType.CODE);
|
||||
assertThat(authorizationRequest.getClientId()).isEqualTo(registeredClient.getClientId());
|
||||
assertThat(authorizationRequest.getRedirectUri()).isEqualTo(registeredClient.getRedirectUris().iterator().next());
|
||||
assertThat(authorizationRequest.getScopes()).containsExactlyInAnyOrderElementsOf(registeredClient.getScopes());
|
||||
assertThat(authorizationRequest.getState()).isEqualTo("state");
|
||||
assertThat(authorizationRequest.getAdditionalParameters()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenUserConsentRequestMissingStateThenInvalidRequestError() throws Exception {
|
||||
doFilterWhenUserConsentRequestInvalidParameterThenError(
|
||||
TestRegisteredClients.registeredClient().build(),
|
||||
OAuth2ParameterNames.STATE,
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
request -> request.removeParameter(OAuth2ParameterNames.STATE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenUserConsentRequestMultipleStateThenInvalidRequestError() throws Exception {
|
||||
doFilterWhenUserConsentRequestInvalidParameterThenError(
|
||||
TestRegisteredClients.registeredClient().build(),
|
||||
OAuth2ParameterNames.STATE,
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
request -> request.addParameter(OAuth2ParameterNames.STATE, "state-2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenUserConsentRequestInvalidStateThenInvalidRequestError() throws Exception {
|
||||
doFilterWhenUserConsentRequestInvalidParameterThenError(
|
||||
TestRegisteredClients.registeredClient().build(),
|
||||
OAuth2ParameterNames.STATE,
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
request -> request.setParameter(OAuth2ParameterNames.STATE, "invalid"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenUserConsentRequestNotAuthenticatedThenInvalidRequestError() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient).build();
|
||||
when(this.authorizationService.findByToken(eq("state"), eq(new TokenType(OAuth2AuthorizationAttributeNames.STATE))))
|
||||
.thenReturn(authorization);
|
||||
|
||||
this.authentication.setAuthenticated(false);
|
||||
|
||||
doFilterWhenUserConsentRequestInvalidParameterThenError(
|
||||
registeredClient,
|
||||
OAuth2ParameterNames.STATE,
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
request -> {});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenUserConsentRequestInvalidPrincipalThenInvalidRequestError() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient).build();
|
||||
when(this.authorizationService.findByToken(eq("state"), eq(new TokenType(OAuth2AuthorizationAttributeNames.STATE))))
|
||||
.thenReturn(authorization);
|
||||
|
||||
this.authentication = new TestingAuthenticationToken("other-principal", "password");
|
||||
this.authentication.setAuthenticated(true);
|
||||
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
|
||||
securityContext.setAuthentication(this.authentication);
|
||||
SecurityContextHolder.setContext(securityContext);
|
||||
|
||||
doFilterWhenUserConsentRequestInvalidParameterThenError(
|
||||
registeredClient,
|
||||
OAuth2ParameterNames.STATE,
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
request -> {});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenUserConsentRequestMissingClientIdThenInvalidRequestError() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.principalName(this.authentication.getName())
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(eq("state"), eq(new TokenType(OAuth2AuthorizationAttributeNames.STATE))))
|
||||
.thenReturn(authorization);
|
||||
|
||||
doFilterWhenUserConsentRequestInvalidParameterThenError(
|
||||
registeredClient,
|
||||
OAuth2ParameterNames.CLIENT_ID,
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
request -> request.removeParameter(OAuth2ParameterNames.CLIENT_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenUserConsentRequestMultipleClientIdThenInvalidRequestError() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.principalName(this.authentication.getName())
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(eq("state"), eq(new TokenType(OAuth2AuthorizationAttributeNames.STATE))))
|
||||
.thenReturn(authorization);
|
||||
|
||||
doFilterWhenUserConsentRequestInvalidParameterThenError(
|
||||
TestRegisteredClients.registeredClient().build(),
|
||||
OAuth2ParameterNames.CLIENT_ID,
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
request -> request.addParameter(OAuth2ParameterNames.CLIENT_ID, "client-2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenUserConsentRequestInvalidClientIdThenInvalidRequestError() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.principalName(this.authentication.getName())
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(eq("state"), eq(new TokenType(OAuth2AuthorizationAttributeNames.STATE))))
|
||||
.thenReturn(authorization);
|
||||
|
||||
doFilterWhenUserConsentRequestInvalidParameterThenError(
|
||||
registeredClient,
|
||||
OAuth2ParameterNames.CLIENT_ID,
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
request -> request.setParameter(OAuth2ParameterNames.CLIENT_ID, "invalid"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenUserConsentRequestDoesNotMatchClientThenInvalidRequestError() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
RegisteredClient otherRegisteredClient = TestRegisteredClients.registeredClient2().build();
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(otherRegisteredClient)
|
||||
.principalName(this.authentication.getName())
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(eq("state"), eq(new TokenType(OAuth2AuthorizationAttributeNames.STATE))))
|
||||
.thenReturn(authorization);
|
||||
|
||||
doFilterWhenUserConsentRequestInvalidParameterThenError(
|
||||
registeredClient,
|
||||
OAuth2ParameterNames.CLIENT_ID,
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
request -> {});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenUserConsentRequestInvalidScopeThenInvalidScopeError() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.principalName(this.authentication.getName())
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(eq("state"), eq(new TokenType(OAuth2AuthorizationAttributeNames.STATE))))
|
||||
.thenReturn(authorization);
|
||||
|
||||
doFilterWhenUserConsentRequestInvalidParameterThenRedirect(
|
||||
registeredClient,
|
||||
OAuth2ParameterNames.SCOPE,
|
||||
OAuth2ErrorCodes.INVALID_SCOPE,
|
||||
DEFAULT_ERROR_URI,
|
||||
request -> {
|
||||
request.addParameter(OAuth2ParameterNames.SCOPE, "invalid-scope");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenUserConsentRequestNotApprovedThenAccessDeniedError() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.principalName(this.authentication.getName())
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(eq("state"), eq(new TokenType(OAuth2AuthorizationAttributeNames.STATE))))
|
||||
.thenReturn(authorization);
|
||||
|
||||
doFilterWhenUserConsentRequestInvalidParameterThenRedirect(
|
||||
registeredClient,
|
||||
OAuth2ParameterNames.CLIENT_ID,
|
||||
OAuth2ErrorCodes.ACCESS_DENIED,
|
||||
DEFAULT_ERROR_URI,
|
||||
request -> request.removeParameter("consent_action"));
|
||||
|
||||
verify(this.authorizationService).remove(eq(authorization));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenUserConsentRequestApprovedThenAuthorizationResponse() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
||||
.thenReturn(registeredClient);
|
||||
OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient)
|
||||
.principalName(this.authentication.getName())
|
||||
.build();
|
||||
when(this.authorizationService.findByToken(eq("state"), eq(new TokenType(OAuth2AuthorizationAttributeNames.STATE))))
|
||||
.thenReturn(authorization);
|
||||
|
||||
MockHttpServletRequest request = createUserConsentRequest(registeredClient);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain filterChain = mock(FilterChain.class);
|
||||
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
verifyNoInteractions(filterChain);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpStatus.FOUND.value());
|
||||
assertThat(response.getRedirectedUrl()).matches("https://example.com\\?code=.{15,}&state=state");
|
||||
|
||||
ArgumentCaptor<OAuth2Authorization> authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class);
|
||||
|
||||
verify(this.authorizationService).save(authorizationCaptor.capture());
|
||||
|
||||
OAuth2Authorization updatedAuthorization = authorizationCaptor.getValue();
|
||||
assertThat(updatedAuthorization.getRegisteredClientId()).isEqualTo(registeredClient.getId());
|
||||
assertThat(updatedAuthorization.getPrincipalName()).isEqualTo(this.authentication.getPrincipal().toString());
|
||||
assertThat(updatedAuthorization.getAccessToken()).isNotNull();
|
||||
assertThat(updatedAuthorization.<String>getAttribute(OAuth2AuthorizationAttributeNames.STATE)).isNull();
|
||||
assertThat(updatedAuthorization.<String>getAttribute(OAuth2AuthorizationAttributeNames.CODE)).isNotNull();
|
||||
assertThat(updatedAuthorization.<OAuth2AuthorizationRequest>getAttribute(OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST))
|
||||
.isEqualTo(authorization.<OAuth2AuthorizationRequest>getAttribute(OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST));
|
||||
assertThat(updatedAuthorization.<Set<String>>getAttribute(OAuth2AuthorizationAttributeNames.AUTHORIZED_SCOPES))
|
||||
.isEqualTo(registeredClient.getScopes());
|
||||
}
|
||||
|
||||
private void doFilterWhenAuthorizationRequestInvalidParameterThenError(RegisteredClient registeredClient,
|
||||
String parameterName, String errorCode) throws Exception {
|
||||
doFilterWhenAuthorizationRequestInvalidParameterThenError(registeredClient, parameterName, errorCode, request -> {});
|
||||
@@ -345,7 +772,36 @@ public class OAuth2AuthorizationEndpointFilterTests {
|
||||
private void doFilterWhenAuthorizationRequestInvalidParameterThenError(RegisteredClient registeredClient,
|
||||
String parameterName, String errorCode, Consumer<MockHttpServletRequest> requestConsumer) throws Exception {
|
||||
|
||||
MockHttpServletRequest request = createAuthorizationRequest(registeredClient);
|
||||
doFilterWhenRequestInvalidParameterThenError(createAuthorizationRequest(registeredClient),
|
||||
parameterName, errorCode, requestConsumer);
|
||||
}
|
||||
|
||||
private void doFilterWhenAuthorizationRequestInvalidParameterThenRedirect(RegisteredClient registeredClient,
|
||||
String parameterName, String errorCode, String errorUri,
|
||||
Consumer<MockHttpServletRequest> requestConsumer) throws Exception {
|
||||
|
||||
doFilterWhenRequestInvalidParameterThenRedirect(createAuthorizationRequest(registeredClient),
|
||||
parameterName, errorCode, errorUri, requestConsumer);
|
||||
}
|
||||
|
||||
private void doFilterWhenUserConsentRequestInvalidParameterThenError(RegisteredClient registeredClient,
|
||||
String parameterName, String errorCode, Consumer<MockHttpServletRequest> requestConsumer) throws Exception {
|
||||
|
||||
doFilterWhenRequestInvalidParameterThenError(createUserConsentRequest(registeredClient),
|
||||
parameterName, errorCode, requestConsumer);
|
||||
}
|
||||
|
||||
private void doFilterWhenUserConsentRequestInvalidParameterThenRedirect(RegisteredClient registeredClient,
|
||||
String parameterName, String errorCode, String errorUri,
|
||||
Consumer<MockHttpServletRequest> requestConsumer) throws Exception {
|
||||
|
||||
doFilterWhenRequestInvalidParameterThenRedirect(createUserConsentRequest(registeredClient),
|
||||
parameterName, errorCode, errorUri, requestConsumer);
|
||||
}
|
||||
|
||||
private void doFilterWhenRequestInvalidParameterThenError(MockHttpServletRequest request,
|
||||
String parameterName, String errorCode, Consumer<MockHttpServletRequest> requestConsumer) throws Exception {
|
||||
|
||||
requestConsumer.accept(request);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain filterChain = mock(FilterChain.class);
|
||||
@@ -358,6 +814,26 @@ public class OAuth2AuthorizationEndpointFilterTests {
|
||||
assertThat(response.getErrorMessage()).isEqualTo("[" + errorCode + "] OAuth 2.0 Parameter: " + parameterName);
|
||||
}
|
||||
|
||||
private void doFilterWhenRequestInvalidParameterThenRedirect(MockHttpServletRequest request,
|
||||
String parameterName, String errorCode, String errorUri,
|
||||
Consumer<MockHttpServletRequest> requestConsumer) throws Exception {
|
||||
|
||||
requestConsumer.accept(request);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain filterChain = mock(FilterChain.class);
|
||||
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
verifyNoInteractions(filterChain);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpStatus.FOUND.value());
|
||||
assertThat(response.getRedirectedUrl()).matches("https://example.com\\?" +
|
||||
"error=" + errorCode + "&" +
|
||||
"error_description=OAuth%202.0%20Parameter:%20" + parameterName + "&" +
|
||||
"error_uri=" + errorUri + "&" +
|
||||
"state=state");
|
||||
}
|
||||
|
||||
private static MockHttpServletRequest createAuthorizationRequest(RegisteredClient registeredClient) {
|
||||
String[] redirectUris = registeredClient.getRedirectUris().toArray(new String[0]);
|
||||
|
||||
@@ -374,4 +850,24 @@ public class OAuth2AuthorizationEndpointFilterTests {
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
private static void addPkceParameters(MockHttpServletRequest request) {
|
||||
request.addParameter(PkceParameterNames.CODE_CHALLENGE, "code-challenge");
|
||||
request.addParameter(PkceParameterNames.CODE_CHALLENGE_METHOD, "S256");
|
||||
}
|
||||
|
||||
private static MockHttpServletRequest createUserConsentRequest(RegisteredClient registeredClient) {
|
||||
String requestUri = OAuth2AuthorizationEndpointFilter.DEFAULT_AUTHORIZATION_ENDPOINT_URI;
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", requestUri);
|
||||
request.setServletPath(requestUri);
|
||||
|
||||
request.addParameter(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId());
|
||||
request.addParameter(OAuth2ParameterNames.STATE, "state");
|
||||
for (String scope : registeredClient.getScopes()) {
|
||||
request.addParameter(OAuth2ParameterNames.SCOPE, scope);
|
||||
}
|
||||
request.addParameter("consent_action", "approve");
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ public class OAuth2ClientAuthenticationFilterTests {
|
||||
@Test
|
||||
public void doFilterWhenRequestMatchesAndBadCredentialsThenInvalidClientError() throws Exception {
|
||||
when(this.authenticationConverter.convert(any(HttpServletRequest.class))).thenReturn(
|
||||
new OAuth2ClientAuthenticationToken("clientId", "invalid-secret"));
|
||||
new OAuth2ClientAuthenticationToken("clientId", "invalid-secret", null));
|
||||
when(this.authenticationManager.authenticate(any(Authentication.class))).thenThrow(
|
||||
new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_CLIENT)));
|
||||
|
||||
@@ -185,7 +185,7 @@ public class OAuth2ClientAuthenticationFilterTests {
|
||||
public void doFilterWhenRequestMatchesAndValidCredentialsThenProcessed() throws Exception {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
when(this.authenticationConverter.convert(any(HttpServletRequest.class))).thenReturn(
|
||||
new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), registeredClient.getClientSecret()));
|
||||
new OAuth2ClientAuthenticationToken(registeredClient.getClientId(), registeredClient.getClientSecret(), null));
|
||||
when(this.authenticationManager.authenticate(any(Authentication.class))).thenReturn(
|
||||
new OAuth2ClientAuthenticationToken(registeredClient));
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ import static org.mockito.Mockito.when;
|
||||
*
|
||||
* @author Madhu Bhat
|
||||
* @author Joe Grandja
|
||||
* @author Daniel Garnier-Moiroux
|
||||
*/
|
||||
public class OAuth2TokenEndpointFilterTests {
|
||||
private AuthenticationManager authenticationManager;
|
||||
@@ -165,17 +166,6 @@ public class OAuth2TokenEndpointFilterTests {
|
||||
OAuth2ParameterNames.GRANT_TYPE, OAuth2ErrorCodes.UNSUPPORTED_GRANT_TYPE, request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenTokenRequestMultipleClientIdThenInvalidRequestError() throws Exception {
|
||||
MockHttpServletRequest request = createAuthorizationCodeTokenRequest(
|
||||
TestRegisteredClients.registeredClient().build());
|
||||
request.addParameter(OAuth2ParameterNames.CLIENT_ID, "client-1");
|
||||
request.addParameter(OAuth2ParameterNames.CLIENT_ID, "client-2");
|
||||
|
||||
doFilterWhenTokenRequestInvalidParameterThenError(
|
||||
OAuth2ParameterNames.CLIENT_ID, OAuth2ErrorCodes.INVALID_REQUEST, request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenTokenRequestMissingCodeThenInvalidRequestError() throws Exception {
|
||||
MockHttpServletRequest request = createAuthorizationCodeTokenRequest(
|
||||
@@ -359,6 +349,8 @@ public class OAuth2TokenEndpointFilterTests {
|
||||
request.addParameter(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue());
|
||||
request.addParameter(OAuth2ParameterNames.CODE, "code");
|
||||
request.addParameter(OAuth2ParameterNames.REDIRECT_URI, redirectUris[0]);
|
||||
// The client does not need to send the client ID param, but we are resilient in case they do
|
||||
request.addParameter(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId());
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.security.oauth2.server.authorization.web;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.core.endpoint.PkceParameterNames;
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
|
||||
/**
|
||||
* Tests for {@link PublicClientAuthenticationConverter}.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
*/
|
||||
public class PublicClientAuthenticationConverterTests {
|
||||
private PublicClientAuthenticationConverter converter = new PublicClientAuthenticationConverter();
|
||||
|
||||
@Test
|
||||
public void convertWhenNotPublicClientThenReturnNull() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
Authentication authentication = this.converter.convert(request);
|
||||
assertThat(authentication).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertWhenMissingClientIdThenReturnNull() {
|
||||
MockHttpServletRequest request = createPkceTokenRequest();
|
||||
request.removeParameter(OAuth2ParameterNames.CLIENT_ID);
|
||||
Authentication authentication = this.converter.convert(request);
|
||||
assertThat(authentication).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertWhenMultipleClientIdThenInvalidRequestError() {
|
||||
MockHttpServletRequest request = createPkceTokenRequest();
|
||||
request.addParameter(OAuth2ParameterNames.CLIENT_ID, "client-2");
|
||||
assertThatThrownBy(() -> this.converter.convert(request))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.extracting("errorCode")
|
||||
.isEqualTo(OAuth2ErrorCodes.INVALID_REQUEST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertWhenMultipleCodeVerifierThenInvalidRequestError() {
|
||||
MockHttpServletRequest request = createPkceTokenRequest();
|
||||
request.addParameter(PkceParameterNames.CODE_VERIFIER, "code-verifier-2");
|
||||
assertThatThrownBy(() -> this.converter.convert(request))
|
||||
.isInstanceOf(OAuth2AuthenticationException.class)
|
||||
.extracting(ex -> ((OAuth2AuthenticationException) ex).getError())
|
||||
.extracting("errorCode")
|
||||
.isEqualTo(OAuth2ErrorCodes.INVALID_REQUEST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertWhenPublicClientThenReturnClientAuthenticationToken() {
|
||||
MockHttpServletRequest request = createPkceTokenRequest();
|
||||
OAuth2ClientAuthenticationToken authentication = (OAuth2ClientAuthenticationToken) this.converter.convert(request);
|
||||
assertThat(authentication.getPrincipal()).isEqualTo("client-1");
|
||||
assertThat(authentication.getAdditionalParameters())
|
||||
.containsOnly(
|
||||
entry(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue()),
|
||||
entry(OAuth2ParameterNames.CODE, "code"),
|
||||
entry(PkceParameterNames.CODE_VERIFIER, "code-verifier-1"));
|
||||
}
|
||||
|
||||
private static MockHttpServletRequest createPkceTokenRequest() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addParameter(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue());
|
||||
request.addParameter(OAuth2ParameterNames.CODE, "code");
|
||||
request.addParameter(OAuth2ParameterNames.CLIENT_ID, "client-1");
|
||||
request.addParameter(PkceParameterNames.CODE_VERIFIER, "code-verifier-1");
|
||||
return request;
|
||||
}
|
||||
}
|
||||
@@ -8,4 +8,4 @@ This sample integrates `spring-security-oauth2-client` and `spring-security-oaut
|
||||
** *IMPORTANT:* Make sure to modify your `/etc/hosts` file to avoid problems with session cookie overwrites between `client` and `authorizationserver`. Simply add the entry `127.0.0.1 auth-server`
|
||||
* Run Resource Server -> `./gradlew -b samples/boot/oauth2-integration/resourceserver/spring-security-samples-boot-oauth2-integrated-resourceserver.gradle bootRun`
|
||||
* Run Client -> `./gradlew -b samples/boot/oauth2-integration/client/spring-security-samples-boot-oauth2-integrated-client.gradle bootRun`
|
||||
* Go to `http://localhost:8080` and login using *user1/password*
|
||||
* Go to `http://localhost:8080`
|
||||
|
||||
@@ -10,37 +10,34 @@ com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.2
|
||||
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.2
|
||||
com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.2
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
jakarta.annotation:jakarta.annotation-api:1.3.5
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.apache.logging.log4j:log4j-api:2.13.3
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.38
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.38
|
||||
org.glassfish:jakarta.el:3.0.3
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M2
|
||||
org.springframework.boot:spring-boot:2.4.0-M2
|
||||
org.springframework.security:spring-security-config:5.4.0-RC1
|
||||
org.springframework.security:spring-security-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0-RC1
|
||||
org.springframework.security:spring-security-web:5.4.0-RC1
|
||||
org.springframework:spring-aop:5.3.0-M2
|
||||
org.springframework:spring-beans:5.3.0-M2
|
||||
org.springframework:spring-context:5.3.0-M2
|
||||
org.springframework:spring-core:5.3.0-M2
|
||||
org.springframework:spring-expression:5.3.0-M2
|
||||
org.springframework:spring-jcl:5.3.0-M2
|
||||
org.springframework:spring-web:5.3.0-M2
|
||||
org.springframework:spring-webmvc:5.3.0-M2
|
||||
org.yaml:snakeyaml:1.26
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M3
|
||||
org.springframework.boot:spring-boot:2.4.0-M3
|
||||
org.springframework.security:spring-security-config:5.4.0
|
||||
org.springframework.security:spring-security-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0
|
||||
org.springframework.security:spring-security-web:5.4.0
|
||||
org.springframework:spring-aop:5.3.0-RC1
|
||||
org.springframework:spring-beans:5.3.0-RC1
|
||||
org.springframework:spring-context:5.3.0-RC1
|
||||
org.springframework:spring-core:5.3.0-RC1
|
||||
org.springframework:spring-expression:5.3.0-RC1
|
||||
org.springframework:spring-jcl:5.3.0-RC1
|
||||
org.springframework:spring-web:5.3.0-RC1
|
||||
org.springframework:spring-webmvc:5.3.0-RC1
|
||||
org.yaml:snakeyaml:1.27
|
||||
|
||||
@@ -10,37 +10,34 @@ com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.2
|
||||
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.2
|
||||
com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.2
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
jakarta.annotation:jakarta.annotation-api:1.3.5
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.apache.logging.log4j:log4j-api:2.13.3
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.38
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.38
|
||||
org.glassfish:jakarta.el:3.0.3
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M2
|
||||
org.springframework.boot:spring-boot:2.4.0-M2
|
||||
org.springframework.security:spring-security-config:5.4.0-RC1
|
||||
org.springframework.security:spring-security-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0-RC1
|
||||
org.springframework.security:spring-security-web:5.4.0-RC1
|
||||
org.springframework:spring-aop:5.3.0-M2
|
||||
org.springframework:spring-beans:5.3.0-M2
|
||||
org.springframework:spring-context:5.3.0-M2
|
||||
org.springframework:spring-core:5.3.0-M2
|
||||
org.springframework:spring-expression:5.3.0-M2
|
||||
org.springframework:spring-jcl:5.3.0-M2
|
||||
org.springframework:spring-web:5.3.0-M2
|
||||
org.springframework:spring-webmvc:5.3.0-M2
|
||||
org.yaml:snakeyaml:1.26
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M3
|
||||
org.springframework.boot:spring-boot:2.4.0-M3
|
||||
org.springframework.security:spring-security-config:5.4.0
|
||||
org.springframework.security:spring-security-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0
|
||||
org.springframework.security:spring-security-web:5.4.0
|
||||
org.springframework:spring-aop:5.3.0-RC1
|
||||
org.springframework:spring-beans:5.3.0-RC1
|
||||
org.springframework:spring-context:5.3.0-RC1
|
||||
org.springframework:spring-core:5.3.0-RC1
|
||||
org.springframework:spring-expression:5.3.0-RC1
|
||||
org.springframework:spring-jcl:5.3.0-RC1
|
||||
org.springframework:spring-web:5.3.0-RC1
|
||||
org.springframework:spring-webmvc:5.3.0-RC1
|
||||
org.yaml:snakeyaml:1.27
|
||||
|
||||
@@ -10,37 +10,34 @@ com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.2
|
||||
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.2
|
||||
com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.2
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
jakarta.annotation:jakarta.annotation-api:1.3.5
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.apache.logging.log4j:log4j-api:2.13.3
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.38
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.38
|
||||
org.glassfish:jakarta.el:3.0.3
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M2
|
||||
org.springframework.boot:spring-boot:2.4.0-M2
|
||||
org.springframework.security:spring-security-config:5.4.0-RC1
|
||||
org.springframework.security:spring-security-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0-RC1
|
||||
org.springframework.security:spring-security-web:5.4.0-RC1
|
||||
org.springframework:spring-aop:5.3.0-M2
|
||||
org.springframework:spring-beans:5.3.0-M2
|
||||
org.springframework:spring-context:5.3.0-M2
|
||||
org.springframework:spring-core:5.3.0-M2
|
||||
org.springframework:spring-expression:5.3.0-M2
|
||||
org.springframework:spring-jcl:5.3.0-M2
|
||||
org.springframework:spring-web:5.3.0-M2
|
||||
org.springframework:spring-webmvc:5.3.0-M2
|
||||
org.yaml:snakeyaml:1.26
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M3
|
||||
org.springframework.boot:spring-boot:2.4.0-M3
|
||||
org.springframework.security:spring-security-config:5.4.0
|
||||
org.springframework.security:spring-security-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0
|
||||
org.springframework.security:spring-security-web:5.4.0
|
||||
org.springframework:spring-aop:5.3.0-RC1
|
||||
org.springframework:spring-beans:5.3.0-RC1
|
||||
org.springframework:spring-context:5.3.0-RC1
|
||||
org.springframework:spring-core:5.3.0-RC1
|
||||
org.springframework:spring-expression:5.3.0-RC1
|
||||
org.springframework:spring-jcl:5.3.0-RC1
|
||||
org.springframework:spring-web:5.3.0-RC1
|
||||
org.springframework:spring-webmvc:5.3.0-RC1
|
||||
org.yaml:snakeyaml:1.27
|
||||
|
||||
@@ -10,37 +10,34 @@ com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.2
|
||||
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.2
|
||||
com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.2
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
jakarta.annotation:jakarta.annotation-api:1.3.5
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.apache.logging.log4j:log4j-api:2.13.3
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.38
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.38
|
||||
org.glassfish:jakarta.el:3.0.3
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M2
|
||||
org.springframework.boot:spring-boot:2.4.0-M2
|
||||
org.springframework.security:spring-security-config:5.4.0-RC1
|
||||
org.springframework.security:spring-security-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0-RC1
|
||||
org.springframework.security:spring-security-web:5.4.0-RC1
|
||||
org.springframework:spring-aop:5.3.0-M2
|
||||
org.springframework:spring-beans:5.3.0-M2
|
||||
org.springframework:spring-context:5.3.0-M2
|
||||
org.springframework:spring-core:5.3.0-M2
|
||||
org.springframework:spring-expression:5.3.0-M2
|
||||
org.springframework:spring-jcl:5.3.0-M2
|
||||
org.springframework:spring-web:5.3.0-M2
|
||||
org.springframework:spring-webmvc:5.3.0-M2
|
||||
org.yaml:snakeyaml:1.26
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M3
|
||||
org.springframework.boot:spring-boot:2.4.0-M3
|
||||
org.springframework.security:spring-security-config:5.4.0
|
||||
org.springframework.security:spring-security-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0
|
||||
org.springframework.security:spring-security-web:5.4.0
|
||||
org.springframework:spring-aop:5.3.0-RC1
|
||||
org.springframework:spring-beans:5.3.0-RC1
|
||||
org.springframework:spring-context:5.3.0-RC1
|
||||
org.springframework:spring-core:5.3.0-RC1
|
||||
org.springframework:spring-expression:5.3.0-RC1
|
||||
org.springframework:spring-jcl:5.3.0-RC1
|
||||
org.springframework:spring-web:5.3.0-RC1
|
||||
org.springframework:spring-webmvc:5.3.0-RC1
|
||||
org.yaml:snakeyaml:1.27
|
||||
|
||||
@@ -10,37 +10,34 @@ com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.2
|
||||
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.2
|
||||
com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.2
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
jakarta.annotation:jakarta.annotation-api:1.3.5
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.apache.logging.log4j:log4j-api:2.13.3
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.38
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.38
|
||||
org.glassfish:jakarta.el:3.0.3
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M2
|
||||
org.springframework.boot:spring-boot:2.4.0-M2
|
||||
org.springframework.security:spring-security-config:5.4.0-RC1
|
||||
org.springframework.security:spring-security-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0-RC1
|
||||
org.springframework.security:spring-security-web:5.4.0-RC1
|
||||
org.springframework:spring-aop:5.3.0-M2
|
||||
org.springframework:spring-beans:5.3.0-M2
|
||||
org.springframework:spring-context:5.3.0-M2
|
||||
org.springframework:spring-core:5.3.0-M2
|
||||
org.springframework:spring-expression:5.3.0-M2
|
||||
org.springframework:spring-jcl:5.3.0-M2
|
||||
org.springframework:spring-web:5.3.0-M2
|
||||
org.springframework:spring-webmvc:5.3.0-M2
|
||||
org.yaml:snakeyaml:1.26
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M3
|
||||
org.springframework.boot:spring-boot:2.4.0-M3
|
||||
org.springframework.security:spring-security-config:5.4.0
|
||||
org.springframework.security:spring-security-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0
|
||||
org.springframework.security:spring-security-web:5.4.0
|
||||
org.springframework:spring-aop:5.3.0-RC1
|
||||
org.springframework:spring-beans:5.3.0-RC1
|
||||
org.springframework:spring-context:5.3.0-RC1
|
||||
org.springframework:spring-core:5.3.0-RC1
|
||||
org.springframework:spring-expression:5.3.0-RC1
|
||||
org.springframework:spring-jcl:5.3.0-RC1
|
||||
org.springframework:spring-web:5.3.0-RC1
|
||||
org.springframework:spring-webmvc:5.3.0-RC1
|
||||
org.yaml:snakeyaml:1.27
|
||||
|
||||
@@ -10,37 +10,34 @@ com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.2
|
||||
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.2
|
||||
com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.2
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
jakarta.annotation:jakarta.annotation-api:1.3.5
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.apache.logging.log4j:log4j-api:2.13.3
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.38
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.38
|
||||
org.glassfish:jakarta.el:3.0.3
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M2
|
||||
org.springframework.boot:spring-boot:2.4.0-M2
|
||||
org.springframework.security:spring-security-config:5.4.0-RC1
|
||||
org.springframework.security:spring-security-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0-RC1
|
||||
org.springframework.security:spring-security-web:5.4.0-RC1
|
||||
org.springframework:spring-aop:5.3.0-M2
|
||||
org.springframework:spring-beans:5.3.0-M2
|
||||
org.springframework:spring-context:5.3.0-M2
|
||||
org.springframework:spring-core:5.3.0-M2
|
||||
org.springframework:spring-expression:5.3.0-M2
|
||||
org.springframework:spring-jcl:5.3.0-M2
|
||||
org.springframework:spring-web:5.3.0-M2
|
||||
org.springframework:spring-webmvc:5.3.0-M2
|
||||
org.yaml:snakeyaml:1.26
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M3
|
||||
org.springframework.boot:spring-boot:2.4.0-M3
|
||||
org.springframework.security:spring-security-config:5.4.0
|
||||
org.springframework.security:spring-security-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0
|
||||
org.springframework.security:spring-security-web:5.4.0
|
||||
org.springframework:spring-aop:5.3.0-RC1
|
||||
org.springframework:spring-beans:5.3.0-RC1
|
||||
org.springframework:spring-context:5.3.0-RC1
|
||||
org.springframework:spring-core:5.3.0-RC1
|
||||
org.springframework:spring-expression:5.3.0-RC1
|
||||
org.springframework:spring-jcl:5.3.0-RC1
|
||||
org.springframework:spring-web:5.3.0-RC1
|
||||
org.springframework:spring-webmvc:5.3.0-RC1
|
||||
org.yaml:snakeyaml:1.27
|
||||
|
||||
@@ -10,46 +10,43 @@ com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.2
|
||||
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.2
|
||||
com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.2
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
jakarta.annotation:jakarta.annotation-api:1.3.5
|
||||
junit:junit:4.13
|
||||
junit:junit:4.13.1
|
||||
net.bytebuddy:byte-buddy-agent:1.10.14
|
||||
net.bytebuddy:byte-buddy:1.10.14
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.apache.logging.log4j:log4j-api:2.13.3
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.37
|
||||
org.assertj:assertj-core:3.16.1
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.38
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.38
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.glassfish:jakarta.el:3.0.3
|
||||
org.hamcrest:hamcrest-core:2.2
|
||||
org.hamcrest:hamcrest:2.2
|
||||
org.mockito:mockito-core:3.5.2
|
||||
org.mockito:mockito-core:3.5.13
|
||||
org.objenesis:objenesis:3.1
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M2
|
||||
org.springframework.boot:spring-boot:2.4.0-M2
|
||||
org.springframework.security:spring-security-config:5.4.0-RC1
|
||||
org.springframework.security:spring-security-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0-RC1
|
||||
org.springframework.security:spring-security-web:5.4.0-RC1
|
||||
org.springframework:spring-aop:5.3.0-M2
|
||||
org.springframework:spring-beans:5.3.0-M2
|
||||
org.springframework:spring-context:5.3.0-M2
|
||||
org.springframework:spring-core:5.3.0-M2
|
||||
org.springframework:spring-expression:5.3.0-M2
|
||||
org.springframework:spring-jcl:5.3.0-M2
|
||||
org.springframework:spring-test:5.3.0-M2
|
||||
org.springframework:spring-web:5.3.0-M2
|
||||
org.springframework:spring-webmvc:5.3.0-M2
|
||||
org.yaml:snakeyaml:1.26
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M3
|
||||
org.springframework.boot:spring-boot:2.4.0-M3
|
||||
org.springframework.security:spring-security-config:5.4.0
|
||||
org.springframework.security:spring-security-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0
|
||||
org.springframework.security:spring-security-web:5.4.0
|
||||
org.springframework:spring-aop:5.3.0-RC1
|
||||
org.springframework:spring-beans:5.3.0-RC1
|
||||
org.springframework:spring-context:5.3.0-RC1
|
||||
org.springframework:spring-core:5.3.0-RC1
|
||||
org.springframework:spring-expression:5.3.0-RC1
|
||||
org.springframework:spring-jcl:5.3.0-RC1
|
||||
org.springframework:spring-test:5.3.0-RC1
|
||||
org.springframework:spring-web:5.3.0-RC1
|
||||
org.springframework:spring-webmvc:5.3.0-RC1
|
||||
org.yaml:snakeyaml:1.27
|
||||
|
||||
@@ -10,46 +10,43 @@ com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.2
|
||||
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.2
|
||||
com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.2
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
jakarta.annotation:jakarta.annotation-api:1.3.5
|
||||
junit:junit:4.13
|
||||
junit:junit:4.13.1
|
||||
net.bytebuddy:byte-buddy-agent:1.10.14
|
||||
net.bytebuddy:byte-buddy:1.10.14
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.apache.logging.log4j:log4j-api:2.13.3
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.37
|
||||
org.assertj:assertj-core:3.16.1
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.38
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.38
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.glassfish:jakarta.el:3.0.3
|
||||
org.hamcrest:hamcrest-core:2.2
|
||||
org.hamcrest:hamcrest:2.2
|
||||
org.mockito:mockito-core:3.5.2
|
||||
org.mockito:mockito-core:3.5.13
|
||||
org.objenesis:objenesis:3.1
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M2
|
||||
org.springframework.boot:spring-boot:2.4.0-M2
|
||||
org.springframework.security:spring-security-config:5.4.0-RC1
|
||||
org.springframework.security:spring-security-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0-RC1
|
||||
org.springframework.security:spring-security-web:5.4.0-RC1
|
||||
org.springframework:spring-aop:5.3.0-M2
|
||||
org.springframework:spring-beans:5.3.0-M2
|
||||
org.springframework:spring-context:5.3.0-M2
|
||||
org.springframework:spring-core:5.3.0-M2
|
||||
org.springframework:spring-expression:5.3.0-M2
|
||||
org.springframework:spring-jcl:5.3.0-M2
|
||||
org.springframework:spring-test:5.3.0-M2
|
||||
org.springframework:spring-web:5.3.0-M2
|
||||
org.springframework:spring-webmvc:5.3.0-M2
|
||||
org.yaml:snakeyaml:1.26
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M3
|
||||
org.springframework.boot:spring-boot:2.4.0-M3
|
||||
org.springframework.security:spring-security-config:5.4.0
|
||||
org.springframework.security:spring-security-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0
|
||||
org.springframework.security:spring-security-web:5.4.0
|
||||
org.springframework:spring-aop:5.3.0-RC1
|
||||
org.springframework:spring-beans:5.3.0-RC1
|
||||
org.springframework:spring-context:5.3.0-RC1
|
||||
org.springframework:spring-core:5.3.0-RC1
|
||||
org.springframework:spring-expression:5.3.0-RC1
|
||||
org.springframework:spring-jcl:5.3.0-RC1
|
||||
org.springframework:spring-test:5.3.0-RC1
|
||||
org.springframework:spring-web:5.3.0-RC1
|
||||
org.springframework:spring-webmvc:5.3.0-RC1
|
||||
org.yaml:snakeyaml:1.27
|
||||
|
||||
@@ -10,46 +10,43 @@ com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.2
|
||||
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.2
|
||||
com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.2
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
jakarta.annotation:jakarta.annotation-api:1.3.5
|
||||
junit:junit:4.13
|
||||
junit:junit:4.13.1
|
||||
net.bytebuddy:byte-buddy-agent:1.10.14
|
||||
net.bytebuddy:byte-buddy:1.10.14
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.apache.logging.log4j:log4j-api:2.13.3
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.37
|
||||
org.assertj:assertj-core:3.16.1
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.38
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.38
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.glassfish:jakarta.el:3.0.3
|
||||
org.hamcrest:hamcrest-core:2.2
|
||||
org.hamcrest:hamcrest:2.2
|
||||
org.mockito:mockito-core:3.5.2
|
||||
org.mockito:mockito-core:3.5.13
|
||||
org.objenesis:objenesis:3.1
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M2
|
||||
org.springframework.boot:spring-boot:2.4.0-M2
|
||||
org.springframework.security:spring-security-config:5.4.0-RC1
|
||||
org.springframework.security:spring-security-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0-RC1
|
||||
org.springframework.security:spring-security-web:5.4.0-RC1
|
||||
org.springframework:spring-aop:5.3.0-M2
|
||||
org.springframework:spring-beans:5.3.0-M2
|
||||
org.springframework:spring-context:5.3.0-M2
|
||||
org.springframework:spring-core:5.3.0-M2
|
||||
org.springframework:spring-expression:5.3.0-M2
|
||||
org.springframework:spring-jcl:5.3.0-M2
|
||||
org.springframework:spring-test:5.3.0-M2
|
||||
org.springframework:spring-web:5.3.0-M2
|
||||
org.springframework:spring-webmvc:5.3.0-M2
|
||||
org.yaml:snakeyaml:1.26
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M3
|
||||
org.springframework.boot:spring-boot:2.4.0-M3
|
||||
org.springframework.security:spring-security-config:5.4.0
|
||||
org.springframework.security:spring-security-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0
|
||||
org.springframework.security:spring-security-web:5.4.0
|
||||
org.springframework:spring-aop:5.3.0-RC1
|
||||
org.springframework:spring-beans:5.3.0-RC1
|
||||
org.springframework:spring-context:5.3.0-RC1
|
||||
org.springframework:spring-core:5.3.0-RC1
|
||||
org.springframework:spring-expression:5.3.0-RC1
|
||||
org.springframework:spring-jcl:5.3.0-RC1
|
||||
org.springframework:spring-test:5.3.0-RC1
|
||||
org.springframework:spring-web:5.3.0-RC1
|
||||
org.springframework:spring-webmvc:5.3.0-RC1
|
||||
org.yaml:snakeyaml:1.27
|
||||
|
||||
@@ -10,46 +10,43 @@ com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.2
|
||||
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.2
|
||||
com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.2
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
jakarta.annotation:jakarta.annotation-api:1.3.5
|
||||
junit:junit:4.13
|
||||
junit:junit:4.13.1
|
||||
net.bytebuddy:byte-buddy-agent:1.10.14
|
||||
net.bytebuddy:byte-buddy:1.10.14
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.apache.logging.log4j:log4j-api:2.13.3
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.37
|
||||
org.assertj:assertj-core:3.16.1
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.38
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.38
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.glassfish:jakarta.el:3.0.3
|
||||
org.hamcrest:hamcrest-core:2.2
|
||||
org.hamcrest:hamcrest:2.2
|
||||
org.mockito:mockito-core:3.5.2
|
||||
org.mockito:mockito-core:3.5.13
|
||||
org.objenesis:objenesis:3.1
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M2
|
||||
org.springframework.boot:spring-boot:2.4.0-M2
|
||||
org.springframework.security:spring-security-config:5.4.0-RC1
|
||||
org.springframework.security:spring-security-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0-RC1
|
||||
org.springframework.security:spring-security-web:5.4.0-RC1
|
||||
org.springframework:spring-aop:5.3.0-M2
|
||||
org.springframework:spring-beans:5.3.0-M2
|
||||
org.springframework:spring-context:5.3.0-M2
|
||||
org.springframework:spring-core:5.3.0-M2
|
||||
org.springframework:spring-expression:5.3.0-M2
|
||||
org.springframework:spring-jcl:5.3.0-M2
|
||||
org.springframework:spring-test:5.3.0-M2
|
||||
org.springframework:spring-web:5.3.0-M2
|
||||
org.springframework:spring-webmvc:5.3.0-M2
|
||||
org.yaml:snakeyaml:1.26
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M3
|
||||
org.springframework.boot:spring-boot:2.4.0-M3
|
||||
org.springframework.security:spring-security-config:5.4.0
|
||||
org.springframework.security:spring-security-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0
|
||||
org.springframework.security:spring-security-web:5.4.0
|
||||
org.springframework:spring-aop:5.3.0-RC1
|
||||
org.springframework:spring-beans:5.3.0-RC1
|
||||
org.springframework:spring-context:5.3.0-RC1
|
||||
org.springframework:spring-core:5.3.0-RC1
|
||||
org.springframework:spring-expression:5.3.0-RC1
|
||||
org.springframework:spring-jcl:5.3.0-RC1
|
||||
org.springframework:spring-test:5.3.0-RC1
|
||||
org.springframework:spring-web:5.3.0-RC1
|
||||
org.springframework:spring-webmvc:5.3.0-RC1
|
||||
org.yaml:snakeyaml:1.27
|
||||
|
||||
@@ -10,46 +10,43 @@ com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.2
|
||||
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.2
|
||||
com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.2
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
jakarta.annotation:jakarta.annotation-api:1.3.5
|
||||
junit:junit:4.13
|
||||
junit:junit:4.13.1
|
||||
net.bytebuddy:byte-buddy-agent:1.10.14
|
||||
net.bytebuddy:byte-buddy:1.10.14
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.apache.logging.log4j:log4j-api:2.13.3
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.37
|
||||
org.assertj:assertj-core:3.16.1
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.38
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.38
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.glassfish:jakarta.el:3.0.3
|
||||
org.hamcrest:hamcrest-core:2.2
|
||||
org.hamcrest:hamcrest:2.2
|
||||
org.mockito:mockito-core:3.5.2
|
||||
org.mockito:mockito-core:3.5.13
|
||||
org.objenesis:objenesis:3.1
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M2
|
||||
org.springframework.boot:spring-boot:2.4.0-M2
|
||||
org.springframework.security:spring-security-config:5.4.0-RC1
|
||||
org.springframework.security:spring-security-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0-RC1
|
||||
org.springframework.security:spring-security-web:5.4.0-RC1
|
||||
org.springframework:spring-aop:5.3.0-M2
|
||||
org.springframework:spring-beans:5.3.0-M2
|
||||
org.springframework:spring-context:5.3.0-M2
|
||||
org.springframework:spring-core:5.3.0-M2
|
||||
org.springframework:spring-expression:5.3.0-M2
|
||||
org.springframework:spring-jcl:5.3.0-M2
|
||||
org.springframework:spring-test:5.3.0-M2
|
||||
org.springframework:spring-web:5.3.0-M2
|
||||
org.springframework:spring-webmvc:5.3.0-M2
|
||||
org.yaml:snakeyaml:1.26
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M3
|
||||
org.springframework.boot:spring-boot:2.4.0-M3
|
||||
org.springframework.security:spring-security-config:5.4.0
|
||||
org.springframework.security:spring-security-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0
|
||||
org.springframework.security:spring-security-web:5.4.0
|
||||
org.springframework:spring-aop:5.3.0-RC1
|
||||
org.springframework:spring-beans:5.3.0-RC1
|
||||
org.springframework:spring-context:5.3.0-RC1
|
||||
org.springframework:spring-core:5.3.0-RC1
|
||||
org.springframework:spring-expression:5.3.0-RC1
|
||||
org.springframework:spring-jcl:5.3.0-RC1
|
||||
org.springframework:spring-test:5.3.0-RC1
|
||||
org.springframework:spring-web:5.3.0-RC1
|
||||
org.springframework:spring-webmvc:5.3.0-RC1
|
||||
org.yaml:snakeyaml:1.27
|
||||
|
||||
@@ -53,6 +53,7 @@ public class AuthorizationServerConfig {
|
||||
.redirectUri("http://localhost:8080/authorized")
|
||||
.scope("message.read")
|
||||
.scope("message.write")
|
||||
.clientSettings(clientSettings -> clientSettings.requireUserConsent(true))
|
||||
.build();
|
||||
return new InMemoryRegisteredClientRepository(registeredClient);
|
||||
}
|
||||
|
||||
@@ -12,67 +12,67 @@ com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.2
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:content-type:2.1
|
||||
com.nimbusds:lang-tag:1.4.4
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
com.nimbusds:oauth2-oidc-sdk:8.19
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
com.nimbusds:oauth2-oidc-sdk:8.22
|
||||
com.sun.activation:jakarta.activation:1.2.2
|
||||
com.sun.mail:jakarta.mail:1.6.5
|
||||
io.github.classgraph:classgraph:4.8.69
|
||||
io.netty:netty-buffer:4.1.51.Final
|
||||
io.netty:netty-codec-dns:4.1.51.Final
|
||||
io.netty:netty-codec-http2:4.1.51.Final
|
||||
io.netty:netty-codec-http:4.1.51.Final
|
||||
io.netty:netty-codec-socks:4.1.51.Final
|
||||
io.netty:netty-codec:4.1.51.Final
|
||||
io.netty:netty-common:4.1.51.Final
|
||||
io.netty:netty-handler-proxy:4.1.51.Final
|
||||
io.netty:netty-handler:4.1.51.Final
|
||||
io.netty:netty-resolver-dns:4.1.51.Final
|
||||
io.netty:netty-resolver:4.1.51.Final
|
||||
io.netty:netty-transport-native-epoll:4.1.51.Final
|
||||
io.netty:netty-transport-native-unix-common:4.1.51.Final
|
||||
io.netty:netty-transport:4.1.51.Final
|
||||
io.projectreactor.netty:reactor-netty-core:1.0.0-M2
|
||||
io.projectreactor.netty:reactor-netty-http:1.0.0-M2
|
||||
io.projectreactor.netty:reactor-netty:1.0.0-M2
|
||||
io.projectreactor:reactor-core:3.4.0-M2
|
||||
io.netty:netty-buffer:4.1.52.Final
|
||||
io.netty:netty-codec-dns:4.1.52.Final
|
||||
io.netty:netty-codec-http2:4.1.52.Final
|
||||
io.netty:netty-codec-http:4.1.52.Final
|
||||
io.netty:netty-codec-socks:4.1.52.Final
|
||||
io.netty:netty-codec:4.1.52.Final
|
||||
io.netty:netty-common:4.1.52.Final
|
||||
io.netty:netty-handler-proxy:4.1.52.Final
|
||||
io.netty:netty-handler:4.1.52.Final
|
||||
io.netty:netty-resolver-dns:4.1.52.Final
|
||||
io.netty:netty-resolver:4.1.52.Final
|
||||
io.netty:netty-transport-native-epoll:4.1.52.Final
|
||||
io.netty:netty-transport-native-unix-common:4.1.52.Final
|
||||
io.netty:netty-transport:4.1.52.Final
|
||||
io.projectreactor.netty:reactor-netty-core:1.0.0-RC1
|
||||
io.projectreactor.netty:reactor-netty-http:1.0.0-RC1
|
||||
io.projectreactor.netty:reactor-netty:1.0.0-RC1
|
||||
io.projectreactor:reactor-core:3.4.0-RC1
|
||||
jakarta.annotation:jakarta.annotation-api:1.3.5
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.apache.logging.log4j:log4j-api:2.13.3
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.38
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.38
|
||||
org.attoparser:attoparser:2.0.5.RELEASE
|
||||
org.glassfish:jakarta.el:3.0.3
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.reactivestreams:reactive-streams:1.0.3
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-oauth2-client:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-thymeleaf:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M2
|
||||
org.springframework.boot:spring-boot:2.4.0-M2
|
||||
org.springframework.security:spring-security-config:5.4.0-RC1
|
||||
org.springframework.security:spring-security-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-client:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0-RC1
|
||||
org.springframework.security:spring-security-web:5.4.0-RC1
|
||||
org.springframework:spring-aop:5.3.0-M2
|
||||
org.springframework:spring-beans:5.3.0-M2
|
||||
org.springframework:spring-context:5.3.0-M2
|
||||
org.springframework:spring-core:5.3.0-M2
|
||||
org.springframework:spring-expression:5.3.0-M2
|
||||
org.springframework:spring-jcl:5.3.0-M2
|
||||
org.springframework:spring-web:5.3.0-M2
|
||||
org.springframework:spring-webflux:5.3.0-M2
|
||||
org.springframework:spring-webmvc:5.3.0-M2
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-oauth2-client:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-thymeleaf:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M3
|
||||
org.springframework.boot:spring-boot:2.4.0-M3
|
||||
org.springframework.security:spring-security-config:5.4.0
|
||||
org.springframework.security:spring-security-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-client:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0
|
||||
org.springframework.security:spring-security-web:5.4.0
|
||||
org.springframework:spring-aop:5.3.0-RC1
|
||||
org.springframework:spring-beans:5.3.0-RC1
|
||||
org.springframework:spring-context:5.3.0-RC1
|
||||
org.springframework:spring-core:5.3.0-RC1
|
||||
org.springframework:spring-expression:5.3.0-RC1
|
||||
org.springframework:spring-jcl:5.3.0-RC1
|
||||
org.springframework:spring-web:5.3.0-RC1
|
||||
org.springframework:spring-webflux:5.3.0-RC1
|
||||
org.springframework:spring-webmvc:5.3.0-RC1
|
||||
org.thymeleaf.extras:thymeleaf-extras-java8time:3.0.4.RELEASE
|
||||
org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE
|
||||
org.thymeleaf:thymeleaf-spring5:3.0.11.RELEASE
|
||||
@@ -81,4 +81,4 @@ org.unbescape:unbescape:1.1.6.RELEASE
|
||||
org.webjars:bootstrap:3.4.1
|
||||
org.webjars:jquery:3.4.1
|
||||
org.webjars:webjars-locator-core:0.46
|
||||
org.yaml:snakeyaml:1.26
|
||||
org.yaml:snakeyaml:1.27
|
||||
|
||||
@@ -12,67 +12,67 @@ com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.2
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:content-type:2.1
|
||||
com.nimbusds:lang-tag:1.4.4
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
com.nimbusds:oauth2-oidc-sdk:8.19
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
com.nimbusds:oauth2-oidc-sdk:8.22
|
||||
com.sun.activation:jakarta.activation:1.2.2
|
||||
com.sun.mail:jakarta.mail:1.6.5
|
||||
io.github.classgraph:classgraph:4.8.69
|
||||
io.netty:netty-buffer:4.1.51.Final
|
||||
io.netty:netty-codec-dns:4.1.51.Final
|
||||
io.netty:netty-codec-http2:4.1.51.Final
|
||||
io.netty:netty-codec-http:4.1.51.Final
|
||||
io.netty:netty-codec-socks:4.1.51.Final
|
||||
io.netty:netty-codec:4.1.51.Final
|
||||
io.netty:netty-common:4.1.51.Final
|
||||
io.netty:netty-handler-proxy:4.1.51.Final
|
||||
io.netty:netty-handler:4.1.51.Final
|
||||
io.netty:netty-resolver-dns:4.1.51.Final
|
||||
io.netty:netty-resolver:4.1.51.Final
|
||||
io.netty:netty-transport-native-epoll:4.1.51.Final
|
||||
io.netty:netty-transport-native-unix-common:4.1.51.Final
|
||||
io.netty:netty-transport:4.1.51.Final
|
||||
io.projectreactor.netty:reactor-netty-core:1.0.0-M2
|
||||
io.projectreactor.netty:reactor-netty-http:1.0.0-M2
|
||||
io.projectreactor.netty:reactor-netty:1.0.0-M2
|
||||
io.projectreactor:reactor-core:3.4.0-M2
|
||||
io.netty:netty-buffer:4.1.52.Final
|
||||
io.netty:netty-codec-dns:4.1.52.Final
|
||||
io.netty:netty-codec-http2:4.1.52.Final
|
||||
io.netty:netty-codec-http:4.1.52.Final
|
||||
io.netty:netty-codec-socks:4.1.52.Final
|
||||
io.netty:netty-codec:4.1.52.Final
|
||||
io.netty:netty-common:4.1.52.Final
|
||||
io.netty:netty-handler-proxy:4.1.52.Final
|
||||
io.netty:netty-handler:4.1.52.Final
|
||||
io.netty:netty-resolver-dns:4.1.52.Final
|
||||
io.netty:netty-resolver:4.1.52.Final
|
||||
io.netty:netty-transport-native-epoll:4.1.52.Final
|
||||
io.netty:netty-transport-native-unix-common:4.1.52.Final
|
||||
io.netty:netty-transport:4.1.52.Final
|
||||
io.projectreactor.netty:reactor-netty-core:1.0.0-RC1
|
||||
io.projectreactor.netty:reactor-netty-http:1.0.0-RC1
|
||||
io.projectreactor.netty:reactor-netty:1.0.0-RC1
|
||||
io.projectreactor:reactor-core:3.4.0-RC1
|
||||
jakarta.annotation:jakarta.annotation-api:1.3.5
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.apache.logging.log4j:log4j-api:2.13.3
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.38
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.38
|
||||
org.attoparser:attoparser:2.0.5.RELEASE
|
||||
org.glassfish:jakarta.el:3.0.3
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.reactivestreams:reactive-streams:1.0.3
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-oauth2-client:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-thymeleaf:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M2
|
||||
org.springframework.boot:spring-boot:2.4.0-M2
|
||||
org.springframework.security:spring-security-config:5.4.0-RC1
|
||||
org.springframework.security:spring-security-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-client:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0-RC1
|
||||
org.springframework.security:spring-security-web:5.4.0-RC1
|
||||
org.springframework:spring-aop:5.3.0-M2
|
||||
org.springframework:spring-beans:5.3.0-M2
|
||||
org.springframework:spring-context:5.3.0-M2
|
||||
org.springframework:spring-core:5.3.0-M2
|
||||
org.springframework:spring-expression:5.3.0-M2
|
||||
org.springframework:spring-jcl:5.3.0-M2
|
||||
org.springframework:spring-web:5.3.0-M2
|
||||
org.springframework:spring-webflux:5.3.0-M2
|
||||
org.springframework:spring-webmvc:5.3.0-M2
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-oauth2-client:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-thymeleaf:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M3
|
||||
org.springframework.boot:spring-boot:2.4.0-M3
|
||||
org.springframework.security:spring-security-config:5.4.0
|
||||
org.springframework.security:spring-security-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-client:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0
|
||||
org.springframework.security:spring-security-web:5.4.0
|
||||
org.springframework:spring-aop:5.3.0-RC1
|
||||
org.springframework:spring-beans:5.3.0-RC1
|
||||
org.springframework:spring-context:5.3.0-RC1
|
||||
org.springframework:spring-core:5.3.0-RC1
|
||||
org.springframework:spring-expression:5.3.0-RC1
|
||||
org.springframework:spring-jcl:5.3.0-RC1
|
||||
org.springframework:spring-web:5.3.0-RC1
|
||||
org.springframework:spring-webflux:5.3.0-RC1
|
||||
org.springframework:spring-webmvc:5.3.0-RC1
|
||||
org.thymeleaf.extras:thymeleaf-extras-java8time:3.0.4.RELEASE
|
||||
org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE
|
||||
org.thymeleaf:thymeleaf-spring5:3.0.11.RELEASE
|
||||
@@ -81,4 +81,4 @@ org.unbescape:unbescape:1.1.6.RELEASE
|
||||
org.webjars:bootstrap:3.4.1
|
||||
org.webjars:jquery:3.4.1
|
||||
org.webjars:webjars-locator-core:0.46
|
||||
org.yaml:snakeyaml:1.26
|
||||
org.yaml:snakeyaml:1.27
|
||||
|
||||
@@ -12,67 +12,67 @@ com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.2
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:content-type:2.1
|
||||
com.nimbusds:lang-tag:1.4.4
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
com.nimbusds:oauth2-oidc-sdk:8.19
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
com.nimbusds:oauth2-oidc-sdk:8.22
|
||||
com.sun.activation:jakarta.activation:1.2.2
|
||||
com.sun.mail:jakarta.mail:1.6.5
|
||||
io.github.classgraph:classgraph:4.8.69
|
||||
io.netty:netty-buffer:4.1.51.Final
|
||||
io.netty:netty-codec-dns:4.1.51.Final
|
||||
io.netty:netty-codec-http2:4.1.51.Final
|
||||
io.netty:netty-codec-http:4.1.51.Final
|
||||
io.netty:netty-codec-socks:4.1.51.Final
|
||||
io.netty:netty-codec:4.1.51.Final
|
||||
io.netty:netty-common:4.1.51.Final
|
||||
io.netty:netty-handler-proxy:4.1.51.Final
|
||||
io.netty:netty-handler:4.1.51.Final
|
||||
io.netty:netty-resolver-dns:4.1.51.Final
|
||||
io.netty:netty-resolver:4.1.51.Final
|
||||
io.netty:netty-transport-native-epoll:4.1.51.Final
|
||||
io.netty:netty-transport-native-unix-common:4.1.51.Final
|
||||
io.netty:netty-transport:4.1.51.Final
|
||||
io.projectreactor.netty:reactor-netty-core:1.0.0-M2
|
||||
io.projectreactor.netty:reactor-netty-http:1.0.0-M2
|
||||
io.projectreactor.netty:reactor-netty:1.0.0-M2
|
||||
io.projectreactor:reactor-core:3.4.0-M2
|
||||
io.netty:netty-buffer:4.1.52.Final
|
||||
io.netty:netty-codec-dns:4.1.52.Final
|
||||
io.netty:netty-codec-http2:4.1.52.Final
|
||||
io.netty:netty-codec-http:4.1.52.Final
|
||||
io.netty:netty-codec-socks:4.1.52.Final
|
||||
io.netty:netty-codec:4.1.52.Final
|
||||
io.netty:netty-common:4.1.52.Final
|
||||
io.netty:netty-handler-proxy:4.1.52.Final
|
||||
io.netty:netty-handler:4.1.52.Final
|
||||
io.netty:netty-resolver-dns:4.1.52.Final
|
||||
io.netty:netty-resolver:4.1.52.Final
|
||||
io.netty:netty-transport-native-epoll:4.1.52.Final
|
||||
io.netty:netty-transport-native-unix-common:4.1.52.Final
|
||||
io.netty:netty-transport:4.1.52.Final
|
||||
io.projectreactor.netty:reactor-netty-core:1.0.0-RC1
|
||||
io.projectreactor.netty:reactor-netty-http:1.0.0-RC1
|
||||
io.projectreactor.netty:reactor-netty:1.0.0-RC1
|
||||
io.projectreactor:reactor-core:3.4.0-RC1
|
||||
jakarta.annotation:jakarta.annotation-api:1.3.5
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.apache.logging.log4j:log4j-api:2.13.3
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.38
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.38
|
||||
org.attoparser:attoparser:2.0.5.RELEASE
|
||||
org.glassfish:jakarta.el:3.0.3
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.reactivestreams:reactive-streams:1.0.3
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-oauth2-client:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-thymeleaf:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M2
|
||||
org.springframework.boot:spring-boot:2.4.0-M2
|
||||
org.springframework.security:spring-security-config:5.4.0-RC1
|
||||
org.springframework.security:spring-security-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-client:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0-RC1
|
||||
org.springframework.security:spring-security-web:5.4.0-RC1
|
||||
org.springframework:spring-aop:5.3.0-M2
|
||||
org.springframework:spring-beans:5.3.0-M2
|
||||
org.springframework:spring-context:5.3.0-M2
|
||||
org.springframework:spring-core:5.3.0-M2
|
||||
org.springframework:spring-expression:5.3.0-M2
|
||||
org.springframework:spring-jcl:5.3.0-M2
|
||||
org.springframework:spring-web:5.3.0-M2
|
||||
org.springframework:spring-webflux:5.3.0-M2
|
||||
org.springframework:spring-webmvc:5.3.0-M2
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-oauth2-client:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-thymeleaf:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M3
|
||||
org.springframework.boot:spring-boot:2.4.0-M3
|
||||
org.springframework.security:spring-security-config:5.4.0
|
||||
org.springframework.security:spring-security-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-client:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0
|
||||
org.springframework.security:spring-security-web:5.4.0
|
||||
org.springframework:spring-aop:5.3.0-RC1
|
||||
org.springframework:spring-beans:5.3.0-RC1
|
||||
org.springframework:spring-context:5.3.0-RC1
|
||||
org.springframework:spring-core:5.3.0-RC1
|
||||
org.springframework:spring-expression:5.3.0-RC1
|
||||
org.springframework:spring-jcl:5.3.0-RC1
|
||||
org.springframework:spring-web:5.3.0-RC1
|
||||
org.springframework:spring-webflux:5.3.0-RC1
|
||||
org.springframework:spring-webmvc:5.3.0-RC1
|
||||
org.thymeleaf.extras:thymeleaf-extras-java8time:3.0.4.RELEASE
|
||||
org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE
|
||||
org.thymeleaf:thymeleaf-spring5:3.0.11.RELEASE
|
||||
@@ -81,4 +81,4 @@ org.unbescape:unbescape:1.1.6.RELEASE
|
||||
org.webjars:bootstrap:3.4.1
|
||||
org.webjars:jquery:3.4.1
|
||||
org.webjars:webjars-locator-core:0.46
|
||||
org.yaml:snakeyaml:1.26
|
||||
org.yaml:snakeyaml:1.27
|
||||
|
||||
@@ -12,67 +12,67 @@ com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.2
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:content-type:2.1
|
||||
com.nimbusds:lang-tag:1.4.4
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
com.nimbusds:oauth2-oidc-sdk:8.19
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
com.nimbusds:oauth2-oidc-sdk:8.22
|
||||
com.sun.activation:jakarta.activation:1.2.2
|
||||
com.sun.mail:jakarta.mail:1.6.5
|
||||
io.github.classgraph:classgraph:4.8.69
|
||||
io.netty:netty-buffer:4.1.51.Final
|
||||
io.netty:netty-codec-dns:4.1.51.Final
|
||||
io.netty:netty-codec-http2:4.1.51.Final
|
||||
io.netty:netty-codec-http:4.1.51.Final
|
||||
io.netty:netty-codec-socks:4.1.51.Final
|
||||
io.netty:netty-codec:4.1.51.Final
|
||||
io.netty:netty-common:4.1.51.Final
|
||||
io.netty:netty-handler-proxy:4.1.51.Final
|
||||
io.netty:netty-handler:4.1.51.Final
|
||||
io.netty:netty-resolver-dns:4.1.51.Final
|
||||
io.netty:netty-resolver:4.1.51.Final
|
||||
io.netty:netty-transport-native-epoll:4.1.51.Final
|
||||
io.netty:netty-transport-native-unix-common:4.1.51.Final
|
||||
io.netty:netty-transport:4.1.51.Final
|
||||
io.projectreactor.netty:reactor-netty-core:1.0.0-M2
|
||||
io.projectreactor.netty:reactor-netty-http:1.0.0-M2
|
||||
io.projectreactor.netty:reactor-netty:1.0.0-M2
|
||||
io.projectreactor:reactor-core:3.4.0-M2
|
||||
io.netty:netty-buffer:4.1.52.Final
|
||||
io.netty:netty-codec-dns:4.1.52.Final
|
||||
io.netty:netty-codec-http2:4.1.52.Final
|
||||
io.netty:netty-codec-http:4.1.52.Final
|
||||
io.netty:netty-codec-socks:4.1.52.Final
|
||||
io.netty:netty-codec:4.1.52.Final
|
||||
io.netty:netty-common:4.1.52.Final
|
||||
io.netty:netty-handler-proxy:4.1.52.Final
|
||||
io.netty:netty-handler:4.1.52.Final
|
||||
io.netty:netty-resolver-dns:4.1.52.Final
|
||||
io.netty:netty-resolver:4.1.52.Final
|
||||
io.netty:netty-transport-native-epoll:4.1.52.Final
|
||||
io.netty:netty-transport-native-unix-common:4.1.52.Final
|
||||
io.netty:netty-transport:4.1.52.Final
|
||||
io.projectreactor.netty:reactor-netty-core:1.0.0-RC1
|
||||
io.projectreactor.netty:reactor-netty-http:1.0.0-RC1
|
||||
io.projectreactor.netty:reactor-netty:1.0.0-RC1
|
||||
io.projectreactor:reactor-core:3.4.0-RC1
|
||||
jakarta.annotation:jakarta.annotation-api:1.3.5
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.apache.logging.log4j:log4j-api:2.13.3
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.38
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.38
|
||||
org.attoparser:attoparser:2.0.5.RELEASE
|
||||
org.glassfish:jakarta.el:3.0.3
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.reactivestreams:reactive-streams:1.0.3
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-oauth2-client:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-thymeleaf:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M2
|
||||
org.springframework.boot:spring-boot:2.4.0-M2
|
||||
org.springframework.security:spring-security-config:5.4.0-RC1
|
||||
org.springframework.security:spring-security-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-client:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0-RC1
|
||||
org.springframework.security:spring-security-web:5.4.0-RC1
|
||||
org.springframework:spring-aop:5.3.0-M2
|
||||
org.springframework:spring-beans:5.3.0-M2
|
||||
org.springframework:spring-context:5.3.0-M2
|
||||
org.springframework:spring-core:5.3.0-M2
|
||||
org.springframework:spring-expression:5.3.0-M2
|
||||
org.springframework:spring-jcl:5.3.0-M2
|
||||
org.springframework:spring-web:5.3.0-M2
|
||||
org.springframework:spring-webflux:5.3.0-M2
|
||||
org.springframework:spring-webmvc:5.3.0-M2
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-oauth2-client:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-thymeleaf:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M3
|
||||
org.springframework.boot:spring-boot:2.4.0-M3
|
||||
org.springframework.security:spring-security-config:5.4.0
|
||||
org.springframework.security:spring-security-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-client:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0
|
||||
org.springframework.security:spring-security-web:5.4.0
|
||||
org.springframework:spring-aop:5.3.0-RC1
|
||||
org.springframework:spring-beans:5.3.0-RC1
|
||||
org.springframework:spring-context:5.3.0-RC1
|
||||
org.springframework:spring-core:5.3.0-RC1
|
||||
org.springframework:spring-expression:5.3.0-RC1
|
||||
org.springframework:spring-jcl:5.3.0-RC1
|
||||
org.springframework:spring-web:5.3.0-RC1
|
||||
org.springframework:spring-webflux:5.3.0-RC1
|
||||
org.springframework:spring-webmvc:5.3.0-RC1
|
||||
org.thymeleaf.extras:thymeleaf-extras-java8time:3.0.4.RELEASE
|
||||
org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE
|
||||
org.thymeleaf:thymeleaf-spring5:3.0.11.RELEASE
|
||||
@@ -81,4 +81,4 @@ org.unbescape:unbescape:1.1.6.RELEASE
|
||||
org.webjars:bootstrap:3.4.1
|
||||
org.webjars:jquery:3.4.1
|
||||
org.webjars:webjars-locator-core:0.46
|
||||
org.yaml:snakeyaml:1.26
|
||||
org.yaml:snakeyaml:1.27
|
||||
|
||||
@@ -12,67 +12,67 @@ com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.2
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:content-type:2.1
|
||||
com.nimbusds:lang-tag:1.4.4
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
com.nimbusds:oauth2-oidc-sdk:8.19
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
com.nimbusds:oauth2-oidc-sdk:8.22
|
||||
com.sun.activation:jakarta.activation:1.2.2
|
||||
com.sun.mail:jakarta.mail:1.6.5
|
||||
io.github.classgraph:classgraph:4.8.69
|
||||
io.netty:netty-buffer:4.1.51.Final
|
||||
io.netty:netty-codec-dns:4.1.51.Final
|
||||
io.netty:netty-codec-http2:4.1.51.Final
|
||||
io.netty:netty-codec-http:4.1.51.Final
|
||||
io.netty:netty-codec-socks:4.1.51.Final
|
||||
io.netty:netty-codec:4.1.51.Final
|
||||
io.netty:netty-common:4.1.51.Final
|
||||
io.netty:netty-handler-proxy:4.1.51.Final
|
||||
io.netty:netty-handler:4.1.51.Final
|
||||
io.netty:netty-resolver-dns:4.1.51.Final
|
||||
io.netty:netty-resolver:4.1.51.Final
|
||||
io.netty:netty-transport-native-epoll:4.1.51.Final
|
||||
io.netty:netty-transport-native-unix-common:4.1.51.Final
|
||||
io.netty:netty-transport:4.1.51.Final
|
||||
io.projectreactor.netty:reactor-netty-core:1.0.0-M2
|
||||
io.projectreactor.netty:reactor-netty-http:1.0.0-M2
|
||||
io.projectreactor.netty:reactor-netty:1.0.0-M2
|
||||
io.projectreactor:reactor-core:3.4.0-M2
|
||||
io.netty:netty-buffer:4.1.52.Final
|
||||
io.netty:netty-codec-dns:4.1.52.Final
|
||||
io.netty:netty-codec-http2:4.1.52.Final
|
||||
io.netty:netty-codec-http:4.1.52.Final
|
||||
io.netty:netty-codec-socks:4.1.52.Final
|
||||
io.netty:netty-codec:4.1.52.Final
|
||||
io.netty:netty-common:4.1.52.Final
|
||||
io.netty:netty-handler-proxy:4.1.52.Final
|
||||
io.netty:netty-handler:4.1.52.Final
|
||||
io.netty:netty-resolver-dns:4.1.52.Final
|
||||
io.netty:netty-resolver:4.1.52.Final
|
||||
io.netty:netty-transport-native-epoll:4.1.52.Final
|
||||
io.netty:netty-transport-native-unix-common:4.1.52.Final
|
||||
io.netty:netty-transport:4.1.52.Final
|
||||
io.projectreactor.netty:reactor-netty-core:1.0.0-RC1
|
||||
io.projectreactor.netty:reactor-netty-http:1.0.0-RC1
|
||||
io.projectreactor.netty:reactor-netty:1.0.0-RC1
|
||||
io.projectreactor:reactor-core:3.4.0-RC1
|
||||
jakarta.annotation:jakarta.annotation-api:1.3.5
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.apache.logging.log4j:log4j-api:2.13.3
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.38
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.38
|
||||
org.attoparser:attoparser:2.0.5.RELEASE
|
||||
org.glassfish:jakarta.el:3.0.3
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.reactivestreams:reactive-streams:1.0.3
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-oauth2-client:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-thymeleaf:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M2
|
||||
org.springframework.boot:spring-boot:2.4.0-M2
|
||||
org.springframework.security:spring-security-config:5.4.0-RC1
|
||||
org.springframework.security:spring-security-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-client:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0-RC1
|
||||
org.springframework.security:spring-security-web:5.4.0-RC1
|
||||
org.springframework:spring-aop:5.3.0-M2
|
||||
org.springframework:spring-beans:5.3.0-M2
|
||||
org.springframework:spring-context:5.3.0-M2
|
||||
org.springframework:spring-core:5.3.0-M2
|
||||
org.springframework:spring-expression:5.3.0-M2
|
||||
org.springframework:spring-jcl:5.3.0-M2
|
||||
org.springframework:spring-web:5.3.0-M2
|
||||
org.springframework:spring-webflux:5.3.0-M2
|
||||
org.springframework:spring-webmvc:5.3.0-M2
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-oauth2-client:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-thymeleaf:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M3
|
||||
org.springframework.boot:spring-boot:2.4.0-M3
|
||||
org.springframework.security:spring-security-config:5.4.0
|
||||
org.springframework.security:spring-security-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-client:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0
|
||||
org.springframework.security:spring-security-web:5.4.0
|
||||
org.springframework:spring-aop:5.3.0-RC1
|
||||
org.springframework:spring-beans:5.3.0-RC1
|
||||
org.springframework:spring-context:5.3.0-RC1
|
||||
org.springframework:spring-core:5.3.0-RC1
|
||||
org.springframework:spring-expression:5.3.0-RC1
|
||||
org.springframework:spring-jcl:5.3.0-RC1
|
||||
org.springframework:spring-web:5.3.0-RC1
|
||||
org.springframework:spring-webflux:5.3.0-RC1
|
||||
org.springframework:spring-webmvc:5.3.0-RC1
|
||||
org.thymeleaf.extras:thymeleaf-extras-java8time:3.0.4.RELEASE
|
||||
org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE
|
||||
org.thymeleaf:thymeleaf-spring5:3.0.11.RELEASE
|
||||
@@ -81,4 +81,4 @@ org.unbescape:unbescape:1.1.6.RELEASE
|
||||
org.webjars:bootstrap:3.4.1
|
||||
org.webjars:jquery:3.4.1
|
||||
org.webjars:webjars-locator-core:0.46
|
||||
org.yaml:snakeyaml:1.26
|
||||
org.yaml:snakeyaml:1.27
|
||||
|
||||
@@ -12,67 +12,67 @@ com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.2
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:content-type:2.1
|
||||
com.nimbusds:lang-tag:1.4.4
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
com.nimbusds:oauth2-oidc-sdk:8.19
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
com.nimbusds:oauth2-oidc-sdk:8.22
|
||||
com.sun.activation:jakarta.activation:1.2.2
|
||||
com.sun.mail:jakarta.mail:1.6.5
|
||||
io.github.classgraph:classgraph:4.8.69
|
||||
io.netty:netty-buffer:4.1.51.Final
|
||||
io.netty:netty-codec-dns:4.1.51.Final
|
||||
io.netty:netty-codec-http2:4.1.51.Final
|
||||
io.netty:netty-codec-http:4.1.51.Final
|
||||
io.netty:netty-codec-socks:4.1.51.Final
|
||||
io.netty:netty-codec:4.1.51.Final
|
||||
io.netty:netty-common:4.1.51.Final
|
||||
io.netty:netty-handler-proxy:4.1.51.Final
|
||||
io.netty:netty-handler:4.1.51.Final
|
||||
io.netty:netty-resolver-dns:4.1.51.Final
|
||||
io.netty:netty-resolver:4.1.51.Final
|
||||
io.netty:netty-transport-native-epoll:4.1.51.Final
|
||||
io.netty:netty-transport-native-unix-common:4.1.51.Final
|
||||
io.netty:netty-transport:4.1.51.Final
|
||||
io.projectreactor.netty:reactor-netty-core:1.0.0-M2
|
||||
io.projectreactor.netty:reactor-netty-http:1.0.0-M2
|
||||
io.projectreactor.netty:reactor-netty:1.0.0-M2
|
||||
io.projectreactor:reactor-core:3.4.0-M2
|
||||
io.netty:netty-buffer:4.1.52.Final
|
||||
io.netty:netty-codec-dns:4.1.52.Final
|
||||
io.netty:netty-codec-http2:4.1.52.Final
|
||||
io.netty:netty-codec-http:4.1.52.Final
|
||||
io.netty:netty-codec-socks:4.1.52.Final
|
||||
io.netty:netty-codec:4.1.52.Final
|
||||
io.netty:netty-common:4.1.52.Final
|
||||
io.netty:netty-handler-proxy:4.1.52.Final
|
||||
io.netty:netty-handler:4.1.52.Final
|
||||
io.netty:netty-resolver-dns:4.1.52.Final
|
||||
io.netty:netty-resolver:4.1.52.Final
|
||||
io.netty:netty-transport-native-epoll:4.1.52.Final
|
||||
io.netty:netty-transport-native-unix-common:4.1.52.Final
|
||||
io.netty:netty-transport:4.1.52.Final
|
||||
io.projectreactor.netty:reactor-netty-core:1.0.0-RC1
|
||||
io.projectreactor.netty:reactor-netty-http:1.0.0-RC1
|
||||
io.projectreactor.netty:reactor-netty:1.0.0-RC1
|
||||
io.projectreactor:reactor-core:3.4.0-RC1
|
||||
jakarta.annotation:jakarta.annotation-api:1.3.5
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.apache.logging.log4j:log4j-api:2.13.3
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.38
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.38
|
||||
org.attoparser:attoparser:2.0.5.RELEASE
|
||||
org.glassfish:jakarta.el:3.0.3
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.reactivestreams:reactive-streams:1.0.3
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-oauth2-client:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-thymeleaf:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M2
|
||||
org.springframework.boot:spring-boot:2.4.0-M2
|
||||
org.springframework.security:spring-security-config:5.4.0-RC1
|
||||
org.springframework.security:spring-security-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-client:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0-RC1
|
||||
org.springframework.security:spring-security-web:5.4.0-RC1
|
||||
org.springframework:spring-aop:5.3.0-M2
|
||||
org.springframework:spring-beans:5.3.0-M2
|
||||
org.springframework:spring-context:5.3.0-M2
|
||||
org.springframework:spring-core:5.3.0-M2
|
||||
org.springframework:spring-expression:5.3.0-M2
|
||||
org.springframework:spring-jcl:5.3.0-M2
|
||||
org.springframework:spring-web:5.3.0-M2
|
||||
org.springframework:spring-webflux:5.3.0-M2
|
||||
org.springframework:spring-webmvc:5.3.0-M2
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-oauth2-client:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-thymeleaf:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M3
|
||||
org.springframework.boot:spring-boot:2.4.0-M3
|
||||
org.springframework.security:spring-security-config:5.4.0
|
||||
org.springframework.security:spring-security-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-client:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0
|
||||
org.springframework.security:spring-security-web:5.4.0
|
||||
org.springframework:spring-aop:5.3.0-RC1
|
||||
org.springframework:spring-beans:5.3.0-RC1
|
||||
org.springframework:spring-context:5.3.0-RC1
|
||||
org.springframework:spring-core:5.3.0-RC1
|
||||
org.springframework:spring-expression:5.3.0-RC1
|
||||
org.springframework:spring-jcl:5.3.0-RC1
|
||||
org.springframework:spring-web:5.3.0-RC1
|
||||
org.springframework:spring-webflux:5.3.0-RC1
|
||||
org.springframework:spring-webmvc:5.3.0-RC1
|
||||
org.thymeleaf.extras:thymeleaf-extras-java8time:3.0.4.RELEASE
|
||||
org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE
|
||||
org.thymeleaf:thymeleaf-spring5:3.0.11.RELEASE
|
||||
@@ -81,4 +81,4 @@ org.unbescape:unbescape:1.1.6.RELEASE
|
||||
org.webjars:bootstrap:3.4.1
|
||||
org.webjars:jquery:3.4.1
|
||||
org.webjars:webjars-locator-core:0.46
|
||||
org.yaml:snakeyaml:1.26
|
||||
org.yaml:snakeyaml:1.27
|
||||
|
||||
@@ -12,76 +12,76 @@ com.fasterxml.jackson.module:jackson-module-parameter-names:2.11.2
|
||||
com.github.stephenc.jcip:jcip-annotations:1.0-1
|
||||
com.nimbusds:content-type:2.1
|
||||
com.nimbusds:lang-tag:1.4.4
|
||||
com.nimbusds:nimbus-jose-jwt:8.20
|
||||
com.nimbusds:oauth2-oidc-sdk:8.19
|
||||
com.nimbusds:nimbus-jose-jwt:9.0.1
|
||||
com.nimbusds:oauth2-oidc-sdk:8.22
|
||||
com.sun.activation:jakarta.activation:1.2.2
|
||||
com.sun.mail:jakarta.mail:1.6.5
|
||||
io.github.classgraph:classgraph:4.8.69
|
||||
io.netty:netty-buffer:4.1.51.Final
|
||||
io.netty:netty-codec-dns:4.1.51.Final
|
||||
io.netty:netty-codec-http2:4.1.51.Final
|
||||
io.netty:netty-codec-http:4.1.51.Final
|
||||
io.netty:netty-codec-socks:4.1.51.Final
|
||||
io.netty:netty-codec:4.1.51.Final
|
||||
io.netty:netty-common:4.1.51.Final
|
||||
io.netty:netty-handler-proxy:4.1.51.Final
|
||||
io.netty:netty-handler:4.1.51.Final
|
||||
io.netty:netty-resolver-dns:4.1.51.Final
|
||||
io.netty:netty-resolver:4.1.51.Final
|
||||
io.netty:netty-transport-native-epoll:4.1.51.Final
|
||||
io.netty:netty-transport-native-unix-common:4.1.51.Final
|
||||
io.netty:netty-transport:4.1.51.Final
|
||||
io.projectreactor.netty:reactor-netty-core:1.0.0-M2
|
||||
io.projectreactor.netty:reactor-netty-http:1.0.0-M2
|
||||
io.projectreactor.netty:reactor-netty:1.0.0-M2
|
||||
io.projectreactor:reactor-core:3.4.0-M2
|
||||
io.netty:netty-buffer:4.1.52.Final
|
||||
io.netty:netty-codec-dns:4.1.52.Final
|
||||
io.netty:netty-codec-http2:4.1.52.Final
|
||||
io.netty:netty-codec-http:4.1.52.Final
|
||||
io.netty:netty-codec-socks:4.1.52.Final
|
||||
io.netty:netty-codec:4.1.52.Final
|
||||
io.netty:netty-common:4.1.52.Final
|
||||
io.netty:netty-handler-proxy:4.1.52.Final
|
||||
io.netty:netty-handler:4.1.52.Final
|
||||
io.netty:netty-resolver-dns:4.1.52.Final
|
||||
io.netty:netty-resolver:4.1.52.Final
|
||||
io.netty:netty-transport-native-epoll:4.1.52.Final
|
||||
io.netty:netty-transport-native-unix-common:4.1.52.Final
|
||||
io.netty:netty-transport:4.1.52.Final
|
||||
io.projectreactor.netty:reactor-netty-core:1.0.0-RC1
|
||||
io.projectreactor.netty:reactor-netty-http:1.0.0-RC1
|
||||
io.projectreactor.netty:reactor-netty:1.0.0-RC1
|
||||
io.projectreactor:reactor-core:3.4.0-RC1
|
||||
jakarta.annotation:jakarta.annotation-api:1.3.5
|
||||
junit:junit:4.13
|
||||
junit:junit:4.13.1
|
||||
net.bytebuddy:byte-buddy-agent:1.10.14
|
||||
net.bytebuddy:byte-buddy:1.10.14
|
||||
net.minidev:accessors-smart:1.2
|
||||
net.minidev:json-smart:2.3
|
||||
org.apache.logging.log4j:log4j-api:2.13.3
|
||||
org.apache.logging.log4j:log4j-to-slf4j:2.13.3
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.37
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.37
|
||||
org.assertj:assertj-core:3.16.1
|
||||
org.apache.tomcat.embed:tomcat-embed-core:9.0.38
|
||||
org.apache.tomcat.embed:tomcat-embed-websocket:9.0.38
|
||||
org.assertj:assertj-core:3.17.2
|
||||
org.attoparser:attoparser:2.0.5.RELEASE
|
||||
org.glassfish:jakarta.el:3.0.3
|
||||
org.hamcrest:hamcrest-core:2.2
|
||||
org.hamcrest:hamcrest:2.2
|
||||
org.mockito:mockito-core:3.5.2
|
||||
org.mockito:mockito-core:3.5.13
|
||||
org.objenesis:objenesis:3.1
|
||||
org.ow2.asm:asm:5.0.4
|
||||
org.reactivestreams:reactive-streams:1.0.3
|
||||
org.slf4j:jul-to-slf4j:1.7.30
|
||||
org.slf4j:slf4j-api:1.7.30
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-oauth2-client:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-thymeleaf:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M2
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M2
|
||||
org.springframework.boot:spring-boot:2.4.0-M2
|
||||
org.springframework.security:spring-security-config:5.4.0-RC1
|
||||
org.springframework.security:spring-security-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-client:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0-RC1
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0-RC1
|
||||
org.springframework.security:spring-security-web:5.4.0-RC1
|
||||
org.springframework:spring-aop:5.3.0-M2
|
||||
org.springframework:spring-beans:5.3.0-M2
|
||||
org.springframework:spring-context:5.3.0-M2
|
||||
org.springframework:spring-core:5.3.0-M2
|
||||
org.springframework:spring-expression:5.3.0-M2
|
||||
org.springframework:spring-jcl:5.3.0-M2
|
||||
org.springframework:spring-test:5.3.0-M2
|
||||
org.springframework:spring-web:5.3.0-M2
|
||||
org.springframework:spring-webflux:5.3.0-M2
|
||||
org.springframework:spring-webmvc:5.3.0-M2
|
||||
org.springframework.boot:spring-boot-autoconfigure:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-json:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-logging:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-oauth2-client:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-security:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-thymeleaf:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-tomcat:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter-web:2.4.0-M3
|
||||
org.springframework.boot:spring-boot-starter:2.4.0-M3
|
||||
org.springframework.boot:spring-boot:2.4.0-M3
|
||||
org.springframework.security:spring-security-config:5.4.0
|
||||
org.springframework.security:spring-security-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-client:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-core:5.4.0
|
||||
org.springframework.security:spring-security-oauth2-jose:5.4.0
|
||||
org.springframework.security:spring-security-web:5.4.0
|
||||
org.springframework:spring-aop:5.3.0-RC1
|
||||
org.springframework:spring-beans:5.3.0-RC1
|
||||
org.springframework:spring-context:5.3.0-RC1
|
||||
org.springframework:spring-core:5.3.0-RC1
|
||||
org.springframework:spring-expression:5.3.0-RC1
|
||||
org.springframework:spring-jcl:5.3.0-RC1
|
||||
org.springframework:spring-test:5.3.0-RC1
|
||||
org.springframework:spring-web:5.3.0-RC1
|
||||
org.springframework:spring-webflux:5.3.0-RC1
|
||||
org.springframework:spring-webmvc:5.3.0-RC1
|
||||
org.thymeleaf.extras:thymeleaf-extras-java8time:3.0.4.RELEASE
|
||||
org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE
|
||||
org.thymeleaf:thymeleaf-spring5:3.0.11.RELEASE
|
||||
@@ -90,4 +90,4 @@ org.unbescape:unbescape:1.1.6.RELEASE
|
||||
org.webjars:bootstrap:3.4.1
|
||||
org.webjars:jquery:3.4.1
|
||||
org.webjars:webjars-locator-core:0.46
|
||||
org.yaml:snakeyaml:1.26
|
||||
org.yaml:snakeyaml:1.27
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user