Add Basic Authentication Consumer
Issue: SPR-16913
This commit is contained in:
@@ -20,6 +20,8 @@ import java.io.Serializable;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.time.Instant;
|
||||
@@ -28,6 +30,7 @@ import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
@@ -38,6 +41,8 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -1564,4 +1569,88 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
|
||||
return (headers.readOnly ? headers : new HttpHeaders(headers, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code HttpHeaders} consumer that adds Basic Authentication.
|
||||
* More specifically: a consumer that adds an {@linkplain #AUTHORIZATION
|
||||
* Authorization} header based on the given username and password. Meant
|
||||
* to be used in combination with
|
||||
* {@link org.springframework.web.reactive.function.client.WebClient.RequestHeadersSpec#headers(java.util.function.Consumer)}.
|
||||
* <p>Note that Basic Authentication only supports characters in the
|
||||
* {@linkplain StandardCharsets#ISO_8859_1 ISO-8859-1} character set.
|
||||
*
|
||||
* @param username the username
|
||||
* @param password the password
|
||||
* @return a consumer that adds a Basic Authentication header
|
||||
*/
|
||||
public static Consumer<HttpHeaders> basicAuthenticationConsumer(String username,String password) {
|
||||
return basicAuthenticationConsumer(() -> username, () -> password);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code HttpHeaders} consumer that adds Basic Authentication.
|
||||
* More specifically: a consumer that adds an {@linkplain #AUTHORIZATION
|
||||
* Authorization} header based on the given username and password
|
||||
* suppliers. Meant to be used in combination with
|
||||
* {@link org.springframework.web.reactive.function.client.WebClient.RequestHeadersSpec#headers(java.util.function.Consumer)}.
|
||||
* <p>Note that Basic Authentication only supports characters in the
|
||||
* {@linkplain StandardCharsets#ISO_8859_1 ISO-8859-1} character set.
|
||||
*
|
||||
* @param usernameSupplier supplier for the username
|
||||
* @param passwordSupplier supplier for the password
|
||||
* @return a consumer that adds a Basic Authentication header
|
||||
*/
|
||||
public static Consumer<HttpHeaders> basicAuthenticationConsumer(Supplier<String> usernameSupplier,
|
||||
Supplier<String> passwordSupplier) {
|
||||
|
||||
Assert.notNull(usernameSupplier, "Username Supplier must not be null");
|
||||
Assert.notNull(passwordSupplier, "Password Supplier must not be null");
|
||||
|
||||
return new BasicAuthenticationConsumer(usernameSupplier, passwordSupplier);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see #basicAuthenticationConsumer
|
||||
*/
|
||||
private static class BasicAuthenticationConsumer implements Consumer<HttpHeaders> {
|
||||
|
||||
private final Supplier<String> usernameSupplier;
|
||||
|
||||
private final Supplier<String> passwordSupplier;
|
||||
|
||||
public BasicAuthenticationConsumer(Supplier<String> usernameSupplier,
|
||||
Supplier<String> passwordSupplier) {
|
||||
this.usernameSupplier = usernameSupplier;
|
||||
this.passwordSupplier = passwordSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(HttpHeaders httpHeaders) {
|
||||
String username = this.usernameSupplier.get();
|
||||
String password = this.passwordSupplier.get();
|
||||
|
||||
Assert.state(username != null, "Supplied username is null");
|
||||
Assert.state(password != null, "Supplied password is null");
|
||||
|
||||
checkIllegalCharacters(username, password);
|
||||
|
||||
String credentialsString = username + ":" + password;
|
||||
byte[] credentialBytes = credentialsString.getBytes(StandardCharsets.ISO_8859_1);
|
||||
byte[] encodedBytes = Base64.getEncoder().encode(credentialBytes);
|
||||
String encodedCredentials = new String(encodedBytes, StandardCharsets.ISO_8859_1);
|
||||
|
||||
httpHeaders.set(HttpHeaders.AUTHORIZATION, "Basic " + encodedCredentials);
|
||||
}
|
||||
|
||||
private static void checkIllegalCharacters(String username, String password) {
|
||||
// Basic authentication only supports ISO 8859-1
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user