Polish gh-16039
CI / Build (17, ubuntu-latest) (push) Has been cancelled
Details
CI / Build (17, windows-latest) (push) Has been cancelled
Details
CI / Test Against Snapshots (17, 17) (push) Has been cancelled
Details
CI / Test Against Snapshots (21-ea, 21) (push) Has been cancelled
Details
CI / Check Samples (push) Has been cancelled
Details
Deploy Docs / build (push) Has been cancelled
Details
Trigger Dependabot Auto Merge Forward / Trigger Workflow (push) Has been cancelled
Details
CI / Deploy Artifacts (push) Has been cancelled
Details
CI / Deploy Docs (push) Has been cancelled
Details
CI / Deploy Schema (push) Has been cancelled
Details
CI / Perform Release (push) Has been cancelled
Details
CI / Send Notification (push) Has been cancelled
Details
CI / Build (17, ubuntu-latest) (push) Has been cancelled
Details
CI / Build (17, windows-latest) (push) Has been cancelled
Details
CI / Test Against Snapshots (17, 17) (push) Has been cancelled
Details
CI / Test Against Snapshots (21-ea, 21) (push) Has been cancelled
Details
CI / Check Samples (push) Has been cancelled
Details
Deploy Docs / build (push) Has been cancelled
Details
Trigger Dependabot Auto Merge Forward / Trigger Workflow (push) Has been cancelled
Details
CI / Deploy Artifacts (push) Has been cancelled
Details
CI / Deploy Docs (push) Has been cancelled
Details
CI / Deploy Schema (push) Has been cancelled
Details
CI / Perform Release (push) Has been cancelled
Details
CI / Send Notification (push) Has been cancelled
Details
Closes gh-16038
This commit is contained in:
parent
da94fbe431
commit
3c0fef59b5
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -52,23 +52,77 @@ public final class DefaultBearerTokenResolver implements BearerTokenResolver {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String resolve(final HttpServletRequest request) {
|
public String resolve(final HttpServletRequest request) {
|
||||||
final String authorizationHeaderToken = resolveFromAuthorizationHeader(request);
|
// @formatter:off
|
||||||
final String parameterToken = resolveFromRequestParameters(request);
|
return resolveToken(
|
||||||
|
resolveFromAuthorizationHeader(request),
|
||||||
|
resolveAccessTokenFromQueryString(request),
|
||||||
|
resolveAccessTokenFromBody(request)
|
||||||
|
);
|
||||||
|
// @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
if (authorizationHeaderToken != null) {
|
private static String resolveToken(String... accessTokens) {
|
||||||
if (parameterToken != null) {
|
if (accessTokens == null || accessTokens.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String accessToken = null;
|
||||||
|
for (String token : accessTokens) {
|
||||||
|
if (accessToken == null) {
|
||||||
|
accessToken = token;
|
||||||
|
}
|
||||||
|
else if (token != null) {
|
||||||
BearerTokenError error = BearerTokenErrors
|
BearerTokenError error = BearerTokenErrors
|
||||||
.invalidRequest("Found multiple bearer tokens in the request");
|
.invalidRequest("Found multiple bearer tokens in the request");
|
||||||
throw new OAuth2AuthenticationException(error);
|
throw new OAuth2AuthenticationException(error);
|
||||||
}
|
}
|
||||||
return authorizationHeaderToken;
|
|
||||||
}
|
}
|
||||||
if (parameterToken != null && parameterToken.isBlank()) {
|
|
||||||
|
if (accessToken != null && accessToken.isBlank()) {
|
||||||
BearerTokenError error = BearerTokenErrors
|
BearerTokenError error = BearerTokenErrors
|
||||||
.invalidRequest("The requested token parameter is an empty string");
|
.invalidRequest("The requested token parameter is an empty string");
|
||||||
throw new OAuth2AuthenticationException(error);
|
throw new OAuth2AuthenticationException(error);
|
||||||
}
|
}
|
||||||
return parameterToken;
|
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveFromAuthorizationHeader(HttpServletRequest request) {
|
||||||
|
String authorization = request.getHeader(this.bearerTokenHeaderName);
|
||||||
|
if (!StringUtils.startsWithIgnoreCase(authorization, "bearer")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matcher matcher = authorizationPattern.matcher(authorization);
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
BearerTokenError error = BearerTokenErrors.invalidToken("Bearer token is malformed");
|
||||||
|
throw new OAuth2AuthenticationException(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return matcher.group("token");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveAccessTokenFromQueryString(HttpServletRequest request) {
|
||||||
|
if (!this.allowUriQueryParameter || !HttpMethod.GET.name().equals(request.getMethod())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolveToken(request.getParameterValues(ACCESS_TOKEN_PARAMETER_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveAccessTokenFromBody(HttpServletRequest request) {
|
||||||
|
if (!this.allowFormEncodedBodyParameter
|
||||||
|
|| !MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(request.getContentType())
|
||||||
|
|| HttpMethod.GET.name().equals(request.getMethod())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String queryString = request.getQueryString();
|
||||||
|
if (queryString != null && queryString.contains(ACCESS_TOKEN_PARAMETER_NAME)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolveToken(request.getParameterValues(ACCESS_TOKEN_PARAMETER_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,49 +160,4 @@ public final class DefaultBearerTokenResolver implements BearerTokenResolver {
|
||||||
this.bearerTokenHeaderName = bearerTokenHeaderName;
|
this.bearerTokenHeaderName = bearerTokenHeaderName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String resolveFromAuthorizationHeader(HttpServletRequest request) {
|
|
||||||
String authorization = request.getHeader(this.bearerTokenHeaderName);
|
|
||||||
if (!StringUtils.startsWithIgnoreCase(authorization, "bearer")) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Matcher matcher = authorizationPattern.matcher(authorization);
|
|
||||||
if (!matcher.matches()) {
|
|
||||||
BearerTokenError error = BearerTokenErrors.invalidToken("Bearer token is malformed");
|
|
||||||
throw new OAuth2AuthenticationException(error);
|
|
||||||
}
|
|
||||||
return matcher.group("token");
|
|
||||||
}
|
|
||||||
|
|
||||||
private String resolveFromRequestParameters(HttpServletRequest request) {
|
|
||||||
if (!isParameterTokenEnabledForRequest(request)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String[] values = request.getParameterValues(ACCESS_TOKEN_PARAMETER_NAME);
|
|
||||||
if (values == null || values.length == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (values.length == 1) {
|
|
||||||
return values[0];
|
|
||||||
}
|
|
||||||
BearerTokenError error = BearerTokenErrors.invalidRequest("Found multiple bearer tokens in the request");
|
|
||||||
throw new OAuth2AuthenticationException(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isGetRequest(HttpServletRequest request) {
|
|
||||||
return HttpMethod.GET.name().equals(request.getMethod());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isFormEncodedRequest(HttpServletRequest request) {
|
|
||||||
return MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(request.getContentType());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean hasAccessTokenInQueryString(HttpServletRequest request) {
|
|
||||||
return (request.getQueryString() != null) && request.getQueryString().contains(ACCESS_TOKEN_PARAMETER_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isParameterTokenEnabledForRequest(HttpServletRequest request) {
|
|
||||||
return ((this.allowFormEncodedBodyParameter && isFormEncodedRequest(request) && !isGetRequest(request)
|
|
||||||
&& !hasAccessTokenInQueryString(request)) || (this.allowUriQueryParameter && isGetRequest(request)));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -237,6 +237,19 @@ public class DefaultBearerTokenResolverTests {
|
||||||
assertThat(this.resolver.resolve(request)).isNull();
|
assertThat(this.resolver.resolve(request)).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void resolveWhenPostAndQueryParameterIsSupportedAndFormParameterIsPresentThenTokenIsNotResolved() {
|
||||||
|
this.resolver.setAllowUriQueryParameter(true);
|
||||||
|
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request.setMethod("POST");
|
||||||
|
request.setContentType("application/x-www-form-urlencoded");
|
||||||
|
request.setQueryString("access_token=" + TEST_TOKEN);
|
||||||
|
request.addParameter("access_token", TEST_TOKEN);
|
||||||
|
|
||||||
|
assertThat(this.resolver.resolve(request)).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resolveWhenFormParameterIsPresentAndNotSupportedThenTokenIsNotResolved() {
|
public void resolveWhenFormParameterIsPresentAndNotSupportedThenTokenIsNotResolved() {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
@ -267,7 +280,7 @@ public class DefaultBearerTokenResolverTests {
|
||||||
|
|
||||||
// gh-16038
|
// gh-16038
|
||||||
@Test
|
@Test
|
||||||
void resolveWhenRequestContainsTwoAccessTokenFormParametersAndSupportIsDisabledThenTokenIsNotResolved() {
|
public void resolveWhenRequestContainsTwoAccessTokenFormParametersAndSupportIsDisabledThenTokenIsNotResolved() {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
request.setMethod("POST");
|
request.setMethod("POST");
|
||||||
request.setContentType("application/x-www-form-urlencoded");
|
request.setContentType("application/x-www-form-urlencoded");
|
||||||
|
@ -277,7 +290,7 @@ public class DefaultBearerTokenResolverTests {
|
||||||
|
|
||||||
// gh-16038
|
// gh-16038
|
||||||
@Test
|
@Test
|
||||||
void resolveWhenRequestContainsTwoAccessTokenQueryParametersAndSupportIsDisabledThenTokenIsNotResolved() {
|
public void resolveWhenRequestContainsTwoAccessTokenQueryParametersAndSupportIsDisabledThenTokenIsNotResolved() {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
request.setMethod("GET");
|
request.setMethod("GET");
|
||||||
request.addParameter("access_token", "token1", "token2");
|
request.addParameter("access_token", "token1", "token2");
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
Loading…
Reference in New Issue