Skip to content

Commit 3c0fef5

Browse files
committed
Polish gh-16039
Closes gh-16038
1 parent da94fbe commit 3c0fef5

File tree

5 files changed

+80
-58
lines changed

5 files changed

+80
-58
lines changed

config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2025 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.

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

+61-52
Original file line numberDiff line numberDiff line change
@@ -52,23 +52,77 @@ public final class DefaultBearerTokenResolver implements BearerTokenResolver {
5252

5353
@Override
5454
public String resolve(final HttpServletRequest request) {
55-
final String authorizationHeaderToken = resolveFromAuthorizationHeader(request);
56-
final String parameterToken = resolveFromRequestParameters(request);
55+
// @formatter:off
56+
return resolveToken(
57+
resolveFromAuthorizationHeader(request),
58+
resolveAccessTokenFromQueryString(request),
59+
resolveAccessTokenFromBody(request)
60+
);
61+
// @formatter:on
62+
}
63+
64+
private static String resolveToken(String... accessTokens) {
65+
if (accessTokens == null || accessTokens.length == 0) {
66+
return null;
67+
}
5768

58-
if (authorizationHeaderToken != null) {
59-
if (parameterToken != null) {
69+
String accessToken = null;
70+
for (String token : accessTokens) {
71+
if (accessToken == null) {
72+
accessToken = token;
73+
}
74+
else if (token != null) {
6075
BearerTokenError error = BearerTokenErrors
6176
.invalidRequest("Found multiple bearer tokens in the request");
6277
throw new OAuth2AuthenticationException(error);
6378
}
64-
return authorizationHeaderToken;
6579
}
66-
if (parameterToken != null && parameterToken.isBlank()) {
80+
81+
if (accessToken != null && accessToken.isBlank()) {
6782
BearerTokenError error = BearerTokenErrors
6883
.invalidRequest("The requested token parameter is an empty string");
6984
throw new OAuth2AuthenticationException(error);
7085
}
71-
return parameterToken;
86+
87+
return accessToken;
88+
}
89+
90+
private String resolveFromAuthorizationHeader(HttpServletRequest request) {
91+
String authorization = request.getHeader(this.bearerTokenHeaderName);
92+
if (!StringUtils.startsWithIgnoreCase(authorization, "bearer")) {
93+
return null;
94+
}
95+
96+
Matcher matcher = authorizationPattern.matcher(authorization);
97+
if (!matcher.matches()) {
98+
BearerTokenError error = BearerTokenErrors.invalidToken("Bearer token is malformed");
99+
throw new OAuth2AuthenticationException(error);
100+
}
101+
102+
return matcher.group("token");
103+
}
104+
105+
private String resolveAccessTokenFromQueryString(HttpServletRequest request) {
106+
if (!this.allowUriQueryParameter || !HttpMethod.GET.name().equals(request.getMethod())) {
107+
return null;
108+
}
109+
110+
return resolveToken(request.getParameterValues(ACCESS_TOKEN_PARAMETER_NAME));
111+
}
112+
113+
private String resolveAccessTokenFromBody(HttpServletRequest request) {
114+
if (!this.allowFormEncodedBodyParameter
115+
|| !MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(request.getContentType())
116+
|| HttpMethod.GET.name().equals(request.getMethod())) {
117+
return null;
118+
}
119+
120+
String queryString = request.getQueryString();
121+
if (queryString != null && queryString.contains(ACCESS_TOKEN_PARAMETER_NAME)) {
122+
return null;
123+
}
124+
125+
return resolveToken(request.getParameterValues(ACCESS_TOKEN_PARAMETER_NAME));
72126
}
73127

74128
/**
@@ -106,49 +160,4 @@ public void setBearerTokenHeaderName(String bearerTokenHeaderName) {
106160
this.bearerTokenHeaderName = bearerTokenHeaderName;
107161
}
108162

109-
private String resolveFromAuthorizationHeader(HttpServletRequest request) {
110-
String authorization = request.getHeader(this.bearerTokenHeaderName);
111-
if (!StringUtils.startsWithIgnoreCase(authorization, "bearer")) {
112-
return null;
113-
}
114-
Matcher matcher = authorizationPattern.matcher(authorization);
115-
if (!matcher.matches()) {
116-
BearerTokenError error = BearerTokenErrors.invalidToken("Bearer token is malformed");
117-
throw new OAuth2AuthenticationException(error);
118-
}
119-
return matcher.group("token");
120-
}
121-
122-
private String resolveFromRequestParameters(HttpServletRequest request) {
123-
if (!isParameterTokenEnabledForRequest(request)) {
124-
return null;
125-
}
126-
String[] values = request.getParameterValues(ACCESS_TOKEN_PARAMETER_NAME);
127-
if (values == null || values.length == 0) {
128-
return null;
129-
}
130-
if (values.length == 1) {
131-
return values[0];
132-
}
133-
BearerTokenError error = BearerTokenErrors.invalidRequest("Found multiple bearer tokens in the request");
134-
throw new OAuth2AuthenticationException(error);
135-
}
136-
137-
private static boolean isGetRequest(HttpServletRequest request) {
138-
return HttpMethod.GET.name().equals(request.getMethod());
139-
}
140-
141-
private static boolean isFormEncodedRequest(HttpServletRequest request) {
142-
return MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(request.getContentType());
143-
}
144-
145-
private static boolean hasAccessTokenInQueryString(HttpServletRequest request) {
146-
return (request.getQueryString() != null) && request.getQueryString().contains(ACCESS_TOKEN_PARAMETER_NAME);
147-
}
148-
149-
private boolean isParameterTokenEnabledForRequest(HttpServletRequest request) {
150-
return ((this.allowFormEncodedBodyParameter && isFormEncodedRequest(request) && !isGetRequest(request)
151-
&& !hasAccessTokenInQueryString(request)) || (this.allowUriQueryParameter && isGetRequest(request)));
152-
}
153-
154163
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 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.

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

+16-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 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.
@@ -237,6 +237,19 @@ public void resolveWhenPostAndFormParameterIsSupportedAndQueryParameterIsPresent
237237
assertThat(this.resolver.resolve(request)).isNull();
238238
}
239239

240+
@Test
241+
public void resolveWhenPostAndQueryParameterIsSupportedAndFormParameterIsPresentThenTokenIsNotResolved() {
242+
this.resolver.setAllowUriQueryParameter(true);
243+
244+
MockHttpServletRequest request = new MockHttpServletRequest();
245+
request.setMethod("POST");
246+
request.setContentType("application/x-www-form-urlencoded");
247+
request.setQueryString("access_token=" + TEST_TOKEN);
248+
request.addParameter("access_token", TEST_TOKEN);
249+
250+
assertThat(this.resolver.resolve(request)).isNull();
251+
}
252+
240253
@Test
241254
public void resolveWhenFormParameterIsPresentAndNotSupportedThenTokenIsNotResolved() {
242255
MockHttpServletRequest request = new MockHttpServletRequest();
@@ -267,7 +280,7 @@ public void resolveWhenQueryParameterIsPresentAndNotSupportedThenTokenIsNotResol
267280

268281
// gh-16038
269282
@Test
270-
void resolveWhenRequestContainsTwoAccessTokenFormParametersAndSupportIsDisabledThenTokenIsNotResolved() {
283+
public void resolveWhenRequestContainsTwoAccessTokenFormParametersAndSupportIsDisabledThenTokenIsNotResolved() {
271284
MockHttpServletRequest request = new MockHttpServletRequest();
272285
request.setMethod("POST");
273286
request.setContentType("application/x-www-form-urlencoded");
@@ -277,7 +290,7 @@ void resolveWhenRequestContainsTwoAccessTokenFormParametersAndSupportIsDisabledT
277290

278291
// gh-16038
279292
@Test
280-
void resolveWhenRequestContainsTwoAccessTokenQueryParametersAndSupportIsDisabledThenTokenIsNotResolved() {
293+
public void resolveWhenRequestContainsTwoAccessTokenQueryParametersAndSupportIsDisabledThenTokenIsNotResolved() {
281294
MockHttpServletRequest request = new MockHttpServletRequest();
282295
request.setMethod("GET");
283296
request.addParameter("access_token", "token1", "token2");

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 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.

0 commit comments

Comments
 (0)