Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e3e7d76b70 |
+10
-18
@@ -1,5 +1,8 @@
|
||||
version: 2
|
||||
registries:
|
||||
spring-milestones:
|
||||
type: maven-repository
|
||||
url: https://repo.spring.io/milestone
|
||||
shibboleth:
|
||||
type: maven-repository
|
||||
url: https://build.shibboleth.net/maven/releases
|
||||
@@ -14,6 +17,7 @@ updates:
|
||||
labels:
|
||||
- 'type: dependency-upgrade'
|
||||
registries:
|
||||
- spring-milestones
|
||||
- shibboleth
|
||||
ignore:
|
||||
- dependency-name: com.nimbusds:nimbus-jose-jwt
|
||||
@@ -30,9 +34,8 @@ updates:
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
|
||||
- package-ecosystem: gradle
|
||||
target-branch: 7.0.x
|
||||
target-branch: 6.4.x
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
@@ -41,6 +44,7 @@ updates:
|
||||
labels:
|
||||
- 'type: dependency-upgrade'
|
||||
registries:
|
||||
- spring-milestones
|
||||
- shibboleth
|
||||
ignore:
|
||||
- dependency-name: com.nimbusds:nimbus-jose-jwt
|
||||
@@ -53,10 +57,6 @@ updates:
|
||||
- dependency-name: org.mockito:mockito-bom
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- dependency-name: com.gradle.enterprise
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
- dependency-name: '*'
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
@@ -72,6 +72,7 @@ updates:
|
||||
labels:
|
||||
- 'type: dependency-upgrade'
|
||||
registries:
|
||||
- spring-milestones
|
||||
- shibboleth
|
||||
ignore:
|
||||
- dependency-name: com.nimbusds:nimbus-jose-jwt
|
||||
@@ -91,6 +92,7 @@ updates:
|
||||
- dependency-name: '*'
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- version-update:semver-minor
|
||||
|
||||
- package-ecosystem: npm
|
||||
target-branch: docs-build
|
||||
@@ -109,18 +111,8 @@ updates:
|
||||
labels:
|
||||
- 'type: task'
|
||||
- 'in: build'
|
||||
|
||||
- package-ecosystem: 7.0.x
|
||||
target-branch: main
|
||||
directory: /docs
|
||||
schedule:
|
||||
interval: weekly
|
||||
labels:
|
||||
- 'type: task'
|
||||
- 'in: build'
|
||||
|
||||
- package-ecosystem: 6.5.x
|
||||
target-branch: main
|
||||
- package-ecosystem: npm
|
||||
target-branch: 6.3.x
|
||||
directory: /docs
|
||||
schedule:
|
||||
interval: weekly
|
||||
|
||||
@@ -18,8 +18,10 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- java-version: 25
|
||||
toolchain: 25
|
||||
- java-version: 21-ea
|
||||
toolchain: 21
|
||||
- java-version: 17
|
||||
toolchain: 17
|
||||
with:
|
||||
java-version: ${{ matrix.java-version }}
|
||||
test-args: --refresh-dependencies -PforceMavenRepositories=snapshot,https://oss.sonatype.org/content/repositories/snapshots -PisOverrideVersionCatalog -PtestToolchain=${{ matrix.toolchain }} -PspringFrameworkVersion=7.+ -PreactorVersion=2025.+ -PspringDataVersion=2025.+ --stacktrace
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest ]
|
||||
jdk: [ 25 ]
|
||||
jdk: [ 17 ]
|
||||
with:
|
||||
runs-on: ${{ matrix.os }}
|
||||
java-version: ${{ matrix.jdk }}
|
||||
@@ -35,6 +35,13 @@ jobs:
|
||||
should-deploy-artifacts: ${{ needs.build.outputs.should-deploy-artifacts }}
|
||||
default-publish-milestones-central: true
|
||||
secrets: inherit
|
||||
deploy-docs:
|
||||
name: Deploy Docs
|
||||
needs: [ build ]
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-docs.yml@v1
|
||||
with:
|
||||
should-deploy-docs: ${{ needs.build.outputs.should-deploy-artifacts }}
|
||||
secrets: inherit
|
||||
deploy-schema:
|
||||
name: Deploy Schema
|
||||
needs: [ build ]
|
||||
@@ -44,7 +51,7 @@ jobs:
|
||||
secrets: inherit
|
||||
perform-release:
|
||||
name: Perform Release
|
||||
needs: [ deploy-artifacts, deploy-schema ]
|
||||
needs: [ deploy-artifacts, deploy-docs, deploy-schema ]
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/perform-release.yml@v1
|
||||
with:
|
||||
should-perform-release: ${{ needs.deploy-artifacts.outputs.artifacts-deployed }}
|
||||
|
||||
@@ -2,10 +2,6 @@ name: Finalize Release
|
||||
|
||||
on:
|
||||
workflow_dispatch: # Manual trigger
|
||||
inputs:
|
||||
version:
|
||||
description: The Spring Security release to finalize (e.g. 7.0.0-RC2)
|
||||
required: true
|
||||
|
||||
env:
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
@@ -14,14 +10,32 @@ permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
project-version:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.project-version.outputs.version }}
|
||||
steps:
|
||||
- id: project-version
|
||||
run: echo "version=$(grep '^version=' gradle.properties | cut -d'=' -f2)" >> $GITHUB_OUTPUT
|
||||
perform-release:
|
||||
name: Perform Release
|
||||
needs: [ project-version ]
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/perform-release.yml@v1
|
||||
with:
|
||||
should-perform-release: true
|
||||
project-version: ${{ inputs.version }}
|
||||
project-version: ${{ needs.project-version.outputs.version }}
|
||||
milestone-repo-url: https://repo1.maven.org/maven2
|
||||
release-repo-url: https://repo1.maven.org/maven2
|
||||
artifact-path: org/springframework/security/spring-security-core
|
||||
slack-announcing-id: spring-security-announcing
|
||||
secrets: inherit
|
||||
send-notification:
|
||||
name: Send Notification
|
||||
needs: [ perform-release ]
|
||||
if: ${{ !success() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Send Notification
|
||||
uses: spring-io/spring-security-release-tools/.github/actions/send-notification@v1
|
||||
with:
|
||||
webhook-url: ${{ secrets.SPRING_SECURITY_CI_GCHAT_WEBHOOK_URL }}
|
||||
|
||||
@@ -20,10 +20,10 @@ jobs:
|
||||
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up JDK 25
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '25'
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
- name: Set up Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v2
|
||||
with:
|
||||
java-version: '25'
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew clean build -PskipCheckExpectedBranchVersion --continue --scan
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v2
|
||||
with:
|
||||
java-version: '25'
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
- name: Run Antora
|
||||
run: ./gradlew -PbuildSrc.skipTests=true :spring-security-docs:antora
|
||||
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
# List of active maintenance branches.
|
||||
branch: [ main, 7.0.x, 6.5.x, 6.4.x, 6.3.x ]
|
||||
branch: [ main, 6.5.x, 6.4.x, 6.3.x ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
name: Update on Supported Branches
|
||||
strategy:
|
||||
matrix:
|
||||
branch: [ '6.5.x', '7.0.x', 'main' ]
|
||||
branch: [ '5.8.x', '6.2.x', '6.3.x', 'main' ]
|
||||
steps:
|
||||
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@e28269199d1d27975cf7f65e16d6095c555b3cd0
|
||||
name: Update
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
# See https://sdkman.io/usage#config
|
||||
# A summary is to add the following to ~/.sdkman/etc/config
|
||||
# sdkman_auto_env=true
|
||||
java=25-librca
|
||||
java=17.0.3-tem
|
||||
|
||||
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"java.gradle.buildServer.enabled": "off"
|
||||
"java.import.gradle.enabled": false
|
||||
}
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ interface EvaluationContextPostProcessor<I> {
|
||||
* that was passed in.
|
||||
* @param context the original {@link EvaluationContext}
|
||||
* @param invocation the security invocation object (i.e. Message)
|
||||
* @return the updated context.
|
||||
* @return the upated context.
|
||||
*/
|
||||
EvaluationContext postProcess(EvaluationContext context, I invocation);
|
||||
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ import org.springframework.security.acls.model.Acl;
|
||||
|
||||
/**
|
||||
* Strategy used by {@link AclImpl} to determine whether a principal is permitted to call
|
||||
* administrative methods on the <code>AclImpl</code>.
|
||||
* adminstrative methods on the <code>AclImpl</code>.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
|
||||
@@ -42,7 +42,7 @@ public class GrantedAuthoritySid implements Sid {
|
||||
public GrantedAuthoritySid(GrantedAuthority grantedAuthority) {
|
||||
Assert.notNull(grantedAuthority, "GrantedAuthority required");
|
||||
Assert.notNull(grantedAuthority.getAuthority(),
|
||||
"This Sid is only compatible with GrantedAuthority that provide a non-null getAuthority()");
|
||||
"This Sid is only compatible with GrantedAuthoritys that provide a non-null getAuthority()");
|
||||
this.grantedAuthority = grantedAuthority.getAuthority();
|
||||
}
|
||||
|
||||
|
||||
@@ -160,7 +160,7 @@ public class JdbcAclService implements AclService {
|
||||
this.findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL_WITH_CLASS_ID_TYPE;
|
||||
}
|
||||
else {
|
||||
log.debug("Find children statement has already been overridden, so not overriding the default");
|
||||
log.debug("Find children statement has already been overridden, so not overridding the default");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ import org.springframework.util.Assert;
|
||||
* The default settings are for HSQLDB. If you are using a different database you will
|
||||
* probably need to set the {@link #setSidIdentityQuery(String) sidIdentityQuery} and
|
||||
* {@link #setClassIdentityQuery(String) classIdentityQuery} properties appropriately. The
|
||||
* other queries, SQL inserts and updates can also be customized to accommodate schema
|
||||
* other queries, SQL inserts and updates can also be customized to accomodate schema
|
||||
* variations, but must produce results consistent with those expected by the defaults.
|
||||
* <p>
|
||||
* See the appendix of the Spring Security reference manual for more information on the
|
||||
@@ -471,7 +471,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
||||
this.insertClass = DEFAULT_INSERT_INTO_ACL_CLASS_WITH_ID;
|
||||
}
|
||||
else {
|
||||
log.debug("Insert class statement has already been overridden, so not overriding the default");
|
||||
log.debug("Insert class statement has already been overridden, so not overridding the default");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ apply plugin: 'io.spring.convention.spring-module'
|
||||
apply plugin: 'io.freefair.aspectj'
|
||||
|
||||
compileAspectj {
|
||||
sourceCompatibility = "17"
|
||||
targetCompatibility = "17"
|
||||
sourceCompatibility "17"
|
||||
targetCompatibility "17"
|
||||
}
|
||||
compileTestAspectj {
|
||||
sourceCompatibility = "17"
|
||||
targetCompatibility = "17"
|
||||
sourceCompatibility "17"
|
||||
targetCompatibility "17"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
+37
-12
@@ -1,7 +1,5 @@
|
||||
import io.spring.gradle.IncludeRepoTask
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import trang.RncToXsd
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
buildscript {
|
||||
dependencies {
|
||||
@@ -12,7 +10,7 @@ buildscript {
|
||||
classpath libs.com.netflix.nebula.nebula.project.plugin
|
||||
}
|
||||
repositories {
|
||||
maven { url='https://plugins.gradle.org/m2/' }
|
||||
maven { url 'https://plugins.gradle.org/m2/' }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,30 +35,57 @@ ext.milestoneBuild = !(snapshotBuild || releaseBuild)
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url = "https://repo.spring.io/milestone" }
|
||||
maven { url "https://repo.spring.io/milestone" }
|
||||
}
|
||||
|
||||
springRelease {
|
||||
weekOfMonth = 3
|
||||
dayOfWeek = 1
|
||||
referenceDocUrl = "https://docs.spring.io/spring-security/reference/{version}/index.html"
|
||||
apiDocUrl = "https://docs.spring.io/spring-security/reference/{version}/api/java/index.html"
|
||||
apiDocUrl = "https://docs.spring.io/spring-security/site/docs/{version}/api/"
|
||||
replaceSnapshotVersionInReferenceDocUrl = true
|
||||
}
|
||||
|
||||
def toolchainVersion() {
|
||||
if (project.hasProperty('testToolchain')) {
|
||||
return project.property('testToolchain').toString().toInteger()
|
||||
}
|
||||
return 17
|
||||
}
|
||||
|
||||
subprojects {
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(toolchainVersion())
|
||||
}
|
||||
}
|
||||
kotlin {
|
||||
jvmToolchain {
|
||||
languageVersion = JavaLanguageVersion.of(17)
|
||||
}
|
||||
}
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.encoding = "UTF-8"
|
||||
options.compilerArgs.add("-parameters")
|
||||
options.release.set(17)
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
if (!['spring-security-bom', 'spring-security-docs'].contains(project.name)) {
|
||||
apply plugin: 'io.spring.javaformat'
|
||||
apply plugin: 'checkstyle'
|
||||
|
||||
pluginManager.withPlugin("io.spring.convention.checkstyle") {
|
||||
dependencies {
|
||||
checkstyle libs.io.spring.javaformat.spring.javaformat.checkstyle
|
||||
pluginManager.withPlugin("io.spring.convention.checkstyle", { plugin ->
|
||||
configure(plugin) {
|
||||
dependencies {
|
||||
checkstyle libs.io.spring.javaformat.spring.javaformat.checkstyle
|
||||
}
|
||||
checkstyle {
|
||||
toolVersion = '8.34'
|
||||
}
|
||||
}
|
||||
checkstyle {
|
||||
toolVersion = '8.34'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (project.name.contains('sample')) {
|
||||
tasks.whenTaskAdded { task ->
|
||||
|
||||
@@ -12,7 +12,7 @@ java {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
maven { url = 'https://repo.spring.io/snapshot' }
|
||||
maven { url 'https://repo.spring.io/snapshot' }
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import org.gradle.api.tasks.compile.JavaCompile
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.compilerArgs += "-Werror"
|
||||
}
|
||||
|
||||
tasks.withType(KotlinCompile) {
|
||||
kotlinOptions.allWarningsAsErrors = true
|
||||
}
|
||||
@@ -81,8 +81,8 @@ class ArtifactoryPlugin implements Plugin<Project> {
|
||||
repository {
|
||||
repoKey = isSnapshot ? snapshotRepository : isMilestone ? milestoneRepository : releaseRepository
|
||||
if(project.hasProperty('artifactoryUsername')) {
|
||||
username = project.artifactoryUsername
|
||||
password = project.artifactoryPassword
|
||||
username = artifactoryUsername
|
||||
password = artifactoryPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2004-present 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 io.spring.gradle.convention
|
||||
|
||||
import org.gradle.api.plugins.JavaPlugin
|
||||
import org.gradle.api.tasks.bundling.Zip
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
|
||||
public class DeployDocsPlugin implements Plugin<Project> {
|
||||
|
||||
@Override
|
||||
public void apply(Project project) {
|
||||
project.getPluginManager().apply('org.hidetake.ssh')
|
||||
|
||||
project.ssh.settings {
|
||||
knownHosts = allowAnyHosts
|
||||
}
|
||||
project.remotes {
|
||||
docs {
|
||||
role 'docs'
|
||||
if (project.hasProperty('deployDocsHost')) {
|
||||
host = project.findProperty('deployDocsHost')
|
||||
} else {
|
||||
host = 'docs.af.pivotal.io'
|
||||
}
|
||||
retryCount = 5 // retry 5 times (default is 0)
|
||||
retryWaitSec = 10 // wait 10 seconds between retries (default is 0)
|
||||
user = project.findProperty('deployDocsSshUsername')
|
||||
if (project.hasProperty('deployDocsSshKeyPath')) {
|
||||
identity = project.file(project.findProperty('deployDocsSshKeyPath'))
|
||||
} else if (project.hasProperty('deployDocsSshKey')) {
|
||||
identity = project.findProperty('deployDocsSshKey')
|
||||
}
|
||||
if(project.hasProperty('deployDocsSshPassphrase')) {
|
||||
passphrase = project.findProperty('deployDocsSshPassphrase')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project.task('deployDocs') {
|
||||
dependsOn 'docsZip'
|
||||
doFirst {
|
||||
project.ssh.run {
|
||||
session(project.remotes.docs) {
|
||||
def now = System.currentTimeMillis()
|
||||
def name = project.rootProject.name
|
||||
def version = project.rootProject.version
|
||||
def tempPath = "/tmp/${name}-${now}-docs/".replaceAll(' ', '_')
|
||||
execute "mkdir -p $tempPath"
|
||||
|
||||
project.tasks.docsZip.outputs.each { o ->
|
||||
put from: o.files, into: tempPath
|
||||
}
|
||||
|
||||
execute "unzip $tempPath*.zip -d $tempPath"
|
||||
|
||||
def extractPath = "/var/www/domains/spring.io/docs/htdocs/autorepo/docs/${name}/${version}/"
|
||||
|
||||
execute "rm -rf $extractPath"
|
||||
execute "mkdir -p $extractPath"
|
||||
execute "mv $tempPath/docs/* $extractPath"
|
||||
execute "chmod -R g+w $extractPath"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ public class DocsPlugin implements Plugin<Project> {
|
||||
|
||||
PluginManager pluginManager = project.getPluginManager();
|
||||
pluginManager.apply(BasePlugin);
|
||||
pluginManager.apply(DeployDocsPlugin);
|
||||
pluginManager.apply(JavadocApiPlugin);
|
||||
|
||||
Task docsZip = project.tasks.create('docsZip', Zip) {
|
||||
@@ -31,12 +32,12 @@ public class DocsPlugin implements Plugin<Project> {
|
||||
into 'api'
|
||||
}
|
||||
into 'docs'
|
||||
duplicatesStrategy = 'exclude'
|
||||
duplicatesStrategy 'exclude'
|
||||
}
|
||||
|
||||
Task docs = project.tasks.create("docs") {
|
||||
group = 'Documentation'
|
||||
description = 'An aggregator task to generate all the documentation'
|
||||
description 'An aggregator task to generate all the documentation'
|
||||
dependsOn docsZip
|
||||
}
|
||||
project.tasks.assemble.dependsOn docs
|
||||
|
||||
@@ -90,7 +90,7 @@ public class IntegrationTestPlugin implements Plugin<Project> {
|
||||
project.plugins.withType(IdeaPlugin) {
|
||||
project.idea {
|
||||
module {
|
||||
testSources.from(project.file('src/integration-test/java'))
|
||||
testSourceDirs += project.file('src/integration-test/java')
|
||||
scopes.TEST.plus += [ project.configurations.integrationTestCompileClasspath ]
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,7 @@ public class IntegrationTestPlugin implements Plugin<Project> {
|
||||
project.plugins.withType(IdeaPlugin) {
|
||||
project.idea {
|
||||
module {
|
||||
testSources.from(project.file('src/integration-test/groovy'))
|
||||
testSourceDirs += project.file('src/integration-test/groovy')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ class JacocoPlugin implements Plugin<Project> {
|
||||
project.tasks.check.dependsOn project.tasks.jacocoTestReport
|
||||
|
||||
project.jacoco {
|
||||
toolVersion = '0.8.14'
|
||||
toolVersion = '0.8.9'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.gradle.api.Action;
|
||||
import org.gradle.api.JavaVersion
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.plugins.JavaPluginExtension;
|
||||
import org.gradle.api.plugins.JavaPluginConvention;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.javadoc.Javadoc;
|
||||
import org.slf4j.Logger;
|
||||
@@ -71,7 +71,7 @@ public class JavadocApiPlugin implements Plugin<Project> {
|
||||
}
|
||||
|
||||
api.setMaxMemory("1024m");
|
||||
api.setDestinationDir(project.layout.getBuildDirectory().dir("api").get().getAsFile());
|
||||
api.setDestinationDir(new File(project.getBuildDir(), "api"));
|
||||
|
||||
project.getPluginManager().apply("io.spring.convention.javadoc-options");
|
||||
}
|
||||
@@ -99,7 +99,7 @@ public class JavadocApiPlugin implements Plugin<Project> {
|
||||
public void execute(SpringModulePlugin plugin) {
|
||||
logger.info("Added sources for {}", project);
|
||||
|
||||
JavaPluginExtension java = project.getExtensions().getByType(JavaPluginExtension.class);
|
||||
JavaPluginConvention java = project.getConvention().getPlugin(JavaPluginConvention.class);
|
||||
SourceSet mainSourceSet = java.getSourceSets().getByName("main");
|
||||
|
||||
api.setSource(api.getSource().plus(mainSourceSet.getAllJava()));
|
||||
|
||||
@@ -40,7 +40,7 @@ public class SchemaZipPlugin implements Plugin<Project> {
|
||||
throw new IllegalStateException("Could not find schema file for resource name " + schemaResourceName + " in src/main/resources")
|
||||
}
|
||||
schemaZip.into (shortName) {
|
||||
duplicatesStrategy = 'exclude'
|
||||
duplicatesStrategy 'exclude'
|
||||
from xsdFile.path
|
||||
}
|
||||
versionlessXsd.getInputFiles().from(xsdFile.path)
|
||||
|
||||
@@ -35,7 +35,6 @@ class SpringModulePlugin extends AbstractSpringJavaPlugin {
|
||||
pluginManager.apply(SpringMavenPlugin.class);
|
||||
pluginManager.apply(CheckClasspathForProhibitedDependenciesPlugin.class);
|
||||
pluginManager.apply("io.spring.convention.jacoco");
|
||||
pluginManager.apply("java-toolchain");
|
||||
|
||||
def deployArtifacts = project.task("deployArtifacts")
|
||||
deployArtifacts.group = 'Deploy tasks'
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
def toolchainVersion() {
|
||||
if (project.hasProperty('testToolchain')) {
|
||||
return project.property('testToolchain').toString().toInteger()
|
||||
}
|
||||
return 25
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(toolchainVersion())
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.encoding = "UTF-8"
|
||||
options.compilerArgs.add("-parameters")
|
||||
options.release = 17
|
||||
}
|
||||
|
||||
pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
|
||||
kotlin {
|
||||
jvmToolchain {
|
||||
languageVersion = JavaLanguageVersion.of(toolchainVersion())
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(KotlinCompile).configureEach {
|
||||
compilerOptions {
|
||||
javaParameters = true
|
||||
jvmTarget.set(JvmTarget.JVM_17)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import org.gradle.api.tasks.javadoc.Javadoc
|
||||
|
||||
project.tasks.withType(Javadoc).configureEach {
|
||||
options.addBooleanOption('Werror', true)
|
||||
// temporarily disable missing to get build to pass with JDK 25
|
||||
options.addStringOption('Xdoclint:all,-missing')
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import org.gradle.api.tasks.compile.JavaCompile
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
/**
|
||||
* We need to compile with JDK 25 for nullability support, but using JDK 25 means that our tests will fail due to the
|
||||
* <a href="https://docs.oracle.com/en/java/javase/25/security/security-manager-is-permanently-disabled.html">removal
|
||||
* of the Java Security Manager</a>. For example, in JDK 25 {@code Subject.getSubject(AccessControlContext)} throws an
|
||||
* {@code UnsupportedOperationException}.
|
||||
*
|
||||
* To resolve this, we must migrate tests to use the new APIs (e.g. {@code Subject.current()}) but those APIs are not
|
||||
* available in the JDK 17 source, so compiling with JDK 25 and release 17 fails. The plugin overrides the test
|
||||
* compilation to use release 25.
|
||||
*
|
||||
* @see <a href="https://docs.oracle.com/en/java/javase/25/security/security-manager-is-permanently-disabled.html">The
|
||||
* Security Manager Is Permanently Disabled</a>
|
||||
* @see <a href="https://inside.java/2024/07/08/quality-heads-up/">Quality Outreach Heads-up - JDK 23: Re-Specified
|
||||
* Subject.getSubject API</a>
|
||||
*/
|
||||
|
||||
tasks.withType(JavaCompile).configureEach { task ->
|
||||
if (task.name == 'compileTestJava' || task.name == 'compileIntegrationTestJava') {
|
||||
task.options.release.set(25)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(KotlinCompile).configureEach { task ->
|
||||
if (task.name == 'compileTestKotlin' || task.name == 'compileIntegrationTestKotlin') {
|
||||
task.kotlinOptions.jvmTarget = '25'
|
||||
}
|
||||
}
|
||||
+11
-1
@@ -30,6 +30,16 @@ ossrh: {
|
||||
}
|
||||
}
|
||||
},
|
||||
docs: {
|
||||
stage('Deploy Docs') {
|
||||
node {
|
||||
checkout scm
|
||||
withCredentials([file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')]) {
|
||||
sh "./gradlew deployDocs -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --refresh-dependencies --no-daemon --stacktrace"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
schema: {
|
||||
stage('Deploy Schema') {
|
||||
node {
|
||||
@@ -39,4 +49,4 @@ schema: {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,4 @@
|
||||
/**
|
||||
* Jackson 3+ serialization support for CAS.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.security.cas.jackson;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@@ -326,7 +326,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
/**
|
||||
* Use this {@code RequestMatcher} to match proxy receptor requests. Without setting
|
||||
* this matcher, {@link CasAuthenticationFilter} will not capture any proxy receptor
|
||||
* requests.
|
||||
* requets.
|
||||
* @param proxyReceptorMatcher the {@link RequestMatcher} to use
|
||||
* @since 6.5
|
||||
*/
|
||||
@@ -383,8 +383,8 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the request is eligible to process a service ticket. This method
|
||||
* exists for readability.
|
||||
* Indicates if the request is elgible to process a service ticket. This method exists
|
||||
* for readability.
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
@@ -396,7 +396,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the request is eligible to process a proxy ticket.
|
||||
* Indicates if the request is elgible to process a proxy ticket.
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@@ -419,7 +419,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the request is eligible to be processed as the proxy receptor.
|
||||
* Indicates if the request is elgible to be processed as the proxy receptor.
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
|
||||
@@ -4,7 +4,6 @@ import trang.RncToXsd
|
||||
apply plugin: 'io.spring.convention.spring-module'
|
||||
apply plugin: 'trang'
|
||||
apply plugin: 'security-kotlin'
|
||||
apply plugin: 'test-compile-target-jdk25'
|
||||
|
||||
configurations {
|
||||
opensaml5 {
|
||||
@@ -145,14 +144,14 @@ tasks.named('processResources', ProcessResources).configure {
|
||||
into 'org/springframework/security/config/'
|
||||
}
|
||||
from(rncToXsd) {
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
duplicatesStrategy DuplicatesStrategy.EXCLUDE
|
||||
into 'org/springframework/security/config/'
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named('sourcesJar', Jar).configure {
|
||||
from(rncToXsd) {
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
duplicatesStrategy DuplicatesStrategy.EXCLUDE
|
||||
into 'org/springframework/security/config/'
|
||||
}
|
||||
}
|
||||
|
||||
+10
-97
@@ -31,7 +31,6 @@ import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebDriverException;
|
||||
@@ -56,7 +55,6 @@ import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.filter.DelegatingFilterProxy;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
@@ -69,7 +67,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*
|
||||
* @author Daniel Garnier-Moiroux
|
||||
*/
|
||||
@Disabled
|
||||
@org.junit.jupiter.api.Disabled
|
||||
class WebAuthnWebDriverTests {
|
||||
|
||||
private String baseUrl;
|
||||
@@ -84,8 +82,6 @@ class WebAuthnWebDriverTests {
|
||||
|
||||
private static final String PASSWORD = "password";
|
||||
|
||||
private String authenticatorId = null;
|
||||
|
||||
@BeforeAll
|
||||
static void startChromeDriverService() throws Exception {
|
||||
driverService = new ChromeDriverService.Builder().usingAnyFreePort().build();
|
||||
@@ -148,7 +144,7 @@ class WebAuthnWebDriverTests {
|
||||
@Test
|
||||
void loginWhenNoValidAuthenticatorCredentialsThenRejects() {
|
||||
createVirtualAuthenticator(true);
|
||||
this.getAndWait("/", "/login");
|
||||
this.driver.get(this.baseUrl);
|
||||
this.driver.findElement(signinWithPasskeyButton()).click();
|
||||
await(() -> assertThat(this.driver.getCurrentUrl()).endsWith("/login?error"));
|
||||
}
|
||||
@@ -157,7 +153,7 @@ class WebAuthnWebDriverTests {
|
||||
void registerWhenNoLabelThenRejects() {
|
||||
login();
|
||||
|
||||
this.getAndWait("/webauthn/register");
|
||||
this.driver.get(this.baseUrl + "/webauthn/register");
|
||||
|
||||
this.driver.findElement(registerPasskeyButton()).click();
|
||||
assertHasAlertStartingWith("error", "Error: Passkey Label is required");
|
||||
@@ -167,7 +163,7 @@ class WebAuthnWebDriverTests {
|
||||
void registerWhenAuthenticatorNoUserVerificationThenRejects() {
|
||||
createVirtualAuthenticator(false);
|
||||
login();
|
||||
this.getAndWait("/webauthn/register");
|
||||
this.driver.get(this.baseUrl + "/webauthn/register");
|
||||
this.driver.findElement(passkeyLabel()).sendKeys("Virtual authenticator");
|
||||
this.driver.findElement(registerPasskeyButton()).click();
|
||||
|
||||
@@ -182,8 +178,7 @@ class WebAuthnWebDriverTests {
|
||||
* <li>Step 1: Log in with username / password</li>
|
||||
* <li>Step 2: Register a credential from the virtual authenticator</li>
|
||||
* <li>Step 3: Log out</li>
|
||||
* <li>Step 4: Log in with the authenticator (no allowCredentials)</li>
|
||||
* <li>Step 5: Log in again with the same authenticator (with allowCredentials)</li>
|
||||
* <li>Step 4: Log in with the authenticator</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Test
|
||||
@@ -195,7 +190,7 @@ class WebAuthnWebDriverTests {
|
||||
login();
|
||||
|
||||
// Step 2: register a credential from the virtual authenticator
|
||||
this.getAndWait("/webauthn/register");
|
||||
this.driver.get(this.baseUrl + "/webauthn/register");
|
||||
this.driver.findElement(passkeyLabel()).sendKeys("Virtual authenticator");
|
||||
this.driver.findElement(registerPasskeyButton()).click();
|
||||
|
||||
@@ -217,58 +212,9 @@ class WebAuthnWebDriverTests {
|
||||
logout();
|
||||
|
||||
// Step 4: log in with the virtual authenticator
|
||||
this.getAndWait("/webauthn/register", "/login");
|
||||
this.driver.get(this.baseUrl + "/webauthn/register");
|
||||
this.driver.findElement(signinWithPasskeyButton()).click();
|
||||
await(() -> assertThat(this.driver.getCurrentUrl()).endsWith("/webauthn/register?continue"));
|
||||
|
||||
// Step 5: authenticate while being already logged in
|
||||
// This simulates some use-cases with MFA. Since the user is already logged in,
|
||||
// the "allowCredentials" property is populated
|
||||
this.getAndWait("/login");
|
||||
this.driver.findElement(signinWithPasskeyButton()).click();
|
||||
await(() -> assertThat(this.driver.getCurrentUrl()).endsWith("/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerWhenAuthenticatorAlreadyRegisteredThenRejects() {
|
||||
createVirtualAuthenticator(true);
|
||||
login();
|
||||
registerAuthenticator("Virtual authenticator");
|
||||
|
||||
// Cannot re-register the same authenticator because excludeCredentials
|
||||
// is not empty and contains the given authenticator
|
||||
this.driver.findElement(passkeyLabel()).sendKeys("Same authenticator");
|
||||
this.driver.findElement(registerPasskeyButton()).click();
|
||||
|
||||
await(() -> assertHasAlertStartingWith("error", "Registration failed"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerSecondAuthenticatorThenSucceeds() {
|
||||
createVirtualAuthenticator(true);
|
||||
login();
|
||||
|
||||
registerAuthenticator("Virtual authenticator");
|
||||
this.getAndWait("/webauthn/register");
|
||||
List<WebElement> passkeyRows = this.driver.findElements(passkeyTableRows());
|
||||
assertThat(passkeyRows).hasSize(1)
|
||||
.first()
|
||||
.extracting((row) -> row.findElement(firstCell()))
|
||||
.extracting(WebElement::getText)
|
||||
.isEqualTo("Virtual authenticator");
|
||||
|
||||
// Create second authenticator and register
|
||||
removeAuthenticator();
|
||||
createVirtualAuthenticator(true);
|
||||
registerAuthenticator("Second virtual authenticator");
|
||||
|
||||
this.getAndWait("/webauthn/register");
|
||||
|
||||
passkeyRows = this.driver.findElements(passkeyTableRows());
|
||||
assertThat(passkeyRows).hasSize(2)
|
||||
.extracting((row) -> row.findElement(firstCell()))
|
||||
.extracting(WebElement::getText)
|
||||
.contains("Second virtual authenticator");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,14 +231,11 @@ class WebAuthnWebDriverTests {
|
||||
* "https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn/">https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn/</a>
|
||||
*/
|
||||
private void createVirtualAuthenticator(boolean userIsVerified) {
|
||||
if (StringUtils.hasText(this.authenticatorId)) {
|
||||
throw new IllegalStateException("Authenticator already exists, please remove it before re-creating one");
|
||||
}
|
||||
HasCdp cdpDriver = (HasCdp) this.driver;
|
||||
cdpDriver.executeCdpCommand("WebAuthn.enable", Map.of("enableUI", false));
|
||||
// this.driver.addVirtualAuthenticator(createVirtualAuthenticatorOptions());
|
||||
//@formatter:off
|
||||
Map<String, Object> cmdResponse = cdpDriver.executeCdpCommand("WebAuthn.addVirtualAuthenticator",
|
||||
cdpDriver.executeCdpCommand("WebAuthn.addVirtualAuthenticator",
|
||||
Map.of(
|
||||
"options",
|
||||
Map.of(
|
||||
@@ -305,38 +248,21 @@ class WebAuthnWebDriverTests {
|
||||
)
|
||||
));
|
||||
//@formatter:on
|
||||
this.authenticatorId = cmdResponse.get("authenticatorId").toString();
|
||||
}
|
||||
|
||||
private void removeAuthenticator() {
|
||||
HasCdp cdpDriver = (HasCdp) this.driver;
|
||||
cdpDriver.executeCdpCommand("WebAuthn.removeVirtualAuthenticator",
|
||||
Map.of("authenticatorId", this.authenticatorId));
|
||||
this.authenticatorId = null;
|
||||
}
|
||||
|
||||
private void login() {
|
||||
this.getAndWait("/", "/login");
|
||||
this.driver.get(this.baseUrl);
|
||||
this.driver.findElement(usernameField()).sendKeys(USERNAME);
|
||||
this.driver.findElement(passwordField()).sendKeys(PASSWORD);
|
||||
this.driver.findElement(signinWithUsernamePasswordButton()).click();
|
||||
// Ensure login has completed
|
||||
await(() -> assertThat(this.driver.getCurrentUrl()).doesNotContain("/login"));
|
||||
}
|
||||
|
||||
private void logout() {
|
||||
this.getAndWait("/logout");
|
||||
this.driver.get(this.baseUrl + "/logout");
|
||||
this.driver.findElement(logoutButton()).click();
|
||||
await(() -> assertThat(this.driver.getCurrentUrl()).endsWith("/login?logout"));
|
||||
}
|
||||
|
||||
private void registerAuthenticator(String passkeyName) {
|
||||
this.getAndWait("/webauthn/register");
|
||||
this.driver.findElement(passkeyLabel()).sendKeys(passkeyName);
|
||||
this.driver.findElement(registerPasskeyButton()).click();
|
||||
await(() -> assertThat(this.driver.getCurrentUrl()).endsWith("/webauthn/register?success"));
|
||||
}
|
||||
|
||||
private AbstractStringAssert<?> assertHasAlertStartingWith(String alertType, String alertMessage) {
|
||||
WebElement alert = this.driver.findElement(new By.ById(alertType));
|
||||
assertThat(alert.isDisplayed())
|
||||
@@ -363,15 +289,6 @@ class WebAuthnWebDriverTests {
|
||||
});
|
||||
}
|
||||
|
||||
private void getAndWait(String endpoint) {
|
||||
this.getAndWait(endpoint, endpoint);
|
||||
}
|
||||
|
||||
private void getAndWait(String endpoint, String redirectUrl) {
|
||||
this.driver.get(this.baseUrl + endpoint);
|
||||
this.await(() -> assertThat(this.driver.getCurrentUrl()).endsWith(redirectUrl));
|
||||
}
|
||||
|
||||
private static By.ById passkeyLabel() {
|
||||
return new By.ById("label");
|
||||
}
|
||||
@@ -408,10 +325,6 @@ class WebAuthnWebDriverTests {
|
||||
return new By.ByCssSelector("button");
|
||||
}
|
||||
|
||||
private static By.ByCssSelector deletePasskeyButton() {
|
||||
return new By.ByCssSelector("table > tbody > tr > button");
|
||||
}
|
||||
|
||||
/**
|
||||
* The configuration for WebAuthN tests. It accesses the Server's current port, so we
|
||||
* can configurer WebAuthnConfigurer#allowedOrigin
|
||||
|
||||
+2
-2
@@ -94,7 +94,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
public BeanDefinition parse(Element element, ParserContext pc) {
|
||||
if (!namespaceMatchesVersion(element)) {
|
||||
pc.getReaderContext()
|
||||
.fatal("You cannot use any XSD older than spring-security-7.1.xsd. Either change to spring-security.xsd or spring-security-7.1.xsd",
|
||||
.fatal("You cannot use any XSD older than spring-security-7.0.xsd. Either change to spring-security.xsd or spring-security-7.0.xsd",
|
||||
element);
|
||||
}
|
||||
String name = pc.getDelegate().getLocalName(element);
|
||||
@@ -219,7 +219,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
|
||||
|
||||
private boolean matchesVersionInternal(Element element) {
|
||||
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
|
||||
return schemaLocation.matches("(?m).*spring-security-7\\.1.*.xsd.*")
|
||||
return schemaLocation.matches("(?m).*spring-security-7\\.0.*.xsd.*")
|
||||
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|
||||
|| !schemaLocation.matches("(?m).*spring-security.*");
|
||||
}
|
||||
|
||||
+5
-5
@@ -177,7 +177,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a shared Object. Note that object hierarchies are not considered.
|
||||
* Gets a shared Object. Note that object heirarchies are not considered.
|
||||
* @param sharedType the type of the shared Object
|
||||
* @return the shared Object or null if it is not found
|
||||
*/
|
||||
@@ -360,7 +360,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
|
||||
/**
|
||||
* Subclasses must implement this method to build the object that is being returned.
|
||||
* @return the Object to be built or null if the implementation allows it
|
||||
* @return the Object to be buit or null if the implementation allows it
|
||||
*/
|
||||
protected abstract O performBuild();
|
||||
|
||||
@@ -414,13 +414,13 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
|
||||
private enum BuildState {
|
||||
|
||||
/**
|
||||
* This is the state before the {@link SecurityBuilder#build()} is invoked
|
||||
* This is the state before the {@link Builder#build()} is invoked
|
||||
*/
|
||||
UNBUILT(0),
|
||||
|
||||
/**
|
||||
* The state from when {@link SecurityBuilder#build()} is first invoked until all
|
||||
* the {@link SecurityConfigurer#init(SecurityBuilder)} methods have been invoked.
|
||||
* The state from when {@link Builder#build()} is first invoked until all the
|
||||
* {@link SecurityConfigurer#init(SecurityBuilder)} methods have been invoked.
|
||||
*/
|
||||
INITIALIZING(1),
|
||||
|
||||
|
||||
+1
-2
@@ -42,8 +42,7 @@ final class MethodSecuritySelector implements ImportSelector {
|
||||
.isPresent("org.springframework.security.data.aot.hint.AuthorizeReturnObjectDataHintsRegistrar", null);
|
||||
|
||||
private static final boolean isWebPresent = ClassUtils
|
||||
.isPresent("org.springframework.web.servlet.DispatcherServlet", null)
|
||||
&& ClassUtils.isPresent("org.springframework.security.web.util.ThrowableAnalyzer", null);
|
||||
.isPresent("org.springframework.web.servlet.DispatcherServlet", null);
|
||||
|
||||
private static final boolean isObservabilityPresent = ClassUtils
|
||||
.isPresent("io.micrometer.observation.ObservationRegistry", null);
|
||||
|
||||
+1
-1
@@ -82,7 +82,7 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>>
|
||||
<C> void setSharedObject(Class<C> sharedType, C object);
|
||||
|
||||
/**
|
||||
* Gets a shared Object. Note that object hierarchies are not considered.
|
||||
* Gets a shared Object. Note that object heirarchies are not considered.
|
||||
* @param sharedType the type of the shared Object
|
||||
* @return the shared Object or null if it is not found
|
||||
*/
|
||||
|
||||
+1
-1
@@ -133,7 +133,7 @@ final class FilterOrderRegistration {
|
||||
/**
|
||||
* Register a {@link Filter} with its specific position. If the {@link Filter} was
|
||||
* already registered before, the position previously defined is not going to be
|
||||
* overridden
|
||||
* overriden
|
||||
* @param filter the {@link Filter} to register
|
||||
* @param position the position to associate with the {@link Filter}
|
||||
*/
|
||||
|
||||
+1
@@ -2052,6 +2052,7 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<Defaul
|
||||
* http
|
||||
* // ...
|
||||
* .webAuthn((webAuthn) -> webAuthn
|
||||
* .rpName("Spring Security Relying Party")
|
||||
* .rpId("example.com")
|
||||
* .allowedOrigins("https://example.com")
|
||||
* );
|
||||
|
||||
+1
-1
@@ -305,7 +305,7 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the logoutSuccessUrl or null if a
|
||||
* Gets the logoutSuccesUrl or null if a
|
||||
* {@link #logoutSuccessHandler(LogoutSuccessHandler)} was configured.
|
||||
* @return the logoutSuccessUrl
|
||||
*/
|
||||
|
||||
+1
-1
@@ -146,7 +146,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
|
||||
/**
|
||||
* This should not use RequestAttributeSecurityContextRepository since that is
|
||||
* stateless and session management is about state management.
|
||||
* stateless and sesison management is about state management.
|
||||
*/
|
||||
private SecurityContextRepository sessionManagementSecurityContextRepository = new HttpSessionSecurityContextRepository();
|
||||
|
||||
|
||||
+3
-5
@@ -177,7 +177,6 @@ public class WebAuthnConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
WebAuthnAuthenticationFilter webAuthnAuthnFilter = new WebAuthnAuthenticationFilter();
|
||||
webAuthnAuthnFilter.setAuthenticationManager(
|
||||
new ProviderManager(new WebAuthnAuthenticationProvider(rpOperations, userDetailsService)));
|
||||
webAuthnAuthnFilter = postProcess(webAuthnAuthnFilter);
|
||||
WebAuthnRegistrationFilter webAuthnRegistrationFilter = new WebAuthnRegistrationFilter(userCredentials,
|
||||
rpOperations);
|
||||
PublicKeyCredentialCreationOptionsFilter creationOptionsFilter = new PublicKeyCredentialCreationOptionsFilter(
|
||||
@@ -257,10 +256,9 @@ public class WebAuthnConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
PublicKeyCredentialUserEntityRepository userEntities, UserCredentialRepository userCredentials) {
|
||||
Optional<WebAuthnRelyingPartyOperations> webauthnOperationsBean = getBeanOrNull(
|
||||
WebAuthnRelyingPartyOperations.class);
|
||||
String rpName = (this.rpName != null) ? this.rpName : this.rpId;
|
||||
return webauthnOperationsBean
|
||||
.orElseGet(() -> new Webauthn4JRelyingPartyOperations(userEntities, userCredentials,
|
||||
PublicKeyCredentialRpEntity.builder().id(this.rpId).name(rpName).build(), this.allowedOrigins));
|
||||
return webauthnOperationsBean.orElseGet(() -> new Webauthn4JRelyingPartyOperations(userEntities,
|
||||
userCredentials, PublicKeyCredentialRpEntity.builder().id(this.rpId).name(this.rpName).build(),
|
||||
this.allowedOrigins));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-29
@@ -16,12 +16,10 @@
|
||||
|
||||
package org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import jakarta.servlet.Filter;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
@@ -38,12 +36,10 @@ import org.springframework.security.oauth2.server.authorization.authentication.O
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationValidator;
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationConsentAuthenticationProvider;
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationConsentAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
|
||||
import org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationEndpointFilter;
|
||||
import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2AuthorizationCodeRequestAuthenticationConverter;
|
||||
import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2AuthorizationConsentAuthenticationConverter;
|
||||
import org.springframework.security.web.access.intercept.AuthorizationFilter;
|
||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
@@ -54,7 +50,6 @@ import org.springframework.security.web.servlet.util.matcher.PathPatternRequestM
|
||||
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.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -88,8 +83,6 @@ public final class OAuth2AuthorizationEndpointConfigurer extends AbstractOAuth2C
|
||||
|
||||
private Consumer<OAuth2AuthorizationCodeRequestAuthenticationContext> authorizationCodeRequestAuthenticationValidator;
|
||||
|
||||
private Consumer<OAuth2AuthorizationCodeRequestAuthenticationContext> authorizationCodeRequestAuthenticationValidatorComposite;
|
||||
|
||||
private SessionAuthenticationStrategy sessionAuthenticationStrategy;
|
||||
|
||||
/**
|
||||
@@ -255,16 +248,8 @@ public final class OAuth2AuthorizationEndpointConfigurer extends AbstractOAuth2C
|
||||
authenticationProviders.addAll(0, this.authenticationProviders);
|
||||
}
|
||||
this.authenticationProvidersConsumer.accept(authenticationProviders);
|
||||
authenticationProviders.forEach((authenticationProvider) -> {
|
||||
httpSecurity.authenticationProvider(postProcess(authenticationProvider));
|
||||
if (authenticationProvider instanceof OAuth2AuthorizationCodeRequestAuthenticationProvider) {
|
||||
Method method = ReflectionUtils.findMethod(OAuth2AuthorizationCodeRequestAuthenticationProvider.class,
|
||||
"getAuthenticationValidatorComposite");
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
this.authorizationCodeRequestAuthenticationValidatorComposite = (Consumer<OAuth2AuthorizationCodeRequestAuthenticationContext>) ReflectionUtils
|
||||
.invokeMethod(method, authenticationProvider);
|
||||
}
|
||||
});
|
||||
authenticationProviders.forEach(
|
||||
(authenticationProvider) -> httpSecurity.authenticationProvider(postProcess(authenticationProvider)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -297,18 +282,7 @@ public final class OAuth2AuthorizationEndpointConfigurer extends AbstractOAuth2C
|
||||
if (this.sessionAuthenticationStrategy != null) {
|
||||
authorizationEndpointFilter.setSessionAuthenticationStrategy(this.sessionAuthenticationStrategy);
|
||||
}
|
||||
httpSecurity.addFilterAfter(postProcess(authorizationEndpointFilter), AuthorizationFilter.class);
|
||||
// Create and add
|
||||
// OAuth2AuthorizationEndpointFilter.OAuth2AuthorizationCodeRequestValidatingFilter
|
||||
Method method = ReflectionUtils.findMethod(OAuth2AuthorizationEndpointFilter.class,
|
||||
"createAuthorizationCodeRequestValidatingFilter", RegisteredClientRepository.class, Consumer.class);
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
RegisteredClientRepository registeredClientRepository = OAuth2ConfigurerUtils
|
||||
.getRegisteredClientRepository(httpSecurity);
|
||||
Filter authorizationCodeRequestValidatingFilter = (Filter) ReflectionUtils.invokeMethod(method,
|
||||
authorizationEndpointFilter, registeredClientRepository,
|
||||
this.authorizationCodeRequestAuthenticationValidatorComposite);
|
||||
httpSecurity.addFilterBefore(postProcess(authorizationCodeRequestValidatingFilter),
|
||||
httpSecurity.addFilterBefore(postProcess(authorizationEndpointFilter),
|
||||
AbstractPreAuthenticatedProcessingFilter.class);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -95,7 +95,7 @@ public class Saml2MetadataConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* If there is no {@code registrationId} and your
|
||||
* {@link RelyingPartyRegistrationRepository} is {code Iterable}, the metadata
|
||||
* endpoint will try and show all relying parties' metadata in a single
|
||||
* {@code <md:EntitiesDescriptor} element.
|
||||
* {@code <md:EntitiesDecriptor} element.
|
||||
*
|
||||
* <p>
|
||||
* If you need a more sophisticated lookup strategy than these, use
|
||||
|
||||
+1
-1
@@ -167,7 +167,7 @@ class ServerHttpSecurityConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies all {@code Customizer<ServerHttpSecurity>} Beans to
|
||||
* Applies all {@code Custmizer<ServerHttpSecurity>} Beans to
|
||||
* {@link ServerHttpSecurity}.
|
||||
* @param context the {@link ApplicationContext}
|
||||
* @param http the {@link ServerHttpSecurity}
|
||||
|
||||
+3
-3
@@ -538,7 +538,7 @@ final class AuthenticationConfigBuilder {
|
||||
}
|
||||
injectAuthenticationDetailsSource(x509Elt, filterBuilder);
|
||||
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
|
||||
createPreauthEntryPoint(x509Elt);
|
||||
createPrauthEntryPoint(x509Elt);
|
||||
createX509Provider();
|
||||
}
|
||||
this.x509Filter = filter;
|
||||
@@ -562,7 +562,7 @@ final class AuthenticationConfigBuilder {
|
||||
this.x509ProviderRef = new RuntimeBeanReference(this.pc.getReaderContext().registerWithGeneratedName(provider));
|
||||
}
|
||||
|
||||
private void createPreauthEntryPoint(Element source) {
|
||||
private void createPrauthEntryPoint(Element source) {
|
||||
if (this.preAuthEntryPoint == null) {
|
||||
this.preAuthEntryPoint = new RootBeanDefinition(Http403ForbiddenEntryPoint.class);
|
||||
this.preAuthEntryPoint.setSource(this.pc.extractSource(source));
|
||||
@@ -595,7 +595,7 @@ final class AuthenticationConfigBuilder {
|
||||
adsBldr.addPropertyValue("mappableRolesRetriever", mappableRolesRetriever);
|
||||
filterBuilder.addPropertyValue("authenticationDetailsSource", adsBldr.getBeanDefinition());
|
||||
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
|
||||
createPreauthEntryPoint(jeeElt);
|
||||
createPrauthEntryPoint(jeeElt);
|
||||
createJeeProvider();
|
||||
}
|
||||
this.jeeFilter = filter;
|
||||
|
||||
+3
-3
@@ -165,20 +165,20 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
|
||||
private RootBeanDefinition getRootBeanDefinition(String mode) {
|
||||
if (isUnboundIdEnabled(mode)) {
|
||||
if (isUnboundidEnabled(mode)) {
|
||||
return new RootBeanDefinition(UNBOUNDID_CONTAINER_CLASSNAME, null, null);
|
||||
}
|
||||
throw new IllegalStateException("Embedded LDAP server is not provided");
|
||||
}
|
||||
|
||||
private String resolveBeanId(String mode) {
|
||||
if (isUnboundIdEnabled(mode)) {
|
||||
if (isUnboundidEnabled(mode)) {
|
||||
return BeanIds.EMBEDDED_UNBOUNDID;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isUnboundIdEnabled(String mode) {
|
||||
private boolean isUnboundidEnabled(String mode) {
|
||||
return "unboundid".equals(mode) || unboundIdPresent;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-7.1.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-7.0.xsd=org/springframework/security/config/spring-security-7.1.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-7.0.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-7.0.xsd=org/springframework/security/config/spring-security-7.0.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-6.5.xsd=org/springframework/security/config/spring-security-6.5.xsd
|
||||
@@ -44,8 +42,7 @@ http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/spri
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.4.xsd=org/springframework/security/config/spring-security-2.0.4.xsd
|
||||
https\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-7.1.xsd
|
||||
https\://www.springframework.org/schema/security/spring-security-7.1.xsd=org/springframework/security/config/spring-security-7.1.xsd
|
||||
https\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-7.0.xsd
|
||||
https\://www.springframework.org/schema/security/spring-security-7.0.xsd=org/springframework/security/config/spring-security-7.0.xsd
|
||||
https\://www.springframework.org/schema/security/spring-security-6.5.xsd=org/springframework/security/config/spring-security-6.5.xsd
|
||||
https\://www.springframework.org/schema/security/spring-security-6.4.xsd=org/springframework/security/config/spring-security-6.4.xsd
|
||||
|
||||
-1361
File diff suppressed because it is too large
Load Diff
-3849
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -114,7 +114,7 @@ public class SecurityNamespaceHandlerTests {
|
||||
"<user-service id='us'><user name='bob' password='bobspassword' authorities='ROLE_A' /></user-service>",
|
||||
"3.0.3", null))
|
||||
.withMessageContaining(
|
||||
"You cannot use any XSD older than spring-security-7.1.xsd. Either change to spring-security.xsd or spring-security-7.1.xsd");
|
||||
"You cannot use any XSD older than spring-security-7.0.xsd. Either change to spring-security.xsd or spring-security-7.0.xsd");
|
||||
}
|
||||
|
||||
// SEC-1868
|
||||
|
||||
+1
-1
@@ -1340,7 +1340,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
static class ServletPathConfig {
|
||||
|
||||
@Bean
|
||||
PathPatternRequestMatcherBuilderFactoryBean requestMatcherBuilder() {
|
||||
PathPatternRequestMatcherBuilderFactoryBean requesMatcherBuilder() {
|
||||
PathPatternRequestMatcherBuilderFactoryBean bean = new PathPatternRequestMatcherBuilderFactoryBean();
|
||||
bean.setBasePath("/spring");
|
||||
return bean;
|
||||
|
||||
+2
-89
@@ -19,13 +19,10 @@ package org.springframework.security.config.annotation.web.configurers;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
@@ -45,7 +42,6 @@ import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.ui.DefaultResourcesFilter;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialCreationOptions;
|
||||
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialCreationOptions;
|
||||
import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationFilter;
|
||||
import org.springframework.security.web.webauthn.management.WebAuthnRelyingPartyOperations;
|
||||
import org.springframework.security.web.webauthn.registration.HttpSessionPublicKeyCredentialCreationOptionsRepository;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
@@ -56,8 +52,6 @@ import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.willAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
||||
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.content;
|
||||
@@ -94,14 +88,6 @@ public class WebAuthnConfigurerTests {
|
||||
.andExpect(content().string(containsString("body {")));
|
||||
}
|
||||
|
||||
// gh-18128
|
||||
@Test
|
||||
public void webAuthnAuthenticationFilterIsPostProcessed() throws Exception {
|
||||
this.spring.register(DefaultWebauthnConfiguration.class, PostProcessorConfiguration.class).autowire();
|
||||
PostProcessorConfiguration postProcess = this.spring.getContext().getBean(PostProcessorConfiguration.class);
|
||||
assertThat(postProcess.webauthnFilter).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webauthnWhenNoFormLoginAndDefaultRegistrationPageConfiguredThenServesJavascript() throws Exception {
|
||||
this.spring.register(NoFormLoginAndDefaultRegistrationPageConfiguration.class).autowire();
|
||||
@@ -141,42 +127,6 @@ public class WebAuthnConfigurerTests {
|
||||
.hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void webauthnWhenConfiguredDefaultsRpNameToRpId() throws Exception {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
this.spring.register(DefaultWebauthnConfiguration.class).autowire();
|
||||
String response = this.mvc
|
||||
.perform(post("/webauthn/register/options").with(csrf())
|
||||
.with(authentication(new TestingAuthenticationToken("test", "ignored", "ROLE_user"))))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andReturn()
|
||||
.getResponse()
|
||||
.getContentAsString();
|
||||
|
||||
JsonNode parsedResponse = mapper.readTree(response);
|
||||
|
||||
assertThat(parsedResponse.get("rp").get("id").asText()).isEqualTo("example.com");
|
||||
assertThat(parsedResponse.get("rp").get("name").asText()).isEqualTo("example.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
void webauthnWhenRpNameConfiguredUsesRpName() throws Exception {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
this.spring.register(CustomRpNameWebauthnConfiguration.class).autowire();
|
||||
String response = this.mvc
|
||||
.perform(post("/webauthn/register/options").with(csrf())
|
||||
.with(authentication(new TestingAuthenticationToken("test", "ignored", "ROLE_user"))))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andReturn()
|
||||
.getResponse()
|
||||
.getContentAsString();
|
||||
|
||||
JsonNode parsedResponse = mapper.readTree(response);
|
||||
|
||||
assertThat(parsedResponse.get("rp").get("id").asText()).isEqualTo("example.com");
|
||||
assertThat(parsedResponse.get("rp").get("name").asText()).isEqualTo("Test RP Name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webauthnWhenConfiguredAndFormLoginThenDoesServesJavascript() throws Exception {
|
||||
this.spring.register(FormLoginAndNoDefaultRegistrationPageConfiguration.class).autowire();
|
||||
@@ -339,26 +289,6 @@ public class WebAuthnConfigurerTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class PostProcessorConfiguration {
|
||||
|
||||
WebAuthnAuthenticationFilter webauthnFilter;
|
||||
|
||||
@Bean
|
||||
BeanPostProcessor beanPostProcessor() {
|
||||
return new BeanPostProcessor() {
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
if (bean instanceof WebAuthnAuthenticationFilter filter) {
|
||||
PostProcessorConfiguration.this.webauthnFilter = filter;
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class DefaultWebauthnConfiguration {
|
||||
@@ -374,7 +304,8 @@ public class WebAuthnConfigurerTests {
|
||||
http
|
||||
.formLogin(Customizer.withDefaults())
|
||||
.webAuthn((authn) -> authn
|
||||
.rpId("example.com")
|
||||
.rpId("spring.io")
|
||||
.rpName("spring")
|
||||
);
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
@@ -382,24 +313,6 @@ public class WebAuthnConfigurerTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class CustomRpNameWebauthnConfiguration {
|
||||
|
||||
@Bean
|
||||
UserDetailsService userDetailsService() {
|
||||
return new InMemoryUserDetailsManager();
|
||||
}
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
return http.formLogin(Customizer.withDefaults())
|
||||
.webAuthn((webauthn) -> webauthn.rpId("example.com").rpName("Test RP Name"))
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class NoFormLoginAndDefaultRegistrationPageConfiguration {
|
||||
|
||||
+6
-15
@@ -307,8 +307,8 @@ public class OAuth2AuthorizationCodeGrantTests {
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
|
||||
this.mvc
|
||||
.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI)
|
||||
.queryParams(getAuthorizationRequestParameters(registeredClient)))
|
||||
.perform(
|
||||
get(DEFAULT_AUTHORIZATION_ENDPOINT_URI).params(getAuthorizationRequestParameters(registeredClient)))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andReturn();
|
||||
}
|
||||
@@ -851,31 +851,21 @@ public class OAuth2AuthorizationCodeGrantTests {
|
||||
this.spring.register(AuthorizationServerConfigurationCustomAuthorizationEndpoint.class).autowire();
|
||||
|
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||
this.registeredClientRepository.save(registeredClient);
|
||||
|
||||
TestingAuthenticationToken principal = new TestingAuthenticationToken("principalName", "password");
|
||||
Map<String, Object> additionalParameters = new HashMap<>();
|
||||
additionalParameters.put(PkceParameterNames.CODE_CHALLENGE, S256_CODE_CHALLENGE);
|
||||
additionalParameters.put(PkceParameterNames.CODE_CHALLENGE_METHOD, "S256");
|
||||
OAuth2AuthorizationCodeRequestAuthenticationToken authorizationCodeRequestAuthentication = new OAuth2AuthorizationCodeRequestAuthenticationToken(
|
||||
"https://provider.com/oauth2/authorize", registeredClient.getClientId(), principal,
|
||||
registeredClient.getRedirectUris().iterator().next(), STATE_URL_UNENCODED, registeredClient.getScopes(),
|
||||
additionalParameters);
|
||||
OAuth2AuthorizationCode authorizationCode = new OAuth2AuthorizationCode("code", Instant.now(),
|
||||
Instant.now().plus(5, ChronoUnit.MINUTES));
|
||||
OAuth2AuthorizationCodeRequestAuthenticationToken authorizationCodeRequestAuthenticationResult = new OAuth2AuthorizationCodeRequestAuthenticationToken(
|
||||
"https://provider.com/oauth2/authorize", registeredClient.getClientId(), principal, authorizationCode,
|
||||
registeredClient.getRedirectUris().iterator().next(), STATE_URL_UNENCODED,
|
||||
registeredClient.getScopes());
|
||||
given(authorizationRequestConverter.convert(any())).willReturn(authorizationCodeRequestAuthentication);
|
||||
given(authorizationRequestConverter.convert(any())).willReturn(authorizationCodeRequestAuthenticationResult);
|
||||
given(authorizationRequestAuthenticationProvider
|
||||
.supports(eq(OAuth2AuthorizationCodeRequestAuthenticationToken.class))).willReturn(true);
|
||||
given(authorizationRequestAuthenticationProvider.authenticate(any()))
|
||||
.willReturn(authorizationCodeRequestAuthenticationResult);
|
||||
|
||||
this.mvc
|
||||
.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI)
|
||||
.queryParams(getAuthorizationRequestParameters(registeredClient))
|
||||
.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI).params(getAuthorizationRequestParameters(registeredClient))
|
||||
.with(user("user")))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
@@ -890,7 +880,8 @@ public class OAuth2AuthorizationCodeGrantTests {
|
||||
|| converter instanceof OAuth2AuthorizationCodeRequestAuthenticationConverter
|
||||
|| converter instanceof OAuth2AuthorizationConsentAuthenticationConverter);
|
||||
|
||||
verify(authorizationRequestAuthenticationProvider).authenticate(eq(authorizationCodeRequestAuthentication));
|
||||
verify(authorizationRequestAuthenticationProvider)
|
||||
.authenticate(eq(authorizationCodeRequestAuthenticationResult));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ArgumentCaptor<List<AuthenticationProvider>> authenticationProvidersCaptor = ArgumentCaptor
|
||||
|
||||
+3
-3
@@ -65,7 +65,7 @@ public class XsdDocumentedTests {
|
||||
|
||||
String schema31xDocumentLocation = "org/springframework/security/config/spring-security-3.1.xsd";
|
||||
|
||||
String schemaDocumentLocation = "org/springframework/security/config/spring-security-7.1.xsd";
|
||||
String schemaDocumentLocation = "org/springframework/security/config/spring-security-7.0.xsd";
|
||||
|
||||
XmlSupport xml = new XmlSupport();
|
||||
|
||||
@@ -151,8 +151,8 @@ public class XsdDocumentedTests {
|
||||
.list((dir, name) -> name.endsWith(".xsd"));
|
||||
// @formatter:on
|
||||
assertThat(schemas.length)
|
||||
.withFailMessage("the count is equal to 29, if not then schemaDocument needs updating")
|
||||
.isEqualTo(29);
|
||||
.withFailMessage("the count is equal to 28, if not then schemaDocument needs updating")
|
||||
.isEqualTo(28);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-1
@@ -19,6 +19,7 @@ package org.springframework.security.config.http;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.security.AccessController;
|
||||
import java.security.Principal;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
@@ -988,7 +989,7 @@ public class MiscHttpConfigTests {
|
||||
|
||||
@GetMapping("/username")
|
||||
String username() {
|
||||
Subject subject = Subject.current();
|
||||
Subject subject = Subject.getSubject(AccessController.getContext());
|
||||
return subject.getPrincipals().iterator().next().getName();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -275,7 +275,7 @@ class ServerJwtDslTests {
|
||||
}
|
||||
|
||||
class NullConverter: Converter<Jwt, Mono<AbstractAuthenticationToken>> {
|
||||
override fun convert(source: Jwt): Mono<AbstractAuthenticationToken> {
|
||||
override fun convert(source: Jwt): Mono<AbstractAuthenticationToken>? {
|
||||
return Mono.empty()
|
||||
}
|
||||
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user