Compare commits
161 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3d9cd31122 | |||
| 04f530bc1b | |||
| bf619fc3dc | |||
| 488de5af70 | |||
| 709d9bc039 | |||
| 067ed2bab4 | |||
| 1db6718f69 | |||
| 41fc383974 | |||
| d9bb16e913 | |||
| 11114919ec | |||
| 05116eabbd | |||
| adb303e152 | |||
| f2f9d8282a | |||
| 806a0474f4 | |||
| 46f0dc6dfc | |||
| dc2e1af2da | |||
| 4993fa863a | |||
| 36ea1b11a7 | |||
| e793a962c5 | |||
| 5416c6ad29 | |||
| 805720caa6 | |||
| f87b92fbfb | |||
| 4ae0965b1c | |||
| 46cd94b5f4 | |||
| 696147c62b | |||
| fbd97ab0ea | |||
| 1e952c91e5 | |||
| 15ec379e8c | |||
| acd2de4553 | |||
| f796508456 | |||
| d556be49a8 | |||
| 31f593cca2 | |||
| 954101ab0c | |||
| d7f5fd9908 | |||
| 64bdcecdcd | |||
| 34f5f86d51 | |||
| bc0fd60e1a | |||
| 7a96437d86 | |||
| 6865c984b5 | |||
| 2bd3cadde8 | |||
| bfce6e438d | |||
| 71e12bb42e | |||
| d607364b50 | |||
| a0cfb2777c | |||
| 4c33c62485 | |||
| 18c597fa92 | |||
| e8206b42d2 | |||
| db1595f822 | |||
| cc2cfc62b0 | |||
| 3456a8eb17 | |||
| 0737957f94 | |||
| e7431a3a72 | |||
| 77892d571f | |||
| d2f825bc74 | |||
| 6fcbc0ea2a | |||
| efe50dd0eb | |||
| 06026684e5 | |||
| 946812691e | |||
| b5a4218a0b | |||
| 9e1a573531 | |||
| 309daf565d | |||
| c3d45ae529 | |||
| 4c06d98df1 | |||
| 8e752fc70e | |||
| 0ce72d0a90 | |||
| acf19c1f1f | |||
| b3c880cc24 | |||
| 879b44f9a1 | |||
| 17ca1de7cb | |||
| 33d96d574f | |||
| 62c7ff3bf0 | |||
| b64d5af9c4 | |||
| 5a30d984a0 | |||
| 8ebd893d01 | |||
| 3e496c0260 | |||
| 4776446b14 | |||
| b4c7795699 | |||
| 876f67715f | |||
| 007d7da42a | |||
| 002dbf355a | |||
| 47fd6befde | |||
| e31f04bebc | |||
| 5ff87128b1 | |||
| bcc4b415b3 | |||
| eb4befa28e | |||
| ca3c763c04 | |||
| 291fae89a9 | |||
| 7d5414b349 | |||
| fbebd03c08 | |||
| 2de2e3803a | |||
| 28615e7f64 | |||
| 47fc2bff95 | |||
| 43a2fbf5ad | |||
| f4d2b61405 | |||
| d6b295ba2c | |||
| e1e5970a24 | |||
| 36716d12ba | |||
| 3e4ba737e7 | |||
| d7921daa13 | |||
| d043884e32 | |||
| e557c7227b | |||
| 751b5580a1 | |||
| d97e01d1de | |||
| 211fa52649 | |||
| bb8e757c4b | |||
| 028c212be4 | |||
| 1cbe6ac932 | |||
| 3209930cca | |||
| 42a49bbd78 | |||
| 331812df16 | |||
| 46aa65de59 | |||
| 7f410ce5b4 | |||
| bbe4f87641 | |||
| 45da5c94b6 | |||
| 5bf42bb7a8 | |||
| 60dbeba985 | |||
| b4befb4263 | |||
| a3f6825f9c | |||
| ce38162c86 | |||
| 2e5c5fffc4 | |||
| ea0ec9e662 | |||
| 244fd2eb51 | |||
| 8e59fa1719 | |||
| 8735368d9e | |||
| feea103050 | |||
| 6f379aa907 | |||
| ca2c617946 | |||
| 5075869418 | |||
| b9b29edbeb | |||
| decf4def95 | |||
| 882766e54f | |||
| d457e0b59d | |||
| 2e9e5d0555 | |||
| 5fa960d18a | |||
| 2edc7b1f5f | |||
| 92161aae2e | |||
| beab697a88 | |||
| 292ae2c03d | |||
| 3ffda83ba1 | |||
| d44923f64e | |||
| 811d95ca76 | |||
| 431a60d7f2 | |||
| e63b031b9b | |||
| b7b650c519 | |||
| 15faf0f621 | |||
| 05076db53a | |||
| a9f8a23e50 | |||
| 643a3f1206 | |||
| 7aafe2ed5a | |||
| 4bc3693669 | |||
| e188552ccb | |||
| 6e7c62c3b9 | |||
| ce90b85945 | |||
| 27c2a8ad11 | |||
| 841c03fe3b | |||
| bf6a2fab01 | |||
| 64964ca5be | |||
| ac0ca0cafc | |||
| 87888d42fc | |||
| 85ca9e9a57 | |||
| e528923878 |
@@ -64,39 +64,23 @@ jobs:
|
||||
./gradlew publishMavenJavaPublicationToLocalRepository
|
||||
./gradlew cloneRepository -PrepositoryName="spring-projects/spring-security-samples" -Pref="$samples_branch" -PcloneOutputDirectory="$SAMPLES_DIR"
|
||||
./gradlew --refresh-dependencies --project-dir "$SAMPLES_DIR" --init-script spring-security-ci.gradle -PlocalRepositoryPath="$LOCAL_REPOSITORY_PATH" -PspringSecurityVersion="$version" test integrationTest
|
||||
check-tangles:
|
||||
name: Check for Package Tangles
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository_owner == 'spring-projects' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up gradle
|
||||
uses: spring-io/spring-gradle-build-action@v2
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
- name: Check for package tangles
|
||||
env:
|
||||
STRUCTURE101_LICENSEID: ${{ secrets.STRUCTURE101_LICENSEID }}
|
||||
run: |
|
||||
./gradlew check s101 -Ps101.licenseId="$STRUCTURE101_LICENSEID" --stacktrace
|
||||
deploy-artifacts:
|
||||
name: Deploy Artifacts
|
||||
needs: [ build, test, check-samples, check-tangles ]
|
||||
needs: [ build, test, check-samples ]
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-artifacts.yml@v1
|
||||
with:
|
||||
should-deploy-artifacts: ${{ needs.build.outputs.should-deploy-artifacts }}
|
||||
secrets: inherit
|
||||
deploy-docs:
|
||||
name: Deploy Docs
|
||||
needs: [ build, test, check-samples, check-tangles ]
|
||||
needs: [ build, test, check-samples ]
|
||||
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, test, check-samples, check-tangles ]
|
||||
needs: [ build, test, check-samples ]
|
||||
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@v1
|
||||
with:
|
||||
should-deploy-schema: ${{ needs.build.outputs.should-deploy-artifacts }}
|
||||
@@ -116,7 +100,7 @@ jobs:
|
||||
send-notification:
|
||||
name: Send Notification
|
||||
needs: [ perform-release ]
|
||||
if: ${{ failure() || cancelled() }}
|
||||
if: ${{ !success() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Send Notification
|
||||
|
||||
@@ -20,4 +20,5 @@ dependencies {
|
||||
testImplementation "org.springframework:spring-test"
|
||||
|
||||
testRuntimeOnly 'org.hsqldb:hsqldb'
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ dependencies {
|
||||
testImplementation "org.mockito:mockito-junit-jupiter"
|
||||
testImplementation "org.springframework:spring-test"
|
||||
testAspect sourceSets.main.output
|
||||
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
}
|
||||
|
||||
compileAspectj.ajcOptions.outxmlfile = "META-INF/aop.xml"
|
||||
|
||||
+4
-6
@@ -20,7 +20,6 @@ plugins {
|
||||
|
||||
apply plugin: 'io.spring.nohttp'
|
||||
apply plugin: 'locks'
|
||||
apply plugin: 's101'
|
||||
apply plugin: 'io.spring.convention.root'
|
||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||
apply plugin: 'org.springframework.security.versions.verify-dependencies-versions'
|
||||
@@ -110,6 +109,10 @@ nohttp {
|
||||
source.builtBy(project(':spring-security-config').tasks.withType(RncToXsd))
|
||||
}
|
||||
|
||||
tasks.named('checkstyleNohttp') {
|
||||
maxHeapSize = '1g'
|
||||
}
|
||||
|
||||
tasks.register('cloneRepository', IncludeRepoTask) {
|
||||
repository = project.getProperties().get("repositoryName")
|
||||
ref = project.getProperties().get("ref")
|
||||
@@ -117,11 +120,6 @@ tasks.register('cloneRepository', IncludeRepoTask) {
|
||||
outputDirectory = project.hasProperty("cloneOutputDirectory") ? project.file("$cloneOutputDirectory") : defaultDirectory
|
||||
}
|
||||
|
||||
s101 {
|
||||
repository = 'https://structure101.com/binaries/latest'
|
||||
configurationDirectory = project.file("etc/s101")
|
||||
}
|
||||
|
||||
wrapperUpgrade {
|
||||
gradle {
|
||||
'spring-security' {
|
||||
|
||||
@@ -95,6 +95,8 @@ dependencies {
|
||||
testImplementation 'org.mockito:mockito-core'
|
||||
testImplementation 'org.mockito:mockito-junit-jupiter'
|
||||
testImplementation libs.com.squareup.okhttp3.mockwebserver
|
||||
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ public class S101Plugin implements Plugin<Project> {
|
||||
|
||||
private void configure(JavaExec exec) {
|
||||
exec.setDescription("Runs Structure101 headless analysis, installing and configuring if necessary");
|
||||
exec.dependsOn("check");
|
||||
exec.dependsOn("assemble");
|
||||
Project project = exec.getProject();
|
||||
S101PluginExtension extension = project.getExtensions().getByType(S101PluginExtension.class);
|
||||
exec
|
||||
|
||||
@@ -6,5 +6,7 @@ dependencies {
|
||||
implementation 'org.springframework:spring-core'
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-engine"
|
||||
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
}
|
||||
|
||||
|
||||
@@ -5,4 +5,6 @@ dependencies {
|
||||
optional 'ch.qos.logback:logback-classic'
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-engine"
|
||||
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
}
|
||||
|
||||
@@ -22,4 +22,6 @@ dependencies {
|
||||
testImplementation "org.mockito:mockito-junit-jupiter"
|
||||
testImplementation "org.springframework:spring-test"
|
||||
testImplementation 'org.skyscreamer:jsonassert'
|
||||
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||
* @since 4.2
|
||||
* @see org.springframework.security.jackson2.SecurityJackson2Modules
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CasJackson2Module extends SimpleModule {
|
||||
|
||||
public CasJackson2Module() {
|
||||
|
||||
@@ -126,6 +126,7 @@ dependencies {
|
||||
testImplementation libs.org.eclipse.jetty.jetty.servlet
|
||||
|
||||
testRuntimeOnly 'org.hsqldb:hsqldb'
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
}
|
||||
|
||||
def rncToXsd = tasks.named('rncToXsd', RncToXsd)
|
||||
|
||||
+6
-2
@@ -33,6 +33,7 @@ import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebDriverException;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.chrome.ChromeDriverService;
|
||||
import org.openqa.selenium.chrome.ChromeOptions;
|
||||
@@ -66,6 +67,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*
|
||||
* @author Daniel Garnier-Moiroux
|
||||
*/
|
||||
@org.junit.jupiter.api.Disabled
|
||||
class WebAuthnWebDriverTests {
|
||||
|
||||
private String baseUrl;
|
||||
@@ -273,12 +275,14 @@ class WebAuthnWebDriverTests {
|
||||
|
||||
/**
|
||||
* Await until the assertion passes. If the assertion fails, it will display the
|
||||
* assertion error in stdout.
|
||||
* assertion error in stdout. WebDriver-related exceptions are ignored, so that
|
||||
* {@code assertion}s can interact with the page and be retried on error, e.g.
|
||||
* {@code assertThat(this.driver.findElement(By.Id("some-id")).isNotNull()}.
|
||||
*/
|
||||
private void await(Supplier<AbstractAssert<?, ?>> assertion) {
|
||||
new FluentWait<>(this.driver).withTimeout(Duration.ofSeconds(2))
|
||||
.pollingEvery(Duration.ofMillis(100))
|
||||
.ignoring(AssertionError.class)
|
||||
.ignoring(AssertionError.class, WebDriverException.class)
|
||||
.until((d) -> {
|
||||
assertion.get();
|
||||
return true;
|
||||
|
||||
+22
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 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.
|
||||
@@ -99,6 +99,10 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
|
||||
private AuthorizationCodeGrantConfigurer authorizationCodeGrantConfigurer = new AuthorizationCodeGrantConfigurer();
|
||||
|
||||
private ClientRegistrationRepository clientRegistrationRepository;
|
||||
|
||||
private OAuth2AuthorizedClientRepository authorizedClientRepository;
|
||||
|
||||
/**
|
||||
* Sets the repository of client registrations.
|
||||
* @param clientRegistrationRepository the repository of client registrations
|
||||
@@ -108,6 +112,7 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
ClientRegistrationRepository clientRegistrationRepository) {
|
||||
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
|
||||
this.getBuilder().setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository);
|
||||
this.clientRegistrationRepository = clientRegistrationRepository;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -120,6 +125,7 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
OAuth2AuthorizedClientRepository authorizedClientRepository) {
|
||||
Assert.notNull(authorizedClientRepository, "authorizedClientRepository cannot be null");
|
||||
this.getBuilder().setSharedObject(OAuth2AuthorizedClientRepository.class, authorizedClientRepository);
|
||||
this.authorizedClientRepository = authorizedClientRepository;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -284,8 +290,7 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
if (this.authorizationRequestResolver != null) {
|
||||
return this.authorizationRequestResolver;
|
||||
}
|
||||
ClientRegistrationRepository clientRegistrationRepository = OAuth2ClientConfigurerUtils
|
||||
.getClientRegistrationRepository(getBuilder());
|
||||
ClientRegistrationRepository clientRegistrationRepository = getClientRegistrationRepository(getBuilder());
|
||||
ResolvableType resolvableType = ResolvableType.forClass(OAuth2AuthorizationRequestResolver.class);
|
||||
OAuth2AuthorizationRequestResolver bean = getBeanOrNull(resolvableType);
|
||||
return (bean != null) ? bean : new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository,
|
||||
@@ -295,8 +300,8 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
private OAuth2AuthorizationCodeGrantFilter createAuthorizationCodeGrantFilter(B builder) {
|
||||
AuthenticationManager authenticationManager = builder.getSharedObject(AuthenticationManager.class);
|
||||
OAuth2AuthorizationCodeGrantFilter authorizationCodeGrantFilter = new OAuth2AuthorizationCodeGrantFilter(
|
||||
OAuth2ClientConfigurerUtils.getClientRegistrationRepository(builder),
|
||||
OAuth2ClientConfigurerUtils.getAuthorizedClientRepository(builder), authenticationManager);
|
||||
getClientRegistrationRepository(builder), getAuthorizedClientRepository(builder),
|
||||
authenticationManager);
|
||||
if (this.authorizationRequestRepository != null) {
|
||||
authorizationCodeGrantFilter.setAuthorizationRequestRepository(this.authorizationRequestRepository);
|
||||
}
|
||||
@@ -318,6 +323,18 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
return (bean != null) ? bean : new DefaultAuthorizationCodeTokenResponseClient();
|
||||
}
|
||||
|
||||
private ClientRegistrationRepository getClientRegistrationRepository(B builder) {
|
||||
return (OAuth2ClientConfigurer.this.clientRegistrationRepository != null)
|
||||
? OAuth2ClientConfigurer.this.clientRegistrationRepository
|
||||
: OAuth2ClientConfigurerUtils.getClientRegistrationRepository(builder);
|
||||
}
|
||||
|
||||
private OAuth2AuthorizedClientRepository getAuthorizedClientRepository(B builder) {
|
||||
return (OAuth2ClientConfigurer.this.authorizedClientRepository != null)
|
||||
? OAuth2ClientConfigurer.this.authorizedClientRepository
|
||||
: OAuth2ClientConfigurerUtils.getAuthorizedClientRepository(builder);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T getBeanOrNull(ResolvableType type) {
|
||||
ApplicationContext context = getBuilder().getSharedObject(ApplicationContext.class);
|
||||
|
||||
+20
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 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.
|
||||
@@ -173,6 +173,10 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
|
||||
private String loginProcessingUrl = OAuth2LoginAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI;
|
||||
|
||||
private ClientRegistrationRepository clientRegistrationRepository;
|
||||
|
||||
private OAuth2AuthorizedClientRepository authorizedClientRepository;
|
||||
|
||||
/**
|
||||
* Sets the repository of client registrations.
|
||||
* @param clientRegistrationRepository the repository of client registrations
|
||||
@@ -182,6 +186,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
ClientRegistrationRepository clientRegistrationRepository) {
|
||||
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
|
||||
this.getBuilder().setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository);
|
||||
this.clientRegistrationRepository = clientRegistrationRepository;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -195,6 +200,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
OAuth2AuthorizedClientRepository authorizedClientRepository) {
|
||||
Assert.notNull(authorizedClientRepository, "authorizedClientRepository cannot be null");
|
||||
this.getBuilder().setSharedObject(OAuth2AuthorizedClientRepository.class, authorizedClientRepository);
|
||||
this.authorizedClientRepository = authorizedClientRepository;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -340,8 +346,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
@Override
|
||||
public void init(B http) throws Exception {
|
||||
OAuth2LoginAuthenticationFilter authenticationFilter = new OAuth2LoginAuthenticationFilter(
|
||||
OAuth2ClientConfigurerUtils.getClientRegistrationRepository(this.getBuilder()),
|
||||
OAuth2ClientConfigurerUtils.getAuthorizedClientRepository(this.getBuilder()), this.loginProcessingUrl);
|
||||
this.getClientRegistrationRepository(), this.getAuthorizedClientRepository(), this.loginProcessingUrl);
|
||||
authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||
this.setAuthenticationFilter(authenticationFilter);
|
||||
super.loginProcessingUrl(this.loginProcessingUrl);
|
||||
@@ -407,8 +412,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
authorizationRequestBaseUri = OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI;
|
||||
}
|
||||
authorizationRequestFilter = new OAuth2AuthorizationRequestRedirectFilter(
|
||||
OAuth2ClientConfigurerUtils.getClientRegistrationRepository(this.getBuilder()),
|
||||
authorizationRequestBaseUri);
|
||||
this.getClientRegistrationRepository(), authorizationRequestBaseUri);
|
||||
}
|
||||
if (this.authorizationEndpointConfig.authorizationRequestRepository != null) {
|
||||
authorizationRequestFilter
|
||||
@@ -440,6 +444,16 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
return new AntPathRequestMatcher(loginProcessingUrl);
|
||||
}
|
||||
|
||||
private ClientRegistrationRepository getClientRegistrationRepository() {
|
||||
return (this.clientRegistrationRepository != null) ? this.clientRegistrationRepository
|
||||
: OAuth2ClientConfigurerUtils.getClientRegistrationRepository(this.getBuilder());
|
||||
}
|
||||
|
||||
private OAuth2AuthorizedClientRepository getAuthorizedClientRepository() {
|
||||
return (this.authorizedClientRepository != null) ? this.authorizedClientRepository
|
||||
: OAuth2ClientConfigurerUtils.getAuthorizedClientRepository(this.getBuilder());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private JwtDecoderFactory<ClientRegistration> getJwtDecoderFactoryBean() {
|
||||
ResolvableType type = ResolvableType.forClassWithGenerics(JwtDecoderFactory.class, ClientRegistration.class);
|
||||
@@ -526,8 +540,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, String> getLoginLinks() {
|
||||
Iterable<ClientRegistration> clientRegistrations = null;
|
||||
ClientRegistrationRepository clientRegistrationRepository = OAuth2ClientConfigurerUtils
|
||||
.getClientRegistrationRepository(this.getBuilder());
|
||||
ClientRegistrationRepository clientRegistrationRepository = this.getClientRegistrationRepository();
|
||||
ResolvableType type = ResolvableType.forInstance(clientRegistrationRepository).as(Iterable.class);
|
||||
if (type != ResolvableType.NONE && ClientRegistration.class.isAssignableFrom(type.resolveGenerics()[0])) {
|
||||
clientRegistrations = (Iterable<ClientRegistration>) clientRegistrationRepository;
|
||||
|
||||
+1
@@ -146,6 +146,7 @@ final class Saml2LogoutBeanDefinitionParser implements BeanDefinitionParser {
|
||||
BeanMetadataElement saml2LogoutRequestSuccessHandler = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(Saml2RelyingPartyInitiatedLogoutSuccessHandler.class)
|
||||
.addConstructorArgValue(logoutRequestResolver)
|
||||
.addPropertyValue("logoutRequestRepository", logoutRequestRepository)
|
||||
.getBeanDefinition();
|
||||
this.logoutFilter = BeanDefinitionBuilder.rootBeanDefinition(LogoutFilter.class)
|
||||
.addConstructorArgValue(saml2LogoutRequestSuccessHandler)
|
||||
|
||||
+9
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2025 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.
|
||||
@@ -24,20 +24,24 @@ import org.springframework.security.config.annotation.web.configurers.WebAuthnCo
|
||||
* @property rpName the relying party name
|
||||
* @property rpId the relying party id
|
||||
* @property the allowed origins
|
||||
* @property disableDefaultRegistrationPage disable default webauthn registration page
|
||||
* @since 6.4
|
||||
* @author Rob Winch
|
||||
* @author Max Batischev
|
||||
*/
|
||||
@SecurityMarker
|
||||
class WebAuthnDsl {
|
||||
var rpName: String? = null
|
||||
var rpId: String? = null
|
||||
var allowedOrigins: Set<String>? = null
|
||||
var disableDefaultRegistrationPage: Boolean? = false
|
||||
|
||||
internal fun get(): (WebAuthnConfigurer<HttpSecurity>) -> Unit {
|
||||
return { webAuthn -> webAuthn
|
||||
.rpId(rpId)
|
||||
.rpName(rpName)
|
||||
.allowedOrigins(allowedOrigins);
|
||||
return { webAuthn ->
|
||||
rpName?.also { webAuthn.rpName(rpName) }
|
||||
rpId?.also { webAuthn.rpId(rpId) }
|
||||
allowedOrigins?.also { webAuthn.allowedOrigins(allowedOrigins) }
|
||||
disableDefaultRegistrationPage?.also { webAuthn.disableDefaultRegistrationPage(disableDefaultRegistrationPage!!) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+358
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,18 +32,21 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import org.apereo.cas.client.validation.AssertionImpl;
|
||||
import org.instancio.Instancio;
|
||||
import org.instancio.InstancioApi;
|
||||
import org.instancio.InstancioOfClassApi;
|
||||
import org.instancio.Select;
|
||||
import org.instancio.generator.Generator;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
@@ -53,26 +56,72 @@ import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.type.filter.AssignableTypeFilter;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpSession;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.AuthorizationServiceException;
|
||||
import org.springframework.security.access.SecurityConfig;
|
||||
import org.springframework.security.access.intercept.RunAsUserToken;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.authentication.AccountExpiredException;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.CredentialsExpiredException;
|
||||
import org.springframework.security.authentication.DisabledException;
|
||||
import org.springframework.security.authentication.InsufficientAuthenticationException;
|
||||
import org.springframework.security.authentication.InternalAuthenticationServiceException;
|
||||
import org.springframework.security.authentication.LockedException;
|
||||
import org.springframework.security.authentication.ProviderNotFoundException;
|
||||
import org.springframework.security.authentication.RememberMeAuthenticationToken;
|
||||
import org.springframework.security.authentication.TestAuthentication;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
|
||||
import org.springframework.security.authentication.event.AuthenticationFailureCredentialsExpiredEvent;
|
||||
import org.springframework.security.authentication.event.AuthenticationFailureDisabledEvent;
|
||||
import org.springframework.security.authentication.event.AuthenticationFailureExpiredEvent;
|
||||
import org.springframework.security.authentication.event.AuthenticationFailureLockedEvent;
|
||||
import org.springframework.security.authentication.event.AuthenticationFailureProviderNotFoundEvent;
|
||||
import org.springframework.security.authentication.event.AuthenticationFailureProxyUntrustedEvent;
|
||||
import org.springframework.security.authentication.event.AuthenticationFailureServiceExceptionEvent;
|
||||
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
|
||||
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
|
||||
import org.springframework.security.authentication.event.LogoutSuccessEvent;
|
||||
import org.springframework.security.authentication.jaas.JaasAuthenticationToken;
|
||||
import org.springframework.security.authentication.jaas.event.JaasAuthenticationFailedEvent;
|
||||
import org.springframework.security.authentication.jaas.event.JaasAuthenticationSuccessEvent;
|
||||
import org.springframework.security.authentication.ott.InvalidOneTimeTokenException;
|
||||
import org.springframework.security.authentication.ott.OneTimeTokenAuthenticationToken;
|
||||
import org.springframework.security.authentication.password.CompromisedPasswordException;
|
||||
import org.springframework.security.authorization.AuthorityAuthorizationDecision;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.AuthorizationDeniedException;
|
||||
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
|
||||
import org.springframework.security.cas.authentication.CasAuthenticationToken;
|
||||
import org.springframework.security.cas.authentication.CasServiceTicketAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextImpl;
|
||||
import org.springframework.security.core.context.TransientSecurityContext;
|
||||
import org.springframework.security.core.session.AbstractSessionEvent;
|
||||
import org.springframework.security.core.session.ReactiveSessionInformation;
|
||||
import org.springframework.security.core.session.SessionInformation;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.ldap.ppolicy.PasswordPolicyControl;
|
||||
import org.springframework.security.ldap.ppolicy.PasswordPolicyErrorStatus;
|
||||
import org.springframework.security.ldap.ppolicy.PasswordPolicyException;
|
||||
import org.springframework.security.ldap.ppolicy.PasswordPolicyResponseControl;
|
||||
import org.springframework.security.ldap.userdetails.LdapAuthority;
|
||||
import org.springframework.security.oauth2.client.ClientAuthorizationException;
|
||||
import org.springframework.security.oauth2.client.ClientAuthorizationRequiredException;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
|
||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken;
|
||||
@@ -88,7 +137,10 @@ import org.springframework.security.oauth2.client.registration.TestClientRegistr
|
||||
import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2DeviceCode;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2UserCode;
|
||||
import org.springframework.security.oauth2.core.TestOAuth2AccessTokens;
|
||||
@@ -108,23 +160,86 @@ import org.springframework.security.oauth2.core.oidc.user.TestOidcUsers;
|
||||
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
|
||||
import org.springframework.security.oauth2.core.user.TestOAuth2Users;
|
||||
import org.springframework.security.oauth2.jwt.BadJwtException;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoderInitializationException;
|
||||
import org.springframework.security.oauth2.jwt.JwtEncodingException;
|
||||
import org.springframework.security.oauth2.jwt.JwtException;
|
||||
import org.springframework.security.oauth2.jwt.JwtValidationException;
|
||||
import org.springframework.security.oauth2.jwt.TestJwts;
|
||||
import org.springframework.security.oauth2.server.resource.BearerTokenError;
|
||||
import org.springframework.security.oauth2.server.resource.BearerTokenErrors;
|
||||
import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.BadOpaqueTokenException;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionAuthenticatedPrincipal;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException;
|
||||
import org.springframework.security.saml2.Saml2Exception;
|
||||
import org.springframework.security.saml2.core.Saml2Error;
|
||||
import org.springframework.security.saml2.core.Saml2X509Credential;
|
||||
import org.springframework.security.saml2.credentials.TestSaml2X509Credentials;
|
||||
import org.springframework.security.saml2.provider.service.authentication.DefaultSaml2AuthenticatedPrincipal;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest;
|
||||
import org.springframework.security.saml2.provider.service.authentication.TestSaml2AuthenticationTokens;
|
||||
import org.springframework.security.saml2.provider.service.authentication.TestSaml2Authentications;
|
||||
import org.springframework.security.saml2.provider.service.authentication.TestSaml2PostAuthenticationRequests;
|
||||
import org.springframework.security.saml2.provider.service.authentication.TestSaml2RedirectAuthenticationRequests;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails;
|
||||
import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations;
|
||||
import org.springframework.security.web.PortResolverImpl;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetails;
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException;
|
||||
import org.springframework.security.web.authentication.rememberme.CookieTheftException;
|
||||
import org.springframework.security.web.authentication.rememberme.InvalidCookieException;
|
||||
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException;
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationException;
|
||||
import org.springframework.security.web.authentication.session.SessionFixationProtectionEvent;
|
||||
import org.springframework.security.web.authentication.switchuser.AuthenticationSwitchUserEvent;
|
||||
import org.springframework.security.web.authentication.www.NonceExpiredException;
|
||||
import org.springframework.security.web.csrf.CsrfException;
|
||||
import org.springframework.security.web.csrf.DefaultCsrfToken;
|
||||
import org.springframework.security.web.csrf.InvalidCsrfTokenException;
|
||||
import org.springframework.security.web.csrf.MissingCsrfTokenException;
|
||||
import org.springframework.security.web.firewall.RequestRejectedException;
|
||||
import org.springframework.security.web.savedrequest.DefaultSavedRequest;
|
||||
import org.springframework.security.web.savedrequest.SimpleSavedRequest;
|
||||
import org.springframework.security.web.server.firewall.ServerExchangeRejectedException;
|
||||
import org.springframework.security.web.session.HttpSessionCreatedEvent;
|
||||
import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientInputs;
|
||||
import org.springframework.security.web.webauthn.api.AuthenticationExtensionsClientOutputs;
|
||||
import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse;
|
||||
import org.springframework.security.web.webauthn.api.AuthenticatorAttachment;
|
||||
import org.springframework.security.web.webauthn.api.AuthenticatorTransport;
|
||||
import org.springframework.security.web.webauthn.api.Bytes;
|
||||
import org.springframework.security.web.webauthn.api.CredProtectAuthenticationExtensionsClientInput;
|
||||
import org.springframework.security.web.webauthn.api.CredentialPropertiesOutput;
|
||||
import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInput;
|
||||
import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientInputs;
|
||||
import org.springframework.security.web.webauthn.api.ImmutableAuthenticationExtensionsClientOutputs;
|
||||
import org.springframework.security.web.webauthn.api.ImmutablePublicKeyCredentialUserEntity;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredential;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialDescriptor;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialType;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialUserEntity;
|
||||
import org.springframework.security.web.webauthn.api.TestAuthenticationAssertionResponses;
|
||||
import org.springframework.security.web.webauthn.api.TestBytes;
|
||||
import org.springframework.security.web.webauthn.api.TestPublicKeyCredential;
|
||||
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialRequestOptions;
|
||||
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialUserEntity;
|
||||
import org.springframework.security.web.webauthn.api.UserVerificationRequirement;
|
||||
import org.springframework.security.web.webauthn.authentication.WebAuthnAuthentication;
|
||||
import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationRequestToken;
|
||||
import org.springframework.security.web.webauthn.management.RelyingPartyAuthenticationRequest;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
@@ -155,6 +270,8 @@ class SpringSecurityCoreVersionSerializableTests {
|
||||
|
||||
static {
|
||||
UserDetails user = TestAuthentication.user();
|
||||
Authentication authentication = TestAuthentication.authenticated(user);
|
||||
SecurityContext securityContext = new SecurityContextImpl(authentication);
|
||||
|
||||
// oauth2-core
|
||||
generatorByClassName.put(DefaultOAuth2User.class, (r) -> TestOAuth2Users.create());
|
||||
@@ -180,6 +297,12 @@ class SpringSecurityCoreVersionSerializableTests {
|
||||
generatorByClassName.put(OidcUserAuthority.class,
|
||||
(r) -> new OidcUserAuthority(TestOidcIdTokens.idToken().build(),
|
||||
new OidcUserInfo(Map.of("claim", "value")), "claim"));
|
||||
generatorByClassName.put(OAuth2AuthenticationException.class,
|
||||
(r) -> new OAuth2AuthenticationException(new OAuth2Error("error", "description", "uri"), "message",
|
||||
new RuntimeException()));
|
||||
generatorByClassName.put(OAuth2AuthorizationException.class,
|
||||
(r) -> new OAuth2AuthorizationException(new OAuth2Error("error", "description", "uri"), "message",
|
||||
new RuntimeException()));
|
||||
|
||||
// oauth2-client
|
||||
ClientRegistration.Builder clientRegistrationBuilder = TestClientRegistrations.clientRegistration();
|
||||
@@ -218,6 +341,21 @@ class SpringSecurityCoreVersionSerializableTests {
|
||||
return new DefaultOAuth2AuthenticatedPrincipal(principal.getName(), principal.getAttributes(),
|
||||
(Collection<GrantedAuthority>) principal.getAuthorities());
|
||||
});
|
||||
generatorByClassName.put(ClientAuthorizationException.class,
|
||||
(r) -> new ClientAuthorizationException(new OAuth2Error("error", "description", "uri"), "id", "message",
|
||||
new RuntimeException()));
|
||||
generatorByClassName.put(ClientAuthorizationRequiredException.class,
|
||||
(r) -> new ClientAuthorizationRequiredException("id"));
|
||||
|
||||
// oauth2-jose
|
||||
generatorByClassName.put(BadJwtException.class, (r) -> new BadJwtException("token", new RuntimeException()));
|
||||
generatorByClassName.put(JwtDecoderInitializationException.class,
|
||||
(r) -> new JwtDecoderInitializationException("message", new RuntimeException()));
|
||||
generatorByClassName.put(JwtEncodingException.class,
|
||||
(r) -> new JwtEncodingException("message", new RuntimeException()));
|
||||
generatorByClassName.put(JwtException.class, (r) -> new JwtException("message", new RuntimeException()));
|
||||
generatorByClassName.put(JwtValidationException.class,
|
||||
(r) -> new JwtValidationException("message", List.of(new OAuth2Error("error", "description", "uri"))));
|
||||
|
||||
// oauth2-jwt
|
||||
generatorByClassName.put(Jwt.class, (r) -> TestJwts.user());
|
||||
@@ -249,6 +387,12 @@ class SpringSecurityCoreVersionSerializableTests {
|
||||
generatorByClassName.put(BearerTokenError.class, (r) -> BearerTokenErrors.invalidToken("invalid token"));
|
||||
generatorByClassName.put(OAuth2IntrospectionAuthenticatedPrincipal.class,
|
||||
(r) -> TestOAuth2AuthenticatedPrincipals.active());
|
||||
generatorByClassName.put(InvalidBearerTokenException.class,
|
||||
(r) -> new InvalidBearerTokenException("description", new RuntimeException()));
|
||||
generatorByClassName.put(BadOpaqueTokenException.class,
|
||||
(r) -> new BadOpaqueTokenException("message", new RuntimeException()));
|
||||
generatorByClassName.put(OAuth2IntrospectionException.class,
|
||||
(r) -> new OAuth2IntrospectionException("message", new RuntimeException()));
|
||||
|
||||
// core
|
||||
generatorByClassName.put(RunAsUserToken.class, (r) -> {
|
||||
@@ -274,9 +418,73 @@ class SpringSecurityCoreVersionSerializableTests {
|
||||
});
|
||||
generatorByClassName.put(OneTimeTokenAuthenticationToken.class,
|
||||
(r) -> applyDetails(new OneTimeTokenAuthenticationToken("username", "token")));
|
||||
|
||||
generatorByClassName.put(AccessDeniedException.class,
|
||||
(r) -> new AccessDeniedException("access denied", new RuntimeException()));
|
||||
generatorByClassName.put(AuthorizationServiceException.class,
|
||||
(r) -> new AuthorizationServiceException("access denied", new RuntimeException()));
|
||||
generatorByClassName.put(AccountExpiredException.class,
|
||||
(r) -> new AccountExpiredException("error", new RuntimeException()));
|
||||
generatorByClassName.put(AuthenticationCredentialsNotFoundException.class,
|
||||
(r) -> new AuthenticationCredentialsNotFoundException("error", new RuntimeException()));
|
||||
generatorByClassName.put(AuthenticationServiceException.class,
|
||||
(r) -> new AuthenticationServiceException("error", new RuntimeException()));
|
||||
generatorByClassName.put(BadCredentialsException.class,
|
||||
(r) -> new BadCredentialsException("error", new RuntimeException()));
|
||||
generatorByClassName.put(CredentialsExpiredException.class,
|
||||
(r) -> new CredentialsExpiredException("error", new RuntimeException()));
|
||||
generatorByClassName.put(DisabledException.class,
|
||||
(r) -> new DisabledException("error", new RuntimeException()));
|
||||
generatorByClassName.put(InsufficientAuthenticationException.class,
|
||||
(r) -> new InsufficientAuthenticationException("error", new RuntimeException()));
|
||||
generatorByClassName.put(InternalAuthenticationServiceException.class,
|
||||
(r) -> new InternalAuthenticationServiceException("error", new RuntimeException()));
|
||||
generatorByClassName.put(LockedException.class, (r) -> new LockedException("error", new RuntimeException()));
|
||||
generatorByClassName.put(ProviderNotFoundException.class, (r) -> new ProviderNotFoundException("error"));
|
||||
generatorByClassName.put(InvalidOneTimeTokenException.class, (r) -> new InvalidOneTimeTokenException("error"));
|
||||
generatorByClassName.put(CompromisedPasswordException.class,
|
||||
(r) -> new CompromisedPasswordException("error", new RuntimeException()));
|
||||
generatorByClassName.put(UsernameNotFoundException.class,
|
||||
(r) -> new UsernameNotFoundException("error", new RuntimeException()));
|
||||
generatorByClassName.put(TestingAuthenticationToken.class,
|
||||
(r) -> applyDetails(new TestingAuthenticationToken("username", "password")));
|
||||
generatorByClassName.put(AuthenticationFailureBadCredentialsEvent.class,
|
||||
(r) -> new AuthenticationFailureBadCredentialsEvent(authentication,
|
||||
new BadCredentialsException("message")));
|
||||
generatorByClassName.put(AuthenticationFailureCredentialsExpiredEvent.class,
|
||||
(r) -> new AuthenticationFailureCredentialsExpiredEvent(authentication,
|
||||
new CredentialsExpiredException("message")));
|
||||
generatorByClassName.put(AuthenticationFailureDisabledEvent.class,
|
||||
(r) -> new AuthenticationFailureDisabledEvent(authentication, new DisabledException("message")));
|
||||
generatorByClassName.put(AuthenticationFailureExpiredEvent.class,
|
||||
(r) -> new AuthenticationFailureExpiredEvent(authentication, new AccountExpiredException("message")));
|
||||
generatorByClassName.put(AuthenticationFailureLockedEvent.class,
|
||||
(r) -> new AuthenticationFailureLockedEvent(authentication, new LockedException("message")));
|
||||
generatorByClassName.put(AuthenticationFailureProviderNotFoundEvent.class,
|
||||
(r) -> new AuthenticationFailureProviderNotFoundEvent(authentication,
|
||||
new ProviderNotFoundException("message")));
|
||||
generatorByClassName.put(AuthenticationFailureProxyUntrustedEvent.class,
|
||||
(r) -> new AuthenticationFailureProxyUntrustedEvent(authentication,
|
||||
new AuthenticationServiceException("message")));
|
||||
generatorByClassName.put(AuthenticationFailureServiceExceptionEvent.class,
|
||||
(r) -> new AuthenticationFailureServiceExceptionEvent(authentication,
|
||||
new AuthenticationServiceException("message")));
|
||||
generatorByClassName.put(AuthenticationSuccessEvent.class,
|
||||
(r) -> new AuthenticationSuccessEvent(authentication));
|
||||
generatorByClassName.put(InteractiveAuthenticationSuccessEvent.class,
|
||||
(r) -> new InteractiveAuthenticationSuccessEvent(authentication, Authentication.class));
|
||||
generatorByClassName.put(LogoutSuccessEvent.class, (r) -> new LogoutSuccessEvent(authentication));
|
||||
generatorByClassName.put(JaasAuthenticationFailedEvent.class,
|
||||
(r) -> new JaasAuthenticationFailedEvent(authentication, new RuntimeException("message")));
|
||||
generatorByClassName.put(JaasAuthenticationSuccessEvent.class,
|
||||
(r) -> new JaasAuthenticationSuccessEvent(authentication));
|
||||
generatorByClassName.put(AbstractSessionEvent.class, (r) -> new AbstractSessionEvent(securityContext));
|
||||
generatorByClassName.put(SecurityConfig.class, (r) -> new SecurityConfig("value"));
|
||||
generatorByClassName.put(TransientSecurityContext.class, (r) -> new TransientSecurityContext(authentication));
|
||||
generatorByClassName.put(AuthorizationDeniedException.class,
|
||||
(r) -> new AuthorizationDeniedException("message", new AuthorizationDecision(false)));
|
||||
generatorByClassName.put(AuthorizationDecision.class, (r) -> new AuthorizationDecision(true));
|
||||
generatorByClassName.put(AuthorityAuthorizationDecision.class,
|
||||
(r) -> new AuthorityAuthorizationDecision(true, AuthorityUtils.createAuthorityList("ROLE_USER")));
|
||||
|
||||
// cas
|
||||
generatorByClassName.put(CasServiceTicketAuthenticationToken.class, (r) -> {
|
||||
@@ -299,8 +507,19 @@ class SpringSecurityCoreVersionSerializableTests {
|
||||
// ldap
|
||||
generatorByClassName.put(LdapAuthority.class,
|
||||
(r) -> new LdapAuthority("USER", "username", Map.of("attribute", List.of("value1", "value2"))));
|
||||
generatorByClassName.put(PasswordPolicyException.class,
|
||||
(r) -> new PasswordPolicyException(PasswordPolicyErrorStatus.INSUFFICIENT_PASSWORD_QUALITY));
|
||||
generatorByClassName.put(PasswordPolicyControl.class, (r) -> new PasswordPolicyControl(true));
|
||||
generatorByClassName.put(PasswordPolicyResponseControl.class, (r) -> {
|
||||
byte[] encodedResponse = { 0x30, 0x05, (byte) 0xA0, 0x03, (byte) 0xA0, 0x1, 0x21 };
|
||||
return new PasswordPolicyResponseControl(encodedResponse);
|
||||
});
|
||||
|
||||
// saml2-service-provider
|
||||
generatorByClassName.put(Saml2AuthenticationException.class,
|
||||
(r) -> new Saml2AuthenticationException(new Saml2Error("code", "descirption"), "message",
|
||||
new IOException("fail")));
|
||||
generatorByClassName.put(Saml2Exception.class, (r) -> new Saml2Exception("message", new IOException("fail")));
|
||||
generatorByClassName.put(DefaultSaml2AuthenticatedPrincipal.class,
|
||||
(r) -> TestSaml2Authentications.authentication().getPrincipal());
|
||||
generatorByClassName.put(Saml2Authentication.class,
|
||||
@@ -309,6 +528,16 @@ class SpringSecurityCoreVersionSerializableTests {
|
||||
(r) -> TestSaml2PostAuthenticationRequests.create());
|
||||
generatorByClassName.put(Saml2RedirectAuthenticationRequest.class,
|
||||
(r) -> TestSaml2RedirectAuthenticationRequests.create());
|
||||
generatorByClassName.put(Saml2X509Credential.class,
|
||||
(r) -> TestSaml2X509Credentials.relyingPartyVerifyingCredential());
|
||||
generatorByClassName.put(AssertingPartyDetails.class,
|
||||
(r) -> TestRelyingPartyRegistrations.full().build().getAssertingPartyMetadata());
|
||||
generatorByClassName.put(RelyingPartyRegistration.class, (r) -> TestRelyingPartyRegistrations.full().build());
|
||||
generatorByClassName.put(Saml2AuthenticationToken.class, (r) -> {
|
||||
Saml2AuthenticationToken token = TestSaml2AuthenticationTokens.tokenRequested();
|
||||
token.setDetails(details);
|
||||
return token;
|
||||
});
|
||||
|
||||
// web
|
||||
generatorByClassName.put(AnonymousAuthenticationToken.class, (r) -> {
|
||||
@@ -321,6 +550,119 @@ class SpringSecurityCoreVersionSerializableTests {
|
||||
token.setDetails(details);
|
||||
return token;
|
||||
});
|
||||
generatorByClassName.put(PreAuthenticatedCredentialsNotFoundException.class,
|
||||
(r) -> new PreAuthenticatedCredentialsNotFoundException("message", new IOException("fail")));
|
||||
generatorByClassName.put(CookieTheftException.class, (r) -> new CookieTheftException("message"));
|
||||
generatorByClassName.put(InvalidCookieException.class, (r) -> new InvalidCookieException("message"));
|
||||
generatorByClassName.put(RememberMeAuthenticationException.class,
|
||||
(r) -> new RememberMeAuthenticationException("message", new IOException("fail")));
|
||||
generatorByClassName.put(SessionAuthenticationException.class,
|
||||
(r) -> new SessionAuthenticationException("message"));
|
||||
generatorByClassName.put(NonceExpiredException.class,
|
||||
(r) -> new NonceExpiredException("message", new IOException("fail")));
|
||||
generatorByClassName.put(CsrfException.class, (r) -> new CsrfException("message"));
|
||||
generatorByClassName.put(org.springframework.security.web.server.csrf.CsrfException.class,
|
||||
(r) -> new org.springframework.security.web.server.csrf.CsrfException("message"));
|
||||
generatorByClassName.put(InvalidCsrfTokenException.class,
|
||||
(r) -> new InvalidCsrfTokenException(new DefaultCsrfToken("header", "parameter", "token"), "token"));
|
||||
generatorByClassName.put(MissingCsrfTokenException.class, (r) -> new MissingCsrfTokenException("token"));
|
||||
generatorByClassName.put(DefaultCsrfToken.class, (r) -> new DefaultCsrfToken("header", "parameter", "token"));
|
||||
generatorByClassName.put(org.springframework.security.web.server.csrf.DefaultCsrfToken.class,
|
||||
(r) -> new org.springframework.security.web.server.csrf.DefaultCsrfToken("header", "parameter",
|
||||
"token"));
|
||||
generatorByClassName.put(RequestRejectedException.class, (r) -> new RequestRejectedException("message"));
|
||||
generatorByClassName.put(ServerExchangeRejectedException.class,
|
||||
(r) -> new ServerExchangeRejectedException("message"));
|
||||
generatorByClassName.put(SessionFixationProtectionEvent.class,
|
||||
(r) -> new SessionFixationProtectionEvent(authentication, "old", "new"));
|
||||
generatorByClassName.put(AuthenticationSwitchUserEvent.class,
|
||||
(r) -> new AuthenticationSwitchUserEvent(authentication, user));
|
||||
generatorByClassName.put(HttpSessionCreatedEvent.class,
|
||||
(r) -> new HttpSessionCreatedEvent(new MockHttpSession()));
|
||||
generatorByClassName.put(SimpleSavedRequest.class, (r) -> {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/uri");
|
||||
request.setQueryString("query=string");
|
||||
request.setScheme("https");
|
||||
request.setServerName("localhost");
|
||||
request.setServerPort(80);
|
||||
request.setRequestURI("/uri");
|
||||
request.setCookies(new Cookie("name", "value"));
|
||||
request.addHeader("header", "value");
|
||||
request.addParameter("parameter", "value");
|
||||
request.setPathInfo("/path");
|
||||
request.addPreferredLocale(Locale.ENGLISH);
|
||||
return new SimpleSavedRequest(new DefaultSavedRequest(request, new PortResolverImpl(), "continue"));
|
||||
});
|
||||
|
||||
// webauthn
|
||||
generatorByClassName.put(Bytes.class, (r) -> TestBytes.get());
|
||||
generatorByClassName.put(ImmutablePublicKeyCredentialUserEntity.class,
|
||||
(r) -> TestPublicKeyCredentialUserEntity.userEntity().id(TestBytes.get()).build());
|
||||
generatorByClassName.put(WebAuthnAuthentication.class, (r) -> {
|
||||
PublicKeyCredentialUserEntity userEntity = TestPublicKeyCredentialUserEntity.userEntity()
|
||||
.id(TestBytes.get())
|
||||
.build();
|
||||
List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_USER");
|
||||
WebAuthnAuthentication webAuthnAuthentication = new WebAuthnAuthentication(userEntity, authorities);
|
||||
webAuthnAuthentication.setDetails(details);
|
||||
return webAuthnAuthentication;
|
||||
});
|
||||
|
||||
// webauthn
|
||||
CredProtectAuthenticationExtensionsClientInput.CredProtect credProtect = new CredProtectAuthenticationExtensionsClientInput.CredProtect(
|
||||
CredProtectAuthenticationExtensionsClientInput.CredProtect.ProtectionPolicy.USER_VERIFICATION_OPTIONAL,
|
||||
true);
|
||||
Bytes id = TestBytes.get();
|
||||
AuthenticationExtensionsClientInputs inputs = new ImmutableAuthenticationExtensionsClientInputs(
|
||||
ImmutableAuthenticationExtensionsClientInput.credProps);
|
||||
// @formatter:off
|
||||
PublicKeyCredentialDescriptor descriptor = PublicKeyCredentialDescriptor.builder()
|
||||
.id(id)
|
||||
.type(PublicKeyCredentialType.PUBLIC_KEY)
|
||||
.transports(Set.of(AuthenticatorTransport.USB))
|
||||
.build();
|
||||
// @formatter:on
|
||||
generatorByClassName.put(AuthenticatorTransport.class, (a) -> AuthenticatorTransport.USB);
|
||||
generatorByClassName.put(PublicKeyCredentialType.class, (k) -> PublicKeyCredentialType.PUBLIC_KEY);
|
||||
generatorByClassName.put(UserVerificationRequirement.class, (r) -> UserVerificationRequirement.REQUIRED);
|
||||
generatorByClassName.put(CredProtectAuthenticationExtensionsClientInput.CredProtect.class, (c) -> credProtect);
|
||||
generatorByClassName.put(CredProtectAuthenticationExtensionsClientInput.class,
|
||||
(c) -> new CredProtectAuthenticationExtensionsClientInput(credProtect));
|
||||
generatorByClassName.put(ImmutableAuthenticationExtensionsClientInputs.class, (i) -> inputs);
|
||||
Field credPropsField = ReflectionUtils.findField(ImmutableAuthenticationExtensionsClientInput.class,
|
||||
"credProps");
|
||||
generatorByClassName.put(credPropsField.getType(),
|
||||
(i) -> ImmutableAuthenticationExtensionsClientInput.credProps);
|
||||
generatorByClassName.put(Bytes.class, (b) -> id);
|
||||
generatorByClassName.put(PublicKeyCredentialDescriptor.class, (d) -> descriptor);
|
||||
// @formatter:off
|
||||
generatorByClassName.put(PublicKeyCredentialRequestOptions.class, (o) -> TestPublicKeyCredentialRequestOptions.create()
|
||||
.extensions(inputs)
|
||||
.allowCredentials(List.of(descriptor))
|
||||
.build()
|
||||
);
|
||||
|
||||
CredentialPropertiesOutput credentialOutput = new CredentialPropertiesOutput(false);
|
||||
AuthenticationExtensionsClientOutputs outputs = new ImmutableAuthenticationExtensionsClientOutputs(credentialOutput);
|
||||
AuthenticatorAssertionResponse response = TestAuthenticationAssertionResponses.createAuthenticatorAssertionResponse()
|
||||
.build();
|
||||
PublicKeyCredential<AuthenticatorAssertionResponse> credential = TestPublicKeyCredential.createPublicKeyCredential(
|
||||
response, outputs)
|
||||
.build();
|
||||
RelyingPartyAuthenticationRequest authRequest = new RelyingPartyAuthenticationRequest(
|
||||
TestPublicKeyCredentialRequestOptions.create().build(),
|
||||
credential
|
||||
);
|
||||
WebAuthnAuthenticationRequestToken requestToken = new WebAuthnAuthenticationRequestToken(authRequest);
|
||||
requestToken.setDetails(details);
|
||||
generatorByClassName.put(CredentialPropertiesOutput.class, (o) -> credentialOutput);
|
||||
generatorByClassName.put(ImmutableAuthenticationExtensionsClientOutputs.class, (o) -> outputs);
|
||||
generatorByClassName.put(AuthenticatorAssertionResponse.class, (r) -> response);
|
||||
generatorByClassName.put(RelyingPartyAuthenticationRequest.class, (r) -> authRequest);
|
||||
generatorByClassName.put(PublicKeyCredential.class, (r) -> credential);
|
||||
generatorByClassName.put(WebAuthnAuthenticationRequestToken.class, (r) -> requestToken);
|
||||
generatorByClassName.put(AuthenticatorAttachment.class, (r) -> AuthenticatorAttachment.PLATFORM);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@@ -375,7 +717,7 @@ class SpringSecurityCoreVersionSerializableTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void listClassesMissingSerialVersion() throws Exception {
|
||||
void allSerializableClassesShouldHaveSerialVersionOrSuppressWarnings() throws Exception {
|
||||
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
|
||||
provider.addIncludeFilter(new AssignableTypeFilter(Serializable.class));
|
||||
List<Class<?>> classes = new ArrayList<>();
|
||||
@@ -383,10 +725,6 @@ class SpringSecurityCoreVersionSerializableTests {
|
||||
Set<BeanDefinition> components = provider.findCandidateComponents("org/springframework/security");
|
||||
for (BeanDefinition component : components) {
|
||||
Class<?> clazz = Class.forName(component.getBeanClassName());
|
||||
boolean isAbstract = Modifier.isAbstract(clazz.getModifiers());
|
||||
if (isAbstract) {
|
||||
continue;
|
||||
}
|
||||
if (clazz.isEnum()) {
|
||||
continue;
|
||||
}
|
||||
@@ -396,15 +734,16 @@ class SpringSecurityCoreVersionSerializableTests {
|
||||
boolean hasSerialVersion = Stream.of(clazz.getDeclaredFields())
|
||||
.map(Field::getName)
|
||||
.anyMatch((n) -> n.equals("serialVersionUID"));
|
||||
if (!hasSerialVersion) {
|
||||
SuppressWarnings suppressWarnings = clazz.getAnnotation(SuppressWarnings.class);
|
||||
boolean hasSerialIgnore = suppressWarnings == null
|
||||
|| Arrays.asList(suppressWarnings.value()).contains("Serial");
|
||||
if (!hasSerialVersion && !hasSerialIgnore) {
|
||||
classes.add(clazz);
|
||||
}
|
||||
}
|
||||
if (!classes.isEmpty()) {
|
||||
System.out
|
||||
.println("Found " + classes.size() + " Serializable classes that don't declare a seriallVersionUID");
|
||||
System.out.println(classes.stream().map(Class::getName).collect(Collectors.joining("\r\n")));
|
||||
}
|
||||
assertThat(classes)
|
||||
.describedAs("Found Serializable classes that are either missing a serialVersionUID or a @SuppressWarnings")
|
||||
.isEmpty();
|
||||
}
|
||||
|
||||
static Stream<Class<?>> getClassesToSerialize() throws Exception {
|
||||
@@ -430,7 +769,11 @@ class SpringSecurityCoreVersionSerializableTests {
|
||||
}
|
||||
|
||||
private static InstancioApi<?> instancioWithDefaults(Class<?> clazz) {
|
||||
InstancioApi<?> instancio = Instancio.of(clazz);
|
||||
InstancioOfClassApi<?> instancio = Instancio.of(clazz);
|
||||
ResolvableType[] generics = ResolvableType.forClass(clazz).getGenerics();
|
||||
for (ResolvableType type : generics) {
|
||||
instancio.withTypeParameters(type.resolve());
|
||||
}
|
||||
if (generatorByClassName.containsKey(clazz)) {
|
||||
instancio.supply(Select.all(clazz), generatorByClassName.get(clazz));
|
||||
}
|
||||
|
||||
+92
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 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.
|
||||
@@ -75,6 +75,7 @@ import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.springframework.security.config.Customizer.withDefaults;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
|
||||
@@ -301,6 +302,49 @@ public class OAuth2ClientConfigurerTests {
|
||||
verify(authorizationRequestResolver).resolve(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWhenOAuth2LoginBeansConfiguredThenNotShared() throws Exception {
|
||||
this.spring.register(OAuth2ClientConfigWithOAuth2Login.class).autowire();
|
||||
// Setup the Authorization Request in the session
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
attributes.put(OAuth2ParameterNames.REGISTRATION_ID, this.registration1.getRegistrationId());
|
||||
// @formatter:off
|
||||
OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest.authorizationCode()
|
||||
.authorizationUri(this.registration1.getProviderDetails().getAuthorizationUri())
|
||||
.clientId(this.registration1.getClientId())
|
||||
.redirectUri("http://localhost/client-1")
|
||||
.state("state")
|
||||
.attributes(attributes)
|
||||
.build();
|
||||
// @formatter:on
|
||||
AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository = new HttpSessionOAuth2AuthorizationRequestRepository();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, request, response);
|
||||
MockHttpSession session = (MockHttpSession) request.getSession();
|
||||
String principalName = "user1";
|
||||
TestingAuthenticationToken authentication = new TestingAuthenticationToken(principalName, "password");
|
||||
// @formatter:off
|
||||
MockHttpServletRequestBuilder clientRequest = get("/client-1")
|
||||
.param(OAuth2ParameterNames.CODE, "code")
|
||||
.param(OAuth2ParameterNames.STATE, "state")
|
||||
.with(authentication(authentication))
|
||||
.session(session);
|
||||
this.mockMvc.perform(clientRequest)
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andExpect(redirectedUrl("http://localhost/client-1"));
|
||||
// @formatter:on
|
||||
OAuth2AuthorizedClient authorizedClient = authorizedClientRepository
|
||||
.loadAuthorizedClient(this.registration1.getRegistrationId(), authentication, request);
|
||||
assertThat(authorizedClient).isNotNull();
|
||||
// Ensure shared objects set for OAuth2 Client are not used
|
||||
ClientRegistrationRepository clientRegistrationRepository = this.spring.getContext()
|
||||
.getBean(ClientRegistrationRepository.class);
|
||||
OAuth2AuthorizedClientRepository authorizedClientRepository = this.spring.getContext()
|
||||
.getBean(OAuth2AuthorizedClientRepository.class);
|
||||
verifyNoInteractions(clientRegistrationRepository, authorizedClientRepository);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@@ -388,4 +432,51 @@ public class OAuth2ClientConfigurerTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableWebMvc
|
||||
static class OAuth2ClientConfigWithOAuth2Login {
|
||||
|
||||
private final ClientRegistrationRepository clientRegistrationRepository = mock(
|
||||
ClientRegistrationRepository.class);
|
||||
|
||||
private final OAuth2AuthorizedClientRepository authorizedClientRepository = mock(
|
||||
OAuth2AuthorizedClientRepository.class);
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.oauth2Client((oauth2Client) -> oauth2Client
|
||||
.clientRegistrationRepository(OAuth2ClientConfigurerTests.clientRegistrationRepository)
|
||||
.authorizedClientService(OAuth2ClientConfigurerTests.authorizedClientService)
|
||||
.authorizationCodeGrant((authorizationCode) -> authorizationCode
|
||||
.authorizationRequestResolver(authorizationRequestResolver)
|
||||
.authorizationRedirectStrategy(authorizationRedirectStrategy)
|
||||
.accessTokenResponseClient(accessTokenResponseClient)
|
||||
)
|
||||
)
|
||||
.oauth2Login((oauth2Login) -> oauth2Login
|
||||
.clientRegistrationRepository(this.clientRegistrationRepository)
|
||||
.authorizedClientRepository(this.authorizedClientRepository)
|
||||
);
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
ClientRegistrationRepository clientRegistrationRepository() {
|
||||
return this.clientRegistrationRepository;
|
||||
}
|
||||
|
||||
@Bean
|
||||
OAuth2AuthorizedClientRepository authorizedClientRepository() {
|
||||
return this.authorizedClientRepository;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+67
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 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.
|
||||
@@ -73,7 +73,9 @@ import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
|
||||
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository;
|
||||
import org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizationRequestRepository;
|
||||
import org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver;
|
||||
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
||||
@@ -115,6 +117,7 @@ import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.springframework.security.config.annotation.SecurityContextChangedListenerArgumentMatchers.setAuthentication;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
||||
@@ -669,6 +672,30 @@ public class OAuth2LoginConfigurerTests {
|
||||
.collect(Collectors.toList())).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void oidcLoginWhenOAuth2ClientBeansConfiguredThenNotShared() throws Exception {
|
||||
this.spring.register(OAuth2LoginConfigWithOAuth2Client.class, JwtDecoderFactoryConfig.class).autowire();
|
||||
OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest("openid");
|
||||
this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, this.request, this.response);
|
||||
this.request.setParameter("code", "code123");
|
||||
this.request.setParameter("state", authorizationRequest.getState());
|
||||
this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
|
||||
Authentication authentication = this.securityContextRepository
|
||||
.loadContext(new HttpRequestResponseHolder(this.request, this.response))
|
||||
.getAuthentication();
|
||||
assertThat(authentication.getAuthorities()).hasSize(1);
|
||||
assertThat(authentication.getAuthorities()).first()
|
||||
.isInstanceOf(OidcUserAuthority.class)
|
||||
.hasToString("OIDC_USER");
|
||||
|
||||
// Ensure shared objects set for OAuth2 Client are not used
|
||||
ClientRegistrationRepository clientRegistrationRepository = this.spring.getContext()
|
||||
.getBean(ClientRegistrationRepository.class);
|
||||
OAuth2AuthorizedClientRepository authorizedClientRepository = this.spring.getContext()
|
||||
.getBean(OAuth2AuthorizedClientRepository.class);
|
||||
verifyNoInteractions(clientRegistrationRepository, authorizedClientRepository);
|
||||
}
|
||||
|
||||
private void loadConfig(Class<?>... configs) {
|
||||
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
|
||||
applicationContext.register(configs);
|
||||
@@ -1192,6 +1219,45 @@ public class OAuth2LoginConfigurerTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class OAuth2LoginConfigWithOAuth2Client extends CommonLambdaSecurityFilterChainConfig {
|
||||
|
||||
private final ClientRegistrationRepository clientRegistrationRepository = mock(
|
||||
ClientRegistrationRepository.class);
|
||||
|
||||
private final OAuth2AuthorizedClientRepository authorizedClientRepository = mock(
|
||||
OAuth2AuthorizedClientRepository.class);
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.oauth2Login((oauth2Login) -> oauth2Login
|
||||
.clientRegistrationRepository(
|
||||
new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION))
|
||||
.authorizedClientRepository(new HttpSessionOAuth2AuthorizedClientRepository())
|
||||
)
|
||||
.oauth2Client((oauth2Client) -> oauth2Client
|
||||
.clientRegistrationRepository(this.clientRegistrationRepository)
|
||||
.authorizedClientRepository(this.authorizedClientRepository)
|
||||
);
|
||||
// @formatter:on
|
||||
return super.configureFilterChain(http);
|
||||
}
|
||||
|
||||
@Bean
|
||||
ClientRegistrationRepository clientRegistrationRepository() {
|
||||
return this.clientRegistrationRepository;
|
||||
}
|
||||
|
||||
@Bean
|
||||
OAuth2AuthorizedClientRepository authorizedClientRepository() {
|
||||
return this.authorizedClientRepository;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private abstract static class CommonSecurityFilterChainConfig {
|
||||
|
||||
SecurityFilterChain configureFilterChain(HttpSecurity http) throws Exception {
|
||||
|
||||
+35
-11
@@ -72,7 +72,7 @@ public class OneTimeTokenLoginConfigurerTests {
|
||||
this.mvc.perform(post("/ott/generate").param("username", "user").with(csrf()))
|
||||
.andExpectAll(status().isFound(), redirectedUrl("/login/ott"));
|
||||
|
||||
String token = TestOneTimeTokenGenerationSuccessHandler.lastToken.getTokenValue();
|
||||
String token = getLastToken().getTokenValue();
|
||||
|
||||
this.mvc.perform(post("/login/ott").param("token", token).with(csrf()))
|
||||
.andExpectAll(status().isFound(), redirectedUrl("/"), authenticated());
|
||||
@@ -84,7 +84,7 @@ public class OneTimeTokenLoginConfigurerTests {
|
||||
this.mvc.perform(post("/generateurl").param("username", "user").with(csrf()))
|
||||
.andExpectAll(status().isFound(), redirectedUrl("/redirected"));
|
||||
|
||||
String token = TestOneTimeTokenGenerationSuccessHandler.lastToken.getTokenValue();
|
||||
String token = getLastToken().getTokenValue();
|
||||
|
||||
this.mvc.perform(post("/loginprocessingurl").param("token", token).with(csrf()))
|
||||
.andExpectAll(status().isFound(), redirectedUrl("/authenticated"), authenticated());
|
||||
@@ -96,7 +96,7 @@ public class OneTimeTokenLoginConfigurerTests {
|
||||
this.mvc.perform(post("/ott/generate").param("username", "user").with(csrf()))
|
||||
.andExpectAll(status().isFound(), redirectedUrl("/login/ott"));
|
||||
|
||||
String token = TestOneTimeTokenGenerationSuccessHandler.lastToken.getTokenValue();
|
||||
String token = getLastToken().getTokenValue();
|
||||
|
||||
this.mvc.perform(post("/login/ott").param("token", token).with(csrf()))
|
||||
.andExpectAll(status().isFound(), redirectedUrl("/"), authenticated());
|
||||
@@ -194,25 +194,37 @@ public class OneTimeTokenLoginConfigurerTests {
|
||||
""");
|
||||
}
|
||||
|
||||
private OneTimeToken getLastToken() {
|
||||
OneTimeToken lastToken = this.spring.getContext()
|
||||
.getBean(TestOneTimeTokenGenerationSuccessHandler.class).lastToken;
|
||||
return lastToken;
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableWebSecurity
|
||||
@Import(UserDetailsServiceConfig.class)
|
||||
static class OneTimeTokenDefaultConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http,
|
||||
OneTimeTokenGenerationSuccessHandler ottSuccessHandler) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeHttpRequests((authz) -> authz
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.oneTimeTokenLogin((ott) -> ott
|
||||
.tokenGenerationSuccessHandler(new TestOneTimeTokenGenerationSuccessHandler())
|
||||
.tokenGenerationSuccessHandler(ottSuccessHandler)
|
||||
);
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
TestOneTimeTokenGenerationSuccessHandler ottSuccessHandler() {
|
||||
return new TestOneTimeTokenGenerationSuccessHandler();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@@ -221,7 +233,8 @@ public class OneTimeTokenLoginConfigurerTests {
|
||||
static class OneTimeTokenDifferentUrlsConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http,
|
||||
OneTimeTokenGenerationSuccessHandler ottSuccessHandler) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeHttpRequests((authz) -> authz
|
||||
@@ -229,7 +242,7 @@ public class OneTimeTokenLoginConfigurerTests {
|
||||
)
|
||||
.oneTimeTokenLogin((ott) -> ott
|
||||
.tokenGeneratingUrl("/generateurl")
|
||||
.tokenGenerationSuccessHandler(new TestOneTimeTokenGenerationSuccessHandler("/redirected"))
|
||||
.tokenGenerationSuccessHandler(ottSuccessHandler)
|
||||
.loginProcessingUrl("/loginprocessingurl")
|
||||
.authenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/authenticated"))
|
||||
);
|
||||
@@ -237,6 +250,11 @@ public class OneTimeTokenLoginConfigurerTests {
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
TestOneTimeTokenGenerationSuccessHandler ottSuccessHandler() {
|
||||
return new TestOneTimeTokenGenerationSuccessHandler("/redirected");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@@ -245,7 +263,8 @@ public class OneTimeTokenLoginConfigurerTests {
|
||||
static class OneTimeTokenFormLoginConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http,
|
||||
OneTimeTokenGenerationSuccessHandler ottSuccessHandler) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeHttpRequests((authz) -> authz
|
||||
@@ -253,12 +272,17 @@ public class OneTimeTokenLoginConfigurerTests {
|
||||
)
|
||||
.formLogin(Customizer.withDefaults())
|
||||
.oneTimeTokenLogin((ott) -> ott
|
||||
.tokenGenerationSuccessHandler(new TestOneTimeTokenGenerationSuccessHandler())
|
||||
.tokenGenerationSuccessHandler(ottSuccessHandler)
|
||||
);
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
TestOneTimeTokenGenerationSuccessHandler ottSuccessHandler() {
|
||||
return new TestOneTimeTokenGenerationSuccessHandler();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@@ -282,7 +306,7 @@ public class OneTimeTokenLoginConfigurerTests {
|
||||
|
||||
static class TestOneTimeTokenGenerationSuccessHandler implements OneTimeTokenGenerationSuccessHandler {
|
||||
|
||||
private static OneTimeToken lastToken;
|
||||
private OneTimeToken lastToken;
|
||||
|
||||
private final OneTimeTokenGenerationSuccessHandler delegate;
|
||||
|
||||
@@ -297,7 +321,7 @@ public class OneTimeTokenLoginConfigurerTests {
|
||||
@Override
|
||||
public void handle(HttpServletRequest request, HttpServletResponse response, OneTimeToken oneTimeToken)
|
||||
throws IOException, ServletException {
|
||||
lastToken = oneTimeToken;
|
||||
this.lastToken = oneTimeToken;
|
||||
this.delegate.handle(request, response, oneTimeToken);
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -484,6 +484,7 @@ public class Saml2LogoutConfigurerTests {
|
||||
verify(getBean(Saml2LogoutResponseValidator.class)).validate(any());
|
||||
}
|
||||
|
||||
// gh-11363
|
||||
@Test
|
||||
public void saml2LogoutWhenCustomLogoutRequestRepositoryThenUses() throws Exception {
|
||||
this.spring.register(Saml2LogoutComponentsConfig.class).autowire();
|
||||
|
||||
+17
@@ -63,6 +63,7 @@ import org.springframework.web.util.UriUtils;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -380,6 +381,22 @@ public class Saml2LogoutBeanDefinitionParserTests {
|
||||
verify(getBean(Saml2LogoutResponseValidator.class)).validate(any());
|
||||
}
|
||||
|
||||
// gh-11363
|
||||
@Test
|
||||
public void saml2LogoutWhenCustomLogoutRequestRepositoryThenUses() throws Exception {
|
||||
this.spring.configLocations(this.xml("CustomComponents")).autowire();
|
||||
RelyingPartyRegistration registration = this.repository.findByRegistrationId("get");
|
||||
Saml2LogoutRequest logoutRequest = Saml2LogoutRequest.withRelyingPartyRegistration(registration)
|
||||
.samlRequest(this.rpLogoutRequest)
|
||||
.id(this.rpLogoutRequestId)
|
||||
.relayState(this.rpLogoutRequestRelayState)
|
||||
.parameters((params) -> params.put("Signature", this.rpLogoutRequestSignature))
|
||||
.build();
|
||||
given(getBean(Saml2LogoutRequestResolver.class).resolve(any(), any())).willReturn(logoutRequest);
|
||||
this.mvc.perform(post("/logout").with(authentication(this.saml2User)).with(csrf()));
|
||||
verify(getBean(Saml2LogoutRequestRepository.class)).saveLogoutRequest(eq(logoutRequest), any(), any());
|
||||
}
|
||||
|
||||
private <T> T getBean(Class<T> clazz) {
|
||||
return this.spring.getContext().getBean(clazz);
|
||||
}
|
||||
|
||||
+25
-12
@@ -69,7 +69,7 @@ class OneTimeTokenLoginDslTests {
|
||||
.redirectedUrl("/login/ott")
|
||||
)
|
||||
|
||||
val token = TestOneTimeTokenGenerationSuccessHandler.lastToken?.tokenValue
|
||||
val token = getLastToken().tokenValue
|
||||
|
||||
this.mockMvc.perform(
|
||||
MockMvcRequestBuilders.post("/login/ott").param("token", token)
|
||||
@@ -91,7 +91,7 @@ class OneTimeTokenLoginDslTests {
|
||||
)
|
||||
.andExpectAll(MockMvcResultMatchers.status().isFound(), MockMvcResultMatchers.redirectedUrl("/redirected"))
|
||||
|
||||
val token = TestOneTimeTokenGenerationSuccessHandler.lastToken?.tokenValue
|
||||
val token = getLastToken().tokenValue
|
||||
|
||||
this.mockMvc.perform(
|
||||
MockMvcRequestBuilders.post("/loginprocessingurl").param("token", token)
|
||||
@@ -104,25 +104,36 @@ class OneTimeTokenLoginDslTests {
|
||||
)
|
||||
}
|
||||
|
||||
private fun getLastToken(): OneTimeToken {
|
||||
val lastToken: OneTimeToken = spring.context
|
||||
.getBean(TestOneTimeTokenGenerationSuccessHandler::class.java).lastToken!!
|
||||
return lastToken
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@Import(UserDetailsServiceConfig::class)
|
||||
open class OneTimeTokenConfig {
|
||||
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
open fun securityFilterChain(http: HttpSecurity, ottSuccessHandler: OneTimeTokenGenerationSuccessHandler): SecurityFilterChain {
|
||||
// @formatter:off
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
authorize(anyRequest, authenticated)
|
||||
}
|
||||
oneTimeTokenLogin {
|
||||
oneTimeTokenGenerationSuccessHandler = TestOneTimeTokenGenerationSuccessHandler()
|
||||
oneTimeTokenGenerationSuccessHandler = ottSuccessHandler
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun ottSuccessHandler(): TestOneTimeTokenGenerationSuccessHandler {
|
||||
return TestOneTimeTokenGenerationSuccessHandler()
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@@ -130,7 +141,7 @@ class OneTimeTokenLoginDslTests {
|
||||
@Import(UserDetailsServiceConfig::class)
|
||||
open class OneTimeTokenDifferentUrlsConfig {
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
open fun securityFilterChain(http: HttpSecurity, ottSuccessHandler: OneTimeTokenGenerationSuccessHandler): SecurityFilterChain {
|
||||
// @formatter:off
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
@@ -138,7 +149,7 @@ class OneTimeTokenLoginDslTests {
|
||||
}
|
||||
oneTimeTokenLogin {
|
||||
tokenGeneratingUrl = "/generateurl"
|
||||
oneTimeTokenGenerationSuccessHandler = TestOneTimeTokenGenerationSuccessHandler("/redirected")
|
||||
oneTimeTokenGenerationSuccessHandler = ottSuccessHandler
|
||||
loginProcessingUrl = "/loginprocessingurl"
|
||||
authenticationSuccessHandler = SimpleUrlAuthenticationSuccessHandler("/authenticated")
|
||||
}
|
||||
@@ -146,6 +157,11 @@ class OneTimeTokenLoginDslTests {
|
||||
// @formatter:on
|
||||
return http.build()
|
||||
}
|
||||
|
||||
@Bean
|
||||
open fun ottSuccessHandler(): TestOneTimeTokenGenerationSuccessHandler {
|
||||
return TestOneTimeTokenGenerationSuccessHandler("/redirected")
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@@ -156,9 +172,10 @@ class OneTimeTokenLoginDslTests {
|
||||
InMemoryUserDetailsManager(PasswordEncodedUser.user(), PasswordEncodedUser.admin())
|
||||
}
|
||||
|
||||
private class TestOneTimeTokenGenerationSuccessHandler :
|
||||
class TestOneTimeTokenGenerationSuccessHandler :
|
||||
OneTimeTokenGenerationSuccessHandler {
|
||||
private val delegate: OneTimeTokenGenerationSuccessHandler
|
||||
var lastToken: OneTimeToken? = null
|
||||
|
||||
constructor() {
|
||||
this.delegate =
|
||||
@@ -175,12 +192,8 @@ class OneTimeTokenLoginDslTests {
|
||||
}
|
||||
|
||||
override fun handle(request: HttpServletRequest, response: HttpServletResponse, oneTimeToken: OneTimeToken) {
|
||||
lastToken = oneTimeToken
|
||||
this.lastToken = oneTimeToken
|
||||
delegate.handle(request, response, oneTimeToken)
|
||||
}
|
||||
|
||||
companion object {
|
||||
var lastToken: OneTimeToken? = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+74
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.security.config.annotation.web
|
||||
|
||||
import org.hamcrest.Matchers
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
@@ -30,7 +31,9 @@ import org.springframework.security.core.userdetails.UserDetailsService
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager
|
||||
import org.springframework.security.web.SecurityFilterChain
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.get
|
||||
import org.springframework.test.web.servlet.post
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers
|
||||
|
||||
/**
|
||||
* Tests for [WebAuthnDsl]
|
||||
@@ -55,6 +58,76 @@ class WebAuthnDslTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `webauthn and formLogin configured with default registration page`() {
|
||||
spring.register(DefaultWebauthnConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/login/webauthn.js")
|
||||
.andExpect {
|
||||
MockMvcResultMatchers.status().isOk
|
||||
header {
|
||||
string("content-type", "text/javascript;charset=UTF-8")
|
||||
}
|
||||
content {
|
||||
string(Matchers.containsString("async function authenticate("))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `webauthn and formLogin configured with disabled default registration page`() {
|
||||
spring.register(FormLoginAndNoDefaultRegistrationPageConfiguration::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/login/webauthn.js")
|
||||
.andExpect {
|
||||
MockMvcResultMatchers.status().isOk
|
||||
header {
|
||||
string("content-type", "text/javascript;charset=UTF-8")
|
||||
}
|
||||
content {
|
||||
string(Matchers.containsString("async function authenticate("))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
open class FormLoginAndNoDefaultRegistrationPageConfiguration {
|
||||
@Bean
|
||||
open fun userDetailsService(): UserDetailsService =
|
||||
InMemoryUserDetailsManager()
|
||||
|
||||
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http{
|
||||
formLogin { }
|
||||
webAuthn {
|
||||
disableDefaultRegistrationPage = true
|
||||
}
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
open class DefaultWebauthnConfig {
|
||||
@Bean
|
||||
open fun userDetailsService(): UserDetailsService =
|
||||
InMemoryUserDetailsManager()
|
||||
|
||||
|
||||
@Bean
|
||||
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
||||
http{
|
||||
formLogin { }
|
||||
webAuthn { }
|
||||
}
|
||||
return http.build()
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
open class WebauthnConfig {
|
||||
|
||||
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.
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