Skip to content

Commit 0aa03fc

Browse files
committed
Merge branch 'main' into gh-16038
# Conflicts: # oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java # oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java # oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java
2 parents 80fd041 + 380e856 commit 0aa03fc

File tree

14 files changed

+82
-23
lines changed

14 files changed

+82
-23
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistry.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@ public C requestMatchers(RequestMatcher... requestMatchers) {
199199
* @since 5.8
200200
*/
201201
public C requestMatchers(HttpMethod method, String... patterns) {
202+
if (anyPathsDontStartWithLeadingSlash(patterns)) {
203+
this.logger.warn("One of the patterns in " + Arrays.toString(patterns)
204+
+ " is missing a leading slash. This is discouraged; please include the "
205+
+ "leading slash in all your request matcher patterns. In future versions of "
206+
+ "Spring Security, leaving out the leading slash will result in an exception.");
207+
}
202208
if (!mvcPresent) {
203209
return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
204210
}
@@ -219,6 +225,15 @@ public C requestMatchers(HttpMethod method, String... patterns) {
219225
return requestMatchers(matchers.toArray(new RequestMatcher[0]));
220226
}
221227

228+
private boolean anyPathsDontStartWithLeadingSlash(String... patterns) {
229+
for (String pattern : patterns) {
230+
if (!pattern.startsWith("/")) {
231+
return true;
232+
}
233+
}
234+
return false;
235+
}
236+
222237
private RequestMatcher resolve(AntPathRequestMatcher ant, MvcRequestMatcher mvc, ServletContext servletContext) {
223238
Map<String, ? extends ServletRegistration> registrations = mappableServletRegistrations(servletContext);
224239
if (registrations.isEmpty()) {

docs/modules/ROOT/pages/servlet/saml2/login/authentication.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ public class SecurityConfig {
139139
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
140140
OpenSaml4AuthenticationProvider authenticationProvider = new OpenSaml4AuthenticationProvider();
141141
authenticationProvider.setAssertionValidator(OpenSaml4AuthenticationProvider
142-
.createDefaultAssertionValidator(assertionToken -> {
142+
.createDefaultAssertionValidatorWithParameters(assertionToken -> {
143143
Map<String, Object> params = new HashMap<>();
144144
params.put(CLOCK_SKEW, Duration.ofMinutes(10).toMillis());
145145
// ... other validation parameters
@@ -171,7 +171,7 @@ open class SecurityConfig {
171171
val authenticationProvider = OpenSaml4AuthenticationProvider()
172172
authenticationProvider.setAssertionValidator(
173173
OpenSaml4AuthenticationProvider
174-
.createDefaultAssertionValidator(Converter<OpenSaml4AuthenticationProvider.AssertionToken, ValidationContext> {
174+
.createDefaultAssertionValidatorWithParameters(Converter<OpenSaml4AuthenticationProvider.AssertionToken, ValidationContext> {
175175
val params: MutableMap<String, Any> = HashMap()
176176
params[CLOCK_SKEW] =
177177
Duration.ofMinutes(10).toMillis()

docs/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"dependencies": {
33
"antora": "3.2.0-alpha.6",
44
"@antora/atlas-extension": "1.0.0-alpha.2",
5-
"@antora/collector-extension": "1.0.0-beta.3",
5+
"@antora/collector-extension": "1.0.0-beta.4",
66
"@asciidoctor/tabs": "1.0.0-beta.6",
77
"@springio/antora-extensions": "1.14.2",
88
"@springio/asciidoctor-extensions": "1.0.0-alpha.14"

gradle/libs.versions.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jakarta-websocket = "2.2.0"
77
org-apache-directory-server = "1.5.5"
88
org-apache-maven-resolver = "1.9.22"
99
org-aspectj = "1.9.22.1"
10-
org-bouncycastle = "1.78.1"
10+
org-bouncycastle = "1.79"
1111
org-eclipse-jetty = "11.0.24"
1212
org-jetbrains-kotlin = "1.9.25"
1313
org-jetbrains-kotlinx = "1.9.0"
@@ -71,7 +71,7 @@ org-eclipse-jetty-jetty-server = { module = "org.eclipse.jetty:jetty-server", ve
7171
org-eclipse-jetty-jetty-servlet = { module = "org.eclipse.jetty:jetty-servlet", version.ref = "org-eclipse-jetty" }
7272
org-hamcrest = "org.hamcrest:hamcrest:2.2"
7373
org-hibernate-orm-hibernate-core = "org.hibernate.orm:hibernate-core:6.6.1.Final"
74-
org-hsqldb = "org.hsqldb:hsqldb:2.7.3"
74+
org-hsqldb = "org.hsqldb:hsqldb:2.7.4"
7575
org-jetbrains-kotlin-kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "org-jetbrains-kotlin" }
7676
org-jetbrains-kotlin-kotlin-gradle-plugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25"
7777
org-jetbrains-kotlinx-kotlinx-coroutines-bom = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-bom", version.ref = "org-jetbrains-kotlinx" }
@@ -83,7 +83,7 @@ org-opensaml-opensaml5-saml-api = { module = "org.opensaml:opensaml-saml-api", v
8383
org-opensaml-opensaml5-saml-impl = { module = "org.opensaml:opensaml-saml-impl", version.ref = "org-opensaml5" }
8484
org-python-jython = { module = "org.python:jython", version = "2.5.3" }
8585
org-seleniumhq-selenium-htmlunit-driver = "org.seleniumhq.selenium:htmlunit3-driver:4.25.0"
86-
org-seleniumhq-selenium-selenium-java = "org.seleniumhq.selenium:selenium-java:4.25.0"
86+
org-seleniumhq-selenium-selenium-java = "org.seleniumhq.selenium:selenium-java:4.26.0"
8787
org-seleniumhq-selenium-selenium-support = "org.seleniumhq.selenium:selenium-support:3.141.59"
8888
org-skyscreamer-jsonassert = "org.skyscreamer:jsonassert:1.5.3"
8989
org-slf4j-log4j-over-slf4j = "org.slf4j:log4j-over-slf4j:1.7.36"
@@ -107,7 +107,7 @@ org-jfrog-buildinfo-build-info-extractor-gradle = "org.jfrog.buildinfo:build-inf
107107
org-sonarsource-scanner-gradle-sonarqube-gradle-plugin = "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8.0.1969"
108108
org-instancio-instancio-junit = "org.instancio:instancio-junit:3.7.1"
109109

110-
webauthn4j-core = 'com.webauthn4j:webauthn4j-core:0.27.0.RELEASE'
110+
webauthn4j-core = 'com.webauthn4j:webauthn4j-core:0.28.0.RELEASE'
111111

112112
[plugins]
113113

oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,17 @@ public String resolve(final HttpServletRequest request) {
5757
? resolveFromRequestParameters(request) : null;
5858
if (authorizationHeaderToken != null) {
5959
if (parameterToken != null) {
60-
final BearerTokenError error = BearerTokenErrors
60+
BearerTokenError error = BearerTokenErrors
6161
.invalidRequest("Found multiple bearer tokens in the request");
6262
throw new OAuth2AuthenticationException(error);
6363
}
6464
return authorizationHeaderToken;
6565
}
66+
if (parameterToken != null && !StringUtils.hasText(parameterToken)) {
67+
BearerTokenError error = BearerTokenErrors
68+
.invalidRequest("The requested token parameter is an empty string");
69+
throw new OAuth2AuthenticationException(error);
70+
}
6671
return parameterToken;
6772
}
6873

oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverter.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ private String token(ServerHttpRequest request) {
7777
}
7878
return authorizationHeaderToken;
7979
}
80+
if (parameterToken != null && !StringUtils.hasText(parameterToken)) {
81+
BearerTokenError error = BearerTokenErrors
82+
.invalidRequest("The requested token parameter is an empty string");
83+
throw new OAuth2AuthenticationException(error);
84+
}
8085
return parameterToken;
8186
}
8287

oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@
2121
import org.junit.jupiter.api.BeforeEach;
2222
import org.junit.jupiter.api.Test;
2323

24+
import org.springframework.http.HttpStatus;
2425
import org.springframework.mock.web.MockHttpServletRequest;
2526
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
27+
import org.springframework.security.oauth2.server.resource.BearerTokenError;
28+
import org.springframework.security.oauth2.server.resource.BearerTokenErrorCodes;
2629

2730
import static org.assertj.core.api.Assertions.assertThat;
2831
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -285,4 +288,35 @@ void resolveWhenRequestContainsTwoAccessTokenQueryParameterAndSupportIsDisabledT
285288
assertThat(this.resolver.resolve(request)).isNull();
286289
}
287290

291+
@Test
292+
public void resolveWhenQueryParameterIsPresentAndEmptyStringThenTokenIsNotResolved() {
293+
this.resolver.setAllowUriQueryParameter(true);
294+
MockHttpServletRequest request = new MockHttpServletRequest();
295+
request.setMethod("GET");
296+
request.addParameter("access_token", "");
297+
assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> this.resolver.resolve(request))
298+
.withMessageContaining("The requested token parameter is an empty string")
299+
.satisfies((e) -> {
300+
BearerTokenError error = (BearerTokenError) e.getError();
301+
assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_REQUEST);
302+
assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.BAD_REQUEST);
303+
});
304+
}
305+
306+
@Test
307+
public void resolveWhenFormParameterIsPresentAndEmptyStringThenTokenIsNotResolved() {
308+
this.resolver.setAllowFormEncodedBodyParameter(true);
309+
MockHttpServletRequest request = new MockHttpServletRequest();
310+
request.setMethod("POST");
311+
request.setContentType("application/x-www-form-urlencoded");
312+
request.addParameter("access_token", "");
313+
assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> this.resolver.resolve(request))
314+
.withMessageContaining("The requested token parameter is an empty string")
315+
.satisfies((e) -> {
316+
BearerTokenError error = (BearerTokenError) e.getError();
317+
assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_REQUEST);
318+
assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.BAD_REQUEST);
319+
});
320+
}
321+
288322
}

oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/authentication/ServerBearerTokenAuthenticationConverterTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,9 @@ public void resolveWhenQueryParameterIsEmptyAndSupportedThenOAuth2Authentication
188188
.isThrownBy(() -> convertToToken(request))
189189
.satisfies((ex) -> {
190190
BearerTokenError error = (BearerTokenError) ex.getError();
191-
assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_TOKEN);
191+
assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_REQUEST);
192192
assertThat(error.getUri()).isEqualTo("https://tools.ietf.org/html/rfc6750#section-3.1");
193-
assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.UNAUTHORIZED);
193+
assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.BAD_REQUEST);
194194
});
195195
// @formatter:on
196196
}

web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ protected void successfulAuthentication(HttpServletRequest request, HttpServletR
338338
* <ol>
339339
* <li>Clears the {@link SecurityContextHolder}</li>
340340
* <li>Stores the exception in the session (if it exists or
341-
* <tt>allowSesssionCreation</tt> is set to <tt>true</tt>)</li>
341+
* <tt>allowSessionCreation</tt> is set to <tt>true</tt>)</li>
342342
* <li>Informs the configured <tt>RememberMeServices</tt> of the failed login</li>
343343
* <li>Delegates additional behaviour to the
344344
* {@link AuthenticationFailureHandler}.</li>

web/src/main/java/org/springframework/security/web/authentication/session/ConcurrentSessionControlAuthenticationStrategy.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -174,7 +174,7 @@ public void setExceptionIfMaximumExceeded(boolean exceptionIfMaximumExceeded) {
174174
/**
175175
* Sets the <tt>maxSessions</tt> property. The default value is 1. Use -1 for
176176
* unlimited sessions.
177-
* @param maximumSessions the maximimum number of permitted sessions a user can have
177+
* @param maximumSessions the maximum number of permitted sessions a user can have
178178
* open simultaneously.
179179
*/
180180
public void setMaximumSessions(int maximumSessions) {

0 commit comments

Comments
 (0)