Skip to content

Commit 2b6bc5d

Browse files
frozeniceSteve Riesenberg
authored and
Steve Riesenberg
committed
Use configurable charset in ServerHttpBasicAuthenticationConverter
Closes gh-10903
1 parent 428216b commit 2b6bc5d

File tree

2 files changed

+51
-4
lines changed

2 files changed

+51
-4
lines changed

web/src/main/java/org/springframework/security/web/server/ServerHttpBasicAuthenticationConverter.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.security.web.server;
1818

19+
import java.nio.charset.Charset;
20+
import java.nio.charset.StandardCharsets;
1921
import java.util.Base64;
2022
import java.util.function.Function;
2123

@@ -25,6 +27,7 @@
2527
import org.springframework.http.server.reactive.ServerHttpRequest;
2628
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
2729
import org.springframework.security.core.Authentication;
30+
import org.springframework.util.Assert;
2831
import org.springframework.util.StringUtils;
2932
import org.springframework.web.server.ServerWebExchange;
3033

@@ -43,6 +46,8 @@ public class ServerHttpBasicAuthenticationConverter implements Function<ServerWe
4346

4447
public static final String BASIC = "Basic ";
4548

49+
private Charset credentialsCharset = StandardCharsets.UTF_8;
50+
4651
@Override
4752
@Deprecated
4853
public Mono<Authentication> apply(ServerWebExchange exchange) {
@@ -51,9 +56,8 @@ public Mono<Authentication> apply(ServerWebExchange exchange) {
5156
if (!StringUtils.startsWithIgnoreCase(authorization, "basic ")) {
5257
return Mono.empty();
5358
}
54-
String credentials = (authorization.length() <= BASIC.length()) ? ""
55-
: authorization.substring(BASIC.length(), authorization.length());
56-
String decoded = new String(base64Decode(credentials));
59+
String credentials = (authorization.length() <= BASIC.length()) ? "" : authorization.substring(BASIC.length());
60+
String decoded = new String(base64Decode(credentials), this.credentialsCharset);
5761
String[] parts = decoded.split(":", 2);
5862
if (parts.length != 2) {
5963
return Mono.empty();
@@ -70,4 +74,13 @@ private byte[] base64Decode(String value) {
7074
}
7175
}
7276

77+
public Charset getCredentialsCharset() {
78+
return this.credentialsCharset;
79+
}
80+
81+
public void setCredentialsCharset(Charset credentialsCharset) {
82+
Assert.notNull(credentialsCharset, "credentialsCharset cannot be null");
83+
this.credentialsCharset = credentialsCharset;
84+
}
85+
7386
}

web/src/test/java/org/springframework/security/web/server/authentication/ServerHttpBasicAuthenticationConverterTests.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.security.web.server.authentication;
1818

19+
import java.nio.charset.StandardCharsets;
20+
1921
import org.junit.jupiter.api.Test;
2022
import reactor.core.publisher.Mono;
2123

@@ -62,7 +64,7 @@ public void applyWhenNotBase64ThenEmpty() {
6264
}
6365

6466
@Test
65-
public void applyWhenNoSemicolonThenEmpty() {
67+
public void applyWhenNoColonThenEmpty() {
6668
Mono<Authentication> result = apply(this.request.header(HttpHeaders.AUTHORIZATION, "Basic dXNlcg=="));
6769
assertThat(result.block()).isNull();
6870
}
@@ -104,6 +106,38 @@ public void applyWhenWrongSchemeThenEmpty() {
104106
assertThat(result.block()).isNull();
105107
}
106108

109+
@Test
110+
public void applyWhenNonAsciiThenAuthentication() {
111+
Mono<Authentication> result = apply(
112+
this.request.header(HttpHeaders.AUTHORIZATION, "Basic w7xzZXI6cGFzc3fDtnJk"));
113+
UsernamePasswordAuthenticationToken authentication = result.cast(UsernamePasswordAuthenticationToken.class)
114+
.block();
115+
assertThat(authentication.getPrincipal()).isEqualTo("üser");
116+
assertThat(authentication.getCredentials()).isEqualTo("passwörd");
117+
}
118+
119+
@Test
120+
public void applyWhenIsoOnlyAsciiThenAuthentication() {
121+
this.converter.setCredentialsCharset(StandardCharsets.ISO_8859_1);
122+
Mono<Authentication> result = apply(
123+
this.request.header(HttpHeaders.AUTHORIZATION, "Basic dXNlcjpwYXNzd29yZA=="));
124+
UsernamePasswordAuthenticationToken authentication = result.cast(UsernamePasswordAuthenticationToken.class)
125+
.block();
126+
assertThat(authentication.getPrincipal()).isEqualTo("user");
127+
assertThat(authentication.getCredentials()).isEqualTo("password");
128+
}
129+
130+
@Test
131+
public void applyWhenIsoNonAsciiThenAuthentication() {
132+
this.converter.setCredentialsCharset(StandardCharsets.ISO_8859_1);
133+
Mono<Authentication> result = apply(
134+
this.request.header(HttpHeaders.AUTHORIZATION, "Basic /HNlcjpwYXNzd/ZyZA=="));
135+
UsernamePasswordAuthenticationToken authentication = result.cast(UsernamePasswordAuthenticationToken.class)
136+
.block();
137+
assertThat(authentication.getPrincipal()).isEqualTo("üser");
138+
assertThat(authentication.getCredentials()).isEqualTo("passwörd");
139+
}
140+
107141
private Mono<Authentication> apply(MockServerHttpRequest.BaseBuilder<?> request) {
108142
return this.converter.convert(MockServerWebExchange.from(this.request.build()));
109143
}

0 commit comments

Comments
 (0)