Use configurable charset in ServerHttpBasicAuthenticationConverter
Closes gh-10903
This commit is contained in:
parent
428216b322
commit
2b6bc5dd0b
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.security.web.server;
|
package org.springframework.security.web.server;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
@ -25,6 +27,7 @@ import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
|
||||||
|
@ -43,6 +46,8 @@ public class ServerHttpBasicAuthenticationConverter implements Function<ServerWe
|
||||||
|
|
||||||
public static final String BASIC = "Basic ";
|
public static final String BASIC = "Basic ";
|
||||||
|
|
||||||
|
private Charset credentialsCharset = StandardCharsets.UTF_8;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public Mono<Authentication> apply(ServerWebExchange exchange) {
|
public Mono<Authentication> apply(ServerWebExchange exchange) {
|
||||||
|
@ -51,9 +56,8 @@ public class ServerHttpBasicAuthenticationConverter implements Function<ServerWe
|
||||||
if (!StringUtils.startsWithIgnoreCase(authorization, "basic ")) {
|
if (!StringUtils.startsWithIgnoreCase(authorization, "basic ")) {
|
||||||
return Mono.empty();
|
return Mono.empty();
|
||||||
}
|
}
|
||||||
String credentials = (authorization.length() <= BASIC.length()) ? ""
|
String credentials = (authorization.length() <= BASIC.length()) ? "" : authorization.substring(BASIC.length());
|
||||||
: authorization.substring(BASIC.length(), authorization.length());
|
String decoded = new String(base64Decode(credentials), this.credentialsCharset);
|
||||||
String decoded = new String(base64Decode(credentials));
|
|
||||||
String[] parts = decoded.split(":", 2);
|
String[] parts = decoded.split(":", 2);
|
||||||
if (parts.length != 2) {
|
if (parts.length != 2) {
|
||||||
return Mono.empty();
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.security.web.server.authentication;
|
package org.springframework.security.web.server.authentication;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
@ -62,7 +64,7 @@ public class ServerHttpBasicAuthenticationConverterTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void applyWhenNoSemicolonThenEmpty() {
|
public void applyWhenNoColonThenEmpty() {
|
||||||
Mono<Authentication> result = apply(this.request.header(HttpHeaders.AUTHORIZATION, "Basic dXNlcg=="));
|
Mono<Authentication> result = apply(this.request.header(HttpHeaders.AUTHORIZATION, "Basic dXNlcg=="));
|
||||||
assertThat(result.block()).isNull();
|
assertThat(result.block()).isNull();
|
||||||
}
|
}
|
||||||
|
@ -104,6 +106,38 @@ public class ServerHttpBasicAuthenticationConverterTests {
|
||||||
assertThat(result.block()).isNull();
|
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) {
|
private Mono<Authentication> apply(MockServerHttpRequest.BaseBuilder<?> request) {
|
||||||
return this.converter.convert(MockServerWebExchange.from(this.request.build()));
|
return this.converter.convert(MockServerWebExchange.from(this.request.build()));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue