1
0
mirror of synced 2026-09-02 23:39:56 +00:00

Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot] 3017a52406 Bump org.springframework.data:spring-data-bom
Bumps [org.springframework.data:spring-data-bom](https://github.com/spring-projects/spring-data-bom) from 2026.1.0-M1 to 2026.1.0-SNAPSHOT.
- [Release notes](https://github.com/spring-projects/spring-data-bom/releases)
- [Commits](https://github.com/spring-projects/spring-data-bom/commits)

---
updated-dependencies:
- dependency-name: org.springframework.data:spring-data-bom
  dependency-version: 2026.1.0-SNAPSHOT
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-21 03:04:36 +00:00
14 changed files with 11 additions and 350 deletions
+2 -1
View File
@@ -4,6 +4,7 @@ on:
pull_request:
branches:
- main
- '*.x'
- 'docs-build'
run-name: Merge Dependabot PR ${{ github.ref_name }}
@@ -13,4 +14,4 @@ jobs:
permissions: write-all
uses: spring-io/spring-github-workflows/.github/workflows/spring-merge-dependabot-pr.yml@0d3f15bb384839966a1ff5c4383731a2b747f24b # v7
with:
mergeArguments: --auto --rebase
mergeArguments: --auto --rebase
@@ -39,7 +39,7 @@ jobs:
deploy-schema:
name: Deploy Schema
needs: [ build ]
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@3f6cc7ffc137ca160061749d5f34dc30d5f36986 # v1.0.17
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@b92832ecbc7cbe969201e6beafbde0ee400cf095 # v1.0.15
with:
should-deploy-schema: ${{ needs.build.outputs.should-deploy-artifacts }}
java-version: 25
+1 -1
View File
@@ -28,7 +28,7 @@ jobs:
milestone-token: ${{ secrets.GITHUB_TOKEN }}
- name: Compute Next Version
id: next-version
uses: spring-io/spring-release-actions/compute-next-version@1b8671612c3eb3d9b9763e2d7b66f1a80d00ee95 # 0.0.6
uses: spring-io/spring-release-actions/compute-next-version@a1f321783a0769dd2aea4fad6c2ae2f95a52b885 # 0.0.5
with:
version: ${{ steps.todays-release.outputs.release-version }}
- name: Schedule Next Milestone
@@ -16,7 +16,7 @@ permissions:
jobs:
deploy-schema:
name: Deploy Schema
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@3f6cc7ffc137ca160061749d5f34dc30d5f36986 # v1.0.17
uses: spring-io/spring-security-release-tools/.github/workflows/deploy-schema.yml@d6c65d3013c0888e2c9cbae9f4beda610994776c # v1.0.16
with:
should-deploy-schema: true
secrets: inherit
@@ -18,7 +18,7 @@ jobs:
stage-release-announcements:
name: Stage Release Announcements
if: ${{ !github.event.repository.fork }}
uses: spring-io/spring-security-release-tools/.github/workflows/release-announcements-stage.yml@3f6cc7ffc137ca160061749d5f34dc30d5f36986 # v1.0.17
uses: spring-io/spring-security-release-tools/.github/workflows/release-announcements-stage.yml@d6c65d3013c0888e2c9cbae9f4beda610994776c # v1.0.16
with:
version: ${{ inputs.version || github.ref_name }}
secrets: inherit
@@ -297,7 +297,6 @@ import org.springframework.web.util.pattern.PathPatternParser;
* @author Ankur Pathak
* @author Alexey Nesterov
* @author Yanming Zhou
* @author Iain Henderson
* @since 5.0
*/
public class ServerHttpSecurity {
@@ -4139,8 +4138,6 @@ public class ServerHttpSecurity {
private ServerAuthenticationFailureHandler authenticationFailureHandler;
private ServerAuthenticationSuccessHandler authenticationSuccessHandler;
private ServerAccessDeniedHandler accessDeniedHandler = new BearerTokenServerAccessDeniedHandler();
private ServerAuthenticationConverter bearerTokenConverter = new ServerBearerTokenAuthenticationConverter();
@@ -4189,20 +4186,6 @@ public class ServerHttpSecurity {
return this;
}
/**
* Configures the {@link ServerAuthenticationSuccessHandler} to use. The default
* is {@link WebFilterChainServerAuthenticationSuccessHandler}
* @param authenticationSuccessHandler the
* {@link ServerAuthenticationSuccessHandler} to use
* @return the {@link OAuth2ClientSpec} to customize
* @since 7.2
*/
public OAuth2ResourceServerSpec authenticationSuccessHandler(
ServerAuthenticationSuccessHandler authenticationSuccessHandler) {
this.authenticationSuccessHandler = authenticationSuccessHandler;
return this;
}
/**
* Configures the {@link ServerAuthenticationConverter} to use for requests
* authenticating with
@@ -4271,7 +4254,6 @@ public class ServerHttpSecurity {
AuthenticationWebFilter oauth2 = new AuthenticationWebFilter(this.authenticationManagerResolver);
oauth2.setServerAuthenticationConverter(this.bearerTokenConverter);
oauth2.setAuthenticationFailureHandler(authenticationFailureHandler());
oauth2.setAuthenticationSuccessHandler(authenticationSuccessHandler());
http.addFilterAt(oauth2, SecurityWebFiltersOrder.AUTHENTICATION);
}
else if (this.jwt != null) {
@@ -4331,13 +4313,6 @@ public class ServerHttpSecurity {
return new ServerAuthenticationEntryPointFailureHandler(this.entryPoint);
}
private ServerAuthenticationSuccessHandler authenticationSuccessHandler() {
if (this.authenticationSuccessHandler != null) {
return this.authenticationSuccessHandler;
}
return new WebFilterChainServerAuthenticationSuccessHandler();
}
/**
* Configures JWT Resource Server Support
*/
@@ -4412,7 +4387,6 @@ public class ServerHttpSecurity {
AuthenticationWebFilter oauth2 = new AuthenticationWebFilter(authenticationManager);
oauth2.setServerAuthenticationConverter(OAuth2ResourceServerSpec.this.bearerTokenConverter);
oauth2.setAuthenticationFailureHandler(authenticationFailureHandler());
oauth2.setAuthenticationSuccessHandler(authenticationSuccessHandler());
http.addFilterAt(oauth2, SecurityWebFiltersOrder.AUTHENTICATION);
}
@@ -4545,7 +4519,6 @@ public class ServerHttpSecurity {
AuthenticationWebFilter oauth2 = new AuthenticationWebFilter(authenticationManager);
oauth2.setServerAuthenticationConverter(OAuth2ResourceServerSpec.this.bearerTokenConverter);
oauth2.setAuthenticationFailureHandler(authenticationFailureHandler());
oauth2.setAuthenticationSuccessHandler(authenticationSuccessHandler());
http.addFilterAt(oauth2, SecurityWebFiltersOrder.AUTHENTICATION);
}
@@ -20,7 +20,6 @@ import org.springframework.security.authentication.ReactiveAuthenticationManager
import org.springframework.security.web.server.ServerAuthenticationEntryPoint
import org.springframework.security.web.server.authentication.ServerAuthenticationConverter
import org.springframework.security.web.server.authentication.ServerAuthenticationFailureHandler
import org.springframework.security.web.server.authentication.ServerAuthenticationSuccessHandler
import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler
import org.springframework.web.server.ServerWebExchange
@@ -36,8 +35,6 @@ import org.springframework.web.server.ServerWebExchange
* @property bearerTokenConverter the [ServerAuthenticationConverter] to use for requests authenticating with
* Bearer Tokens.
* @property authenticationManagerResolver the [ReactiveAuthenticationManagerResolver] to use.
* @property authenticationSuccessHandler the [ServerAuthenticationSuccessHandler] to use after
* authentication success.
*/
@ServerSecurityMarker
class ServerOAuth2ResourceServerDsl {
@@ -46,7 +43,6 @@ class ServerOAuth2ResourceServerDsl {
var authenticationEntryPoint: ServerAuthenticationEntryPoint? = null
var bearerTokenConverter: ServerAuthenticationConverter? = null
var authenticationManagerResolver: ReactiveAuthenticationManagerResolver<ServerWebExchange>? = null
var authenticationSuccessHandler: ServerAuthenticationSuccessHandler? = null
private var jwt: ((ServerHttpSecurity.OAuth2ResourceServerSpec.JwtSpec) -> Unit)? = null
private var opaqueToken: ((ServerHttpSecurity.OAuth2ResourceServerSpec.OpaqueTokenSpec) -> Unit)? = null
@@ -119,7 +115,6 @@ class ServerOAuth2ResourceServerDsl {
authenticationEntryPoint?.also { oauth2ResourceServer.authenticationEntryPoint(authenticationEntryPoint) }
bearerTokenConverter?.also { oauth2ResourceServer.bearerTokenConverter(bearerTokenConverter) }
authenticationManagerResolver?.also { oauth2ResourceServer.authenticationManagerResolver(authenticationManagerResolver!!) }
authenticationSuccessHandler?.also { oauth2ResourceServer.authenticationSuccessHandler(authenticationSuccessHandler) }
jwt?.also { oauth2ResourceServer.jwt(jwt) }
opaqueToken?.also { oauth2ResourceServer.opaqueToken(opaqueToken) }
}
@@ -73,11 +73,9 @@ import org.springframework.security.oauth2.server.resource.authentication.Reacti
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenAuthenticationConverter;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.WebFilterExchange;
import org.springframework.security.web.server.authentication.HttpStatusServerEntryPoint;
import org.springframework.security.web.server.authentication.ServerAuthenticationConverter;
import org.springframework.security.web.server.authentication.ServerAuthenticationFailureHandler;
import org.springframework.security.web.server.authentication.ServerAuthenticationSuccessHandler;
import org.springframework.security.web.server.authorization.HttpStatusServerAccessDeniedHandler;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.bind.annotation.GetMapping;
@@ -373,79 +371,6 @@ public class OAuth2ResourceServerSpecTests {
verify(handler).onAuthenticationFailure(any(), any());
}
@Test
public void getWhenUsingCustomAuthenticationSuccessHandlerThenUsesIsAccordingly() {
this.spring.register(CustomAuthenticationSuccessHandlerAuthenticationManagerResolverConfig.class).autowire();
ServerAuthenticationSuccessHandler handler = this.spring.getContext()
.getBean(ServerAuthenticationSuccessHandler.class);
ReactiveAuthenticationManager authenticationManager = this.spring.getContext()
.getBean(ReactiveAuthenticationManager.class);
given(authenticationManager.authenticate(any()))
.willAnswer((input) -> Mono.just(input.getArgument(0, Authentication.class)));
given(handler.onAuthenticationSuccess(any(), any())).willAnswer((input) -> {
WebFilterExchange webFilterExchange = input.getArgument(0, WebFilterExchange.class);
return webFilterExchange.getChain().filter(webFilterExchange.getExchange());
});
// @formatter:off
this.client.get()
.headers((headers) -> headers.setBearerAuth(this.messageReadToken))
.exchange()
.expectStatus().isUnauthorized();
// @formatter:on
verify(handler).onAuthenticationSuccess(any(), any());
}
@Test
public void getWhenUsingCustomAuthenticationSuccessHandlerWithJwtThenUsesIsAccordingly() {
this.spring.register(CustomAuthenticationSuccessHandlerJwtConfig.class).autowire();
ServerAuthenticationSuccessHandler handler = this.spring.getContext()
.getBean(ServerAuthenticationSuccessHandler.class);
ReactiveAuthenticationManager authenticationManager = this.spring.getContext()
.getBean(ReactiveAuthenticationManager.class);
given(authenticationManager.authenticate(any()))
.willAnswer((input) -> Mono.just(input.getArgument(0, Authentication.class)));
given(handler.onAuthenticationSuccess(any(), any())).willAnswer((input) -> {
WebFilterExchange webFilterExchange = input.getArgument(0, WebFilterExchange.class);
return webFilterExchange.getChain().filter(webFilterExchange.getExchange());
});
// @formatter:off
this.client.get()
.headers((headers) -> headers.setBearerAuth(this.messageReadToken))
.exchange()
.expectStatus().isUnauthorized();
// @formatter:on
verify(handler).onAuthenticationSuccess(any(), any());
}
@Test
public void getWhenUsingCustomAuthenticationSuccessHandlerWIthOpaqueTokenThenUsesIsAccordingly() {
this.spring.register(CustomAuthenticationSuccessHandlerOpaqueTokenConfig.class, RootController.class)
.autowire();
this.spring.getContext()
.getBean(MockWebServer.class)
.setDispatcher(requiresAuth(this.clientId, this.clientSecret, this.active));
ServerAuthenticationSuccessHandler handler = this.spring.getContext()
.getBean(ServerAuthenticationSuccessHandler.class);
ReactiveAuthenticationManager authenticationManager = this.spring.getContext()
.getBean(ReactiveAuthenticationManager.class);
given(authenticationManager.authenticate(any()))
.willAnswer((input) -> Mono.just(input.getArgument(0, Authentication.class)));
given(handler.onAuthenticationSuccess(any(), any())).willAnswer((input) -> {
WebFilterExchange webFilterExchange = input.getArgument(0, WebFilterExchange.class);
return webFilterExchange.getChain().filter(webFilterExchange.getExchange());
});
// @formatter:off
this.client.get()
.headers((headers) -> headers
.setBearerAuth(this.messageReadToken)
)
.exchange()
.expectStatus().isOk();
// @formatter:on
verify(handler).onAuthenticationSuccess(any(), any());
}
@Test
public void postWhenSignedThenReturnsOk() {
this.spring.register(PublicKeyConfig.class, RootController.class).autowire();
@@ -1025,111 +950,6 @@ public class OAuth2ResourceServerSpecTests {
}
@Configuration
@EnableWebFlux
@EnableWebFluxSecurity
static class CustomAuthenticationSuccessHandlerAuthenticationManagerResolverConfig {
@Bean
SecurityWebFilterChain springSecurity(ServerHttpSecurity http) {
// @formatter:off
http
.authorizeExchange((authorize) -> authorize.anyExchange().authenticated())
.oauth2ResourceServer((oauth2) -> oauth2
.authenticationSuccessHandler(authenticationSuccessHandler())
.authenticationManagerResolver((exchange) -> Mono.just(authenticationManager()))
);
// @formatter:on
return http.build();
}
@Bean
ReactiveAuthenticationManager authenticationManager() {
return mock(ReactiveAuthenticationManager.class);
}
@Bean
ServerAuthenticationSuccessHandler authenticationSuccessHandler() {
return mock(ServerAuthenticationSuccessHandler.class);
}
}
@Configuration
@EnableWebFlux
@EnableWebFluxSecurity
static class CustomAuthenticationSuccessHandlerJwtConfig {
@Bean
SecurityWebFilterChain springSecurity(ServerHttpSecurity http) {
// @formatter:off
http
.authorizeExchange((authorize) -> authorize.anyExchange().authenticated())
.oauth2ResourceServer((oauth2) -> oauth2
.authenticationSuccessHandler(authenticationSuccessHandler())
.jwt((jwt) -> jwt.authenticationManager(authenticationManager()))
);
// @formatter:on
return http.build();
}
@Bean
ReactiveAuthenticationManager authenticationManager() {
return mock(ReactiveAuthenticationManager.class);
}
@Bean
ServerAuthenticationSuccessHandler authenticationSuccessHandler() {
return mock(ServerAuthenticationSuccessHandler.class);
}
}
@Configuration
@EnableWebFlux
@EnableWebFluxSecurity
static class CustomAuthenticationSuccessHandlerOpaqueTokenConfig {
private MockWebServer mockWebServer = new MockWebServer();
@Bean
SecurityWebFilterChain springSecurity(ServerHttpSecurity http) {
String introspectionUri = mockWebServer().url("/introspect").toString();
// @formatter:off
http
.authorizeExchange((authorize) -> authorize.anyExchange().authenticated())
.oauth2ResourceServer((oauth2) -> oauth2
.authenticationSuccessHandler(authenticationSuccessHandler())
.opaqueToken((opaqueToken) -> opaqueToken
.introspectionUri(introspectionUri)
.introspectionClientCredentials("client", "secret"))
);
// @formatter:on
return http.build();
}
@Bean
ReactiveAuthenticationManager authenticationManager() {
return mock(ReactiveAuthenticationManager.class);
}
@Bean
ServerAuthenticationSuccessHandler authenticationSuccessHandler() {
return mock(ServerAuthenticationSuccessHandler.class);
}
@Bean
MockWebServer mockWebServer() {
return this.mockWebServer;
}
@PreDestroy
void shutdown() throws IOException {
this.mockWebServer.shutdown();
}
}
@EnableWebFlux
@EnableWebFluxSecurity
static class CustomBearerTokenServerAuthenticationConverter {
@@ -17,7 +17,6 @@
package org.springframework.security.config.web.server
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.verify
import org.junit.jupiter.api.Test
@@ -38,7 +37,6 @@ import org.springframework.security.web.server.SecurityWebFilterChain
import org.springframework.security.web.server.WebFilterExchange
import org.springframework.security.web.server.authentication.HttpStatusServerEntryPoint
import org.springframework.security.web.server.authentication.ServerAuthenticationFailureHandler
import org.springframework.security.web.server.authentication.ServerAuthenticationSuccessHandler
import org.springframework.security.web.server.authorization.HttpStatusServerAccessDeniedHandler
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.web.reactive.config.EnableWebFlux
@@ -185,46 +183,6 @@ class ServerOAuth2ResourceServerDslTests {
}
@Test
fun `request when custom authentication success handler then success handler used`() {
this.spring.register(AuthenticationSuccessHandlerConfig::class.java).autowire()
every {
AuthenticationSuccessHandlerConfig.SUCCESS_HANDLER.onAuthenticationSuccess(any(), any())
} returns Mono.empty()
this.client.get()
.uri("/")
.headers { it.setBearerAuth(validJwt) }
.exchange()
verify(exactly = 1) { AuthenticationSuccessHandlerConfig.SUCCESS_HANDLER.onAuthenticationSuccess(any(), any()) }
}
@Configuration
@EnableWebFluxSecurity
@EnableWebFlux
open class AuthenticationSuccessHandlerConfig {
companion object {
val SUCCESS_HANDLER: ServerAuthenticationSuccessHandler = mockk()
}
@Bean
open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
return http {
authorizeExchange {
authorize(anyExchange, authenticated)
}
oauth2ResourceServer {
authenticationSuccessHandler = SUCCESS_HANDLER
jwt {
publicKey = publicKey()
}
}
}
}
}
@Test
fun `request when custom bearer token converter configured then custom converter used`() {
this.spring.register(BearerTokenConverterConfig::class.java).autowire()
-5
View File
@@ -8,8 +8,3 @@
== Web
* Since Spring Framework's `HttpMethod#valueOf` now normalizes casing, `StrictServerWebExchangeFirewall` no longer detects a non-canonical-case HTTP method (for example, `get` instead of `GET`) as a distinct value; such requests are processed as the canonical method instead of being rejected. Applications with a customized `ServerExchangeRejectedHandler` should be aware it is no longer invoked for this case.
== OAuth 2.0
* https://github.com/spring-projects/spring-security/pull/18895[gh-18895] - Add `authenticationSuccessHandler` to the Reactive Resource Server DSL
+2 -2
View File
@@ -39,7 +39,7 @@ io-spring-javaformat-spring-javaformat-checkstyle = { module = "io.spring.javafo
io-spring-javaformat-spring-javaformat-gradle-plugin = { module = "io.spring.javaformat:spring-javaformat-gradle-plugin", version.ref = "io-spring-javaformat" }
io-spring-nohttp-nohttp-checkstyle = { module = "io.spring.nohttp:nohttp-checkstyle", version.ref = "io-spring-nohttp" }
io-spring-nohttp-nohttp-gradle = { module = "io.spring.nohttp:nohttp-gradle", version.ref = "io-spring-nohttp" }
io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.17"
io-spring-security-release-plugin = "io.spring.gradle:spring-security-release-plugin:1.0.15"
jakarta-annotation-jakarta-annotation-api = "jakarta.annotation:jakarta.annotation-api:3.0.0"
jakarta-inject-jakarta-inject-api = "jakarta.inject:jakarta.inject-api:2.0.1"
jakarta-persistence-jakarta-persistence-api = "jakarta.persistence:jakarta.persistence-api:3.2.0"
@@ -85,7 +85,7 @@ org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-sup
org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3"
org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36"
org-slf4j-slf4j-api = "org.slf4j:slf4j-api:2.0.18"
org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2026.1.0-M1"
org-springframework-data-spring-data-bom = "org.springframework.data:spring-data-bom:2026.1.0-SNAPSHOT"
org-springframework-ldap-spring-ldap-core = "org.springframework.ldap:spring-ldap-core:4.1.1"
org-springframework-spring-framework-bom = { module = "org.springframework:spring-framework-bom", version.ref = "org-springframework" }
org-synchronoss-cloud-nio-multipart-parser = "org.synchronoss.cloud:nio-multipart-parser:1.1.0"
@@ -24,12 +24,9 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import reactor.core.publisher.Mono;
import org.springframework.core.log.LogMessage;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
@@ -82,7 +79,7 @@ public final class RefreshOidcUserReactiveOAuth2AuthorizationSuccessHandler
.map((c) -> c.get(ServerWebExchange.class));
// @formatter:on
private ServerSecurityContextRepository serverSecurityContextRepository = new NonRotatingWebSessionServerSecurityContextRepository();
private ServerSecurityContextRepository serverSecurityContextRepository = new WebSessionServerSecurityContextRepository();
private ReactiveJwtDecoderFactory<ClientRegistration> jwtDecoderFactory = new ReactiveOidcIdTokenDecoderFactory();
@@ -144,7 +141,8 @@ public final class RefreshOidcUserReactiveOAuth2AuthorizationSuccessHandler
/**
* Sets a {@link ServerSecurityContextRepository} to use for refreshing a
* {@link SecurityContext}.
* {@link SecurityContext}, defaults to
* {@link WebSessionServerSecurityContextRepository}.
* @param serverSecurityContextRepository the {@link ServerSecurityContextRepository}
* to use
*/
@@ -318,28 +316,4 @@ public final class RefreshOidcUserReactiveOAuth2AuthorizationSuccessHandler
return this.serverSecurityContextRepository.save(exchange, securityContext);
}
private static final class NonRotatingWebSessionServerSecurityContextRepository
implements ServerSecurityContextRepository {
private static final Log logger = LogFactory.getLog(NonRotatingWebSessionServerSecurityContextRepository.class);
@Override
public Mono<SecurityContext> load(ServerWebExchange exchange) {
return Mono.empty();
}
@Override
public Mono<Void> save(ServerWebExchange exchange, @Nullable SecurityContext context) {
Assert.notNull(context, "context cannot be null");
// Save SecurityContext in WebSession without rotating session id.
return exchange.getSession().doOnNext((session) -> {
session.getAttributes()
.put(WebSessionServerSecurityContextRepository.DEFAULT_SPRING_SECURITY_CONTEXT_ATTR_NAME, context);
logger.debug(LogMessage.format("Saved SecurityContext '%s' in WebSession: '%s'", context, session));
}).then();
}
}
}
@@ -50,9 +50,7 @@ import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoderFactory;
import org.springframework.security.web.server.context.WebSessionServerSecurityContextRepository;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebSession;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatException;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
@@ -142,51 +140,6 @@ class RefreshOidcUserReactiveOAuth2AuthorizationSuccessHandlerTests {
.verifyComplete();
}
// gh-19424
@Test
void onAuthorizationSuccessWhenDefaultServerSecurityContextRepositoryThenWebSessionIdNotChanged() {
ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().build();
Instant authTime = Instant.now();
DefaultOidcUser principal = createOidcUser(authTime);
OAuth2AuthenticationToken authenticationToken = new OAuth2AuthenticationToken(principal,
principal.getAuthorities(), clientRegistration.getRegistrationId());
OAuth2AccessToken accessToken = createAccessToken();
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(clientRegistration, principal.getName(),
accessToken, null);
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/").build());
Map<String, Object> attributes = Map.of(ServerWebExchange.class.getName(), exchange,
OidcParameterNames.ID_TOKEN, "id-token-1234");
Map<String, Object> claims = new HashMap<>();
claims.put("iss", principal.getIssuer());
claims.put("sub", principal.getSubject());
claims.put("aud", principal.getAudience());
claims.put("auth_time", authTime);
claims.put("nonce", principal.getNonce());
Jwt jwt = mock(Jwt.class);
given(jwt.getTokenValue()).willReturn("id-token-1234");
given(jwt.getIssuedAt()).willReturn(principal.getIssuedAt());
given(jwt.getClaims()).willReturn(claims);
ReactiveJwtDecoder jwtDecoder = mock(ReactiveJwtDecoder.class);
given(jwtDecoder.decode(any())).willReturn(Mono.just(jwt));
ReactiveJwtDecoderFactory<ClientRegistration> reactiveJwtDecoderFactory = mock(ReactiveJwtDecoderFactory.class);
given(reactiveJwtDecoderFactory.createDecoder(any())).willReturn(jwtDecoder);
ReactiveOAuth2UserService<OidcUserRequest, OidcUser> userService = mock(ReactiveOAuth2UserService.class);
given(userService.loadUser(any())).willReturn(Mono.just(principal));
RefreshOidcUserReactiveOAuth2AuthorizationSuccessHandler handler = new RefreshOidcUserReactiveOAuth2AuthorizationSuccessHandler();
handler.setJwtDecoderFactory(reactiveJwtDecoderFactory);
handler.setUserService(userService);
String originalSessionId = exchange.getSession().map(WebSession::getId).block();
StepVerifier.create(handler.onAuthorizationSuccess(authorizedClient, authenticationToken, attributes))
.verifyComplete();
StepVerifier.create(exchange.getSession())
.assertNext((session) -> assertThat(session.getId()).isEqualTo(originalSessionId))
.verifyComplete();
WebSessionServerSecurityContextRepository securityContextRepository = new WebSessionServerSecurityContextRepository();
StepVerifier.create(securityContextRepository.load(exchange).mapNotNull(SecurityContext::getAuthentication))
.expectNext(authenticationToken)
.verifyComplete();
}
@Test
void onAuthorizationSuccessWhenIdTokenIssuerNotSameThenException() {
ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().build();
@@ -35,7 +35,6 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import reactor.util.context.Context;
import org.springframework.http.HttpHeaders;
@@ -78,7 +77,6 @@ import org.springframework.web.reactive.function.client.ExchangeFunction;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebSession;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -322,8 +320,6 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionITests {
doReturn(Mono.just(authorizedClient)).when(this.authorizedClientRepository)
.loadAuthorizedClient(eq(clientRegistration.getRegistrationId()), eq(this.authentication),
eq(this.exchange));
// Capture the original session id.
String originalSessionId = this.exchange.getSession().map(WebSession::getId).block();
this.webClient.get()
.uri(this.serverUrl)
.attributes(ServletOAuth2AuthorizedClientExchangeFilterFunction
@@ -360,10 +356,6 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionITests {
assertThat(oidcUser.getSubject()).isEqualTo("subject-1234");
assertThat(oidcUser.getName()).isEqualTo("refreshed-username");
});
// Verify that session id was not changed.
StepVerifier.create(this.exchange.getSession())
.assertNext((session) -> assertThat(session.getId()).isEqualTo(originalSessionId))
.verifyComplete();
}
@Test