Update deprecated basic auth client filters.
1. Update ExchangeFilterFunctions to delegate internally to HttpHeaders.setBasicAuth(user, password). 2. Remove deprecation from ExchangeFilterFunctions.basicAuthentication(String user, String password) It is still useful as a filter to insert the header. 3. Update deprecation notes. Issue: SPR-17099
This commit is contained in:
parent
6b82a6c38c
commit
4a18488f30
|
@ -711,8 +711,12 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|||
/**
|
||||
* Set the value of the {@linkplain #AUTHORIZATION Authorization} header to
|
||||
* Basic Authentication based on the given username and password.
|
||||
* <p>Note that Basic Authentication only supports characters in the
|
||||
* {@link StandardCharsets#ISO_8859_1 ISO-8859-1} character set.
|
||||
* @param username the username
|
||||
* @param password the password
|
||||
* @throws IllegalArgumentException if either {@code user} or
|
||||
* {@code password} contain characters that cannot be encoded to ISO-8859-1.
|
||||
* @since 5.1
|
||||
* @see <a href="https://tools.ietf.org/html/rfc7617">RFC 7617</a>
|
||||
*/
|
||||
|
@ -725,8 +729,10 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
|||
* Basic Authentication based on the given username and password.
|
||||
* @param username the username
|
||||
* @param password the password
|
||||
* @param charset the charset to use to convert the credentials into an octet sequence. Defaults
|
||||
* to {@linkplain StandardCharsets#ISO_8859_1 ISO-8859-1}
|
||||
* @param charset the charset to use to convert the credentials into an octet
|
||||
* sequence. Defaults to {@linkplain StandardCharsets#ISO_8859_1 ISO-8859-1}
|
||||
* @throws IllegalArgumentException if either {@code user} or
|
||||
* {@code password} contain characters that cannot be encoded to ISO-8859-1.
|
||||
* @since 5.1
|
||||
* @see <a href="https://tools.ietf.org/html/rfc7617">RFC 7617</a>
|
||||
*/
|
||||
|
|
|
@ -16,11 +16,8 @@
|
|||
|
||||
package org.springframework.web.reactive.function.client;
|
||||
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
@ -46,9 +43,9 @@ import org.springframework.web.reactive.function.BodyExtractors;
|
|||
public abstract class ExchangeFilterFunctions {
|
||||
|
||||
/**
|
||||
* Name of the {@linkplain ClientRequest#attributes() request attribute} that
|
||||
* contains the {@link Credentials} used by {@link #basicAuthentication()}.
|
||||
* @deprecated in favor of {@link HttpHeaders#setBasicAuth(String, String)}
|
||||
* Name of the request attribute with {@link Credentials} for {@link #basicAuthentication()}.
|
||||
* @deprecated as of Spring 5.1 in favor of using
|
||||
* {@link HttpHeaders#setBasicAuth(String, String)} while building the request.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String BASIC_AUTHENTICATION_CREDENTIALS_ATTRIBUTE =
|
||||
|
@ -72,73 +69,6 @@ public abstract class ExchangeFilterFunctions {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a filter for HTTP Basic Authentication that adds an authorization
|
||||
* header, based on the given user and password.
|
||||
* <p>Note that Basic Authentication only supports characters in the
|
||||
* {@link StandardCharsets#ISO_8859_1 ISO-8859-1} character set.
|
||||
* @param user the user
|
||||
* @param password the password
|
||||
* @return the filter for basic authentication
|
||||
* @throws IllegalArgumentException if either {@code user} or
|
||||
* {@code password} contain characters that cannot be encoded to ISO-8859-1.
|
||||
* @deprecated in favor of {@link HttpHeaders#setBasicAuth(String, String)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static ExchangeFilterFunction basicAuthentication(String user, String password) {
|
||||
Assert.notNull(user, "'user' must not be null");
|
||||
Assert.notNull(password, "'password' must not be null");
|
||||
checkIllegalCharacters(user, password);
|
||||
return basicAuthenticationInternal(request -> Optional.of(new Credentials(user, password)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Variant of {@link #basicAuthentication(String, String)} that looks up
|
||||
* the {@link Credentials Credentials} provided in a
|
||||
* {@linkplain ClientRequest#attributes() request attribute}, or if the
|
||||
* attribute is not found, the authorization header is not added.
|
||||
* @return the filter for basic authentication
|
||||
* @see #BASIC_AUTHENTICATION_CREDENTIALS_ATTRIBUTE
|
||||
* @see Credentials#basicAuthenticationCredentials(String, String)
|
||||
* @deprecated as of Spring 5.1, with no direct replacement
|
||||
*/
|
||||
@Deprecated
|
||||
public static ExchangeFilterFunction basicAuthentication() {
|
||||
return basicAuthenticationInternal(request ->
|
||||
request.attribute(BASIC_AUTHENTICATION_CREDENTIALS_ATTRIBUTE)
|
||||
.map(credentials -> (Credentials) credentials));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private static ExchangeFilterFunction basicAuthenticationInternal(
|
||||
Function<ClientRequest, Optional<Credentials>> credentialsFunction) {
|
||||
|
||||
return ExchangeFilterFunction.ofRequestProcessor(request ->
|
||||
credentialsFunction.apply(request)
|
||||
.map(credentials -> Mono.just(insertAuthorizationHeader(request, credentials)))
|
||||
.orElseGet(() -> Mono.just(request)));
|
||||
}
|
||||
|
||||
private static void checkIllegalCharacters(String username, String password) {
|
||||
// Basic authentication only supports ISO 8859-1, see
|
||||
// https://stackoverflow.com/questions/702629/utf-8-characters-mangled-in-http-basic-auth-username#703341
|
||||
CharsetEncoder encoder = StandardCharsets.ISO_8859_1.newEncoder();
|
||||
if (!encoder.canEncode(username) || !encoder.canEncode(password)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Username or password contains characters that cannot be encoded to ISO-8859-1");
|
||||
}
|
||||
}
|
||||
|
||||
private static ClientRequest insertAuthorizationHeader(ClientRequest request, Credentials credentials) {
|
||||
return ClientRequest.from(request).headers(headers -> {
|
||||
String credentialsString = credentials.username + ":" + credentials.password;
|
||||
byte[] credentialBytes = credentialsString.getBytes(StandardCharsets.ISO_8859_1);
|
||||
byte[] encodedBytes = Base64.getEncoder().encode(credentialBytes);
|
||||
String encodedCredentials = new String(encodedBytes, StandardCharsets.ISO_8859_1);
|
||||
headers.set(HttpHeaders.AUTHORIZATION, "Basic " + encodedCredentials);
|
||||
}).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a filter that generates an error signal when the given
|
||||
* {@link HttpStatus} predicate matches.
|
||||
|
@ -157,12 +87,55 @@ public abstract class ExchangeFilterFunctions {
|
|||
Mono.error(exceptionFunction.apply(response)) : Mono.just(response)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a filter that applies HTTP Basic Authentication to the request
|
||||
* headers via {@link HttpHeaders#setBasicAuth(String, String)}.
|
||||
* @param user the user
|
||||
* @param password the password
|
||||
* @return the filter to add authentication headers with
|
||||
* @see HttpHeaders#setBasicAuth(String, String)
|
||||
* @see HttpHeaders#setBasicAuth(String, String, Charset)
|
||||
*/
|
||||
public static ExchangeFilterFunction basicAuthentication(String user, String password) {
|
||||
return (request, next) ->
|
||||
next.exchange(ClientRequest.from(request)
|
||||
.headers(headers -> headers.setBasicAuth(user, password))
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Variant of {@link #basicAuthentication(String, String)} that looks up
|
||||
* the {@link Credentials Credentials} in a
|
||||
* {@link #BASIC_AUTHENTICATION_CREDENTIALS_ATTRIBUTE request attribute}.
|
||||
* @return the filter to use
|
||||
* @see Credentials
|
||||
* @deprecated as of Spring 5.1 in favor of using
|
||||
* {@link HttpHeaders#setBasicAuth(String, String)} while building the request.
|
||||
*/
|
||||
@Deprecated
|
||||
public static ExchangeFilterFunction basicAuthentication() {
|
||||
|
||||
return (request, next) -> {
|
||||
Credentials cred = (Credentials) request
|
||||
.attribute(BASIC_AUTHENTICATION_CREDENTIALS_ATTRIBUTE).orElse(null);
|
||||
|
||||
if (cred != null) {
|
||||
return next.exchange(ClientRequest.from(request)
|
||||
.headers(headers -> headers.setBasicAuth(cred.username, cred.password))
|
||||
.build());
|
||||
}
|
||||
else {
|
||||
return next.exchange(request);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stores user and password for HTTP basic authentication.
|
||||
* @see #basicAuthentication()
|
||||
* @see #basicAuthenticationCredentials(String, String)
|
||||
* @deprecated as of Spring 5.1, with no direct replacement
|
||||
* @deprecated as of Spring 5.1 in favor of using
|
||||
* {@link HttpHeaders#setBasicAuth(String, String)} while building the request.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final class Credentials {
|
||||
|
@ -196,7 +169,6 @@ public abstract class ExchangeFilterFunctions {
|
|||
*/
|
||||
public static Consumer<Map<String, Object>> basicAuthenticationCredentials(String user, String password) {
|
||||
Credentials credentials = new Credentials(user, password);
|
||||
checkIllegalCharacters(user, password);
|
||||
return (map -> map.put(BASIC_AUTHENTICATION_CREDENTIALS_ATTRIBUTE, credentials));
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ import static org.junit.Assert.*;
|
|||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ExchangeFilterFunctions}.
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class ExchangeFilterFunctionsTests {
|
||||
|
@ -94,7 +95,6 @@ public class ExchangeFilterFunctionsTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("deprecation")
|
||||
public void basicAuthenticationUsernamePassword() {
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, DEFAULT_URL).build();
|
||||
ClientResponse response = mock(ClientResponse.class);
|
||||
|
@ -113,8 +113,10 @@ public class ExchangeFilterFunctionsTests {
|
|||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void basicAuthenticationInvalidCharacters() {
|
||||
ClientRequest request = ClientRequest.create(HttpMethod.GET, DEFAULT_URL).build();
|
||||
ExchangeFunction exchange = r -> Mono.just(mock(ClientResponse.class));
|
||||
|
||||
ExchangeFilterFunctions.basicAuthentication("foo", "\ud83d\udca9");
|
||||
ExchangeFilterFunctions.basicAuthentication("foo", "\ud83d\udca9").filter(request, exchange);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue