Selaa lähdekoodia

Use configurable charset in ServerHttpBasicAuthenticationConverter

Closes gh-10903
David Kirstein 3 vuotta sitten
vanhempi
commit
1b29c43a11

+ 16 - 3
web/src/main/java/org/springframework/security/web/server/ServerHttpBasicAuthenticationConverter.java

@@ -16,6 +16,8 @@
 
 package org.springframework.security.web.server;
 
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.util.Base64;
 import java.util.function.Function;
 
@@ -25,6 +27,7 @@ import org.springframework.http.HttpHeaders;
 import org.springframework.http.server.reactive.ServerHttpRequest;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
+import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 import org.springframework.web.server.ServerWebExchange;
 
@@ -43,6 +46,8 @@ public class ServerHttpBasicAuthenticationConverter implements Function<ServerWe
 
 	public static final String BASIC = "Basic ";
 
+	private Charset credentialsCharset = StandardCharsets.UTF_8;
+
 	@Override
 	@Deprecated
 	public Mono<Authentication> apply(ServerWebExchange exchange) {
@@ -51,9 +56,8 @@ public class ServerHttpBasicAuthenticationConverter implements Function<ServerWe
 		if (!StringUtils.startsWithIgnoreCase(authorization, "basic ")) {
 			return Mono.empty();
 		}
-		String credentials = (authorization.length() <= BASIC.length()) ? ""
-				: authorization.substring(BASIC.length(), authorization.length());
-		String decoded = new String(base64Decode(credentials));
+		String credentials = (authorization.length() <= BASIC.length()) ? "" : authorization.substring(BASIC.length());
+		String decoded = new String(base64Decode(credentials), this.credentialsCharset);
 		String[] parts = decoded.split(":", 2);
 		if (parts.length != 2) {
 			return Mono.empty();
@@ -70,4 +74,13 @@ public class ServerHttpBasicAuthenticationConverter implements Function<ServerWe
 		}
 	}
 
+	public Charset getCredentialsCharset() {
+		return this.credentialsCharset;
+	}
+
+	public void setCredentialsCharset(Charset credentialsCharset) {
+		Assert.notNull(credentialsCharset, "credentialsCharset cannot be null");
+		this.credentialsCharset = credentialsCharset;
+	}
+
 }

+ 35 - 1
web/src/test/java/org/springframework/security/web/server/authentication/ServerHttpBasicAuthenticationConverterTests.java

@@ -16,6 +16,8 @@
 
 package org.springframework.security.web.server.authentication;
 
+import java.nio.charset.StandardCharsets;
+
 import org.junit.jupiter.api.Test;
 import reactor.core.publisher.Mono;
 
@@ -62,7 +64,7 @@ public class ServerHttpBasicAuthenticationConverterTests {
 	}
 
 	@Test
-	public void applyWhenNoSemicolonThenEmpty() {
+	public void applyWhenNoColonThenEmpty() {
 		Mono<Authentication> result = apply(this.request.header(HttpHeaders.AUTHORIZATION, "Basic dXNlcg=="));
 		assertThat(result.block()).isNull();
 	}
@@ -104,6 +106,38 @@ public class ServerHttpBasicAuthenticationConverterTests {
 		assertThat(result.block()).isNull();
 	}
 
+	@Test
+	public void applyWhenNonAsciiThenAuthentication() {
+		Mono<Authentication> result = apply(
+				this.request.header(HttpHeaders.AUTHORIZATION, "Basic w7xzZXI6cGFzc3fDtnJk"));
+		UsernamePasswordAuthenticationToken authentication = result.cast(UsernamePasswordAuthenticationToken.class)
+				.block();
+		assertThat(authentication.getPrincipal()).isEqualTo("üser");
+		assertThat(authentication.getCredentials()).isEqualTo("passwörd");
+	}
+
+	@Test
+	public void applyWhenIsoOnlyAsciiThenAuthentication() {
+		this.converter.setCredentialsCharset(StandardCharsets.ISO_8859_1);
+		Mono<Authentication> result = apply(
+				this.request.header(HttpHeaders.AUTHORIZATION, "Basic dXNlcjpwYXNzd29yZA=="));
+		UsernamePasswordAuthenticationToken authentication = result.cast(UsernamePasswordAuthenticationToken.class)
+				.block();
+		assertThat(authentication.getPrincipal()).isEqualTo("user");
+		assertThat(authentication.getCredentials()).isEqualTo("password");
+	}
+
+	@Test
+	public void applyWhenIsoNonAsciiThenAuthentication() {
+		this.converter.setCredentialsCharset(StandardCharsets.ISO_8859_1);
+		Mono<Authentication> result = apply(
+				this.request.header(HttpHeaders.AUTHORIZATION, "Basic /HNlcjpwYXNzd/ZyZA=="));
+		UsernamePasswordAuthenticationToken authentication = result.cast(UsernamePasswordAuthenticationToken.class)
+				.block();
+		assertThat(authentication.getPrincipal()).isEqualTo("üser");
+		assertThat(authentication.getCredentials()).isEqualTo("passwörd");
+	}
+
 	private Mono<Authentication> apply(MockServerHttpRequest.BaseBuilder<?> request) {
 		return this.converter.convert(MockServerWebExchange.from(this.request.build()));
 	}