Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save richturner/4779b977b0f13ff147d4cc33fa38d221 to your computer and use it in GitHub Desktop.
Save richturner/4779b977b0f13ff147d4cc33fa38d221 to your computer and use it in GitHub Desktop.
An authentication mechanism for Undertow to fix the broken BasicAuthenticationMechanism and conform to RFC2617
/**
* This is a fix for {@link BasicAuthenticationMechanism} which doesn't conform to RFC2617.
* see: https://issues.redhat.com/browse/UNDERTOW-1727
* <p>
* When no {@link io.undertow.util.Headers#AUTHORIZATION} header is supplied then a 401 is returned with
* {@link io.undertow.util.Headers#WWW_AUTHENTICATE} header unless {@link #silent} is true in which case
* a 403 will be returned.
* <p>
* When an {@link io.undertow.util.Headers#AUTHORIZATION} header is supplied and is valid then the request
* can proceed otherwise a 403 is returned.
*/
public class BasicFixAuthenticationMechanism extends BasicAuthenticationMechanism {
public static class Factory implements AuthenticationMechanismFactory {
@Override
public AuthenticationMechanism create(String mechanismName, IdentityManager identityManager, FormParserFactory formParserFactory, Map<String, String> properties) {
String realm = properties.get(REALM);
String silent = properties.get(SILENT);
String charsetString = properties.get(CHARSET);
Charset charset = charsetString == null ? StandardCharsets.UTF_8 : Charset.forName(charsetString);
Map<Pattern, Charset> userAgentCharsets = new HashMap<>();
String userAgentString = properties.get(USER_AGENT_CHARSETS);
if(userAgentString != null) {
String[] parts = userAgentString.split(",");
if(parts.length % 2 != 0) {
throw UndertowMessages.MESSAGES.userAgentCharsetMustHaveEvenNumberOfItems(userAgentString);
}
for(int i = 0; i < parts.length; i += 2) {
Pattern pattern = Pattern.compile(parts[i]);
Charset c = Charset.forName(parts[i + 1]);
userAgentCharsets.put(pattern, c);
}
}
return new BasicFixAuthenticationMechanism(realm, mechanismName, silent != null && silent.equals("true"), identityManager, charset, userAgentCharsets);
}
}
// field is private in super class so need to redefine!!!
private final boolean silent;
public static Factory FACTORY = new Factory();
public BasicFixAuthenticationMechanism(String realmName, String mechanismName, boolean silent, IdentityManager identityManager, Charset charset, Map<Pattern, Charset> userAgentCharsets) {
super(realmName, mechanismName, false, identityManager, charset, userAgentCharsets);
this.silent = silent;
}
@Override
public AuthenticationMechanismOutcome authenticate(HttpServerExchange exchange, SecurityContext securityContext) {
String authHeader = exchange.getRequestHeaders().getFirst(AUTHORIZATION);
if (authHeader == null) {
if (silent) {
return AuthenticationMechanismOutcome.NOT_ATTEMPTED;
} else {
return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
}
}
return super.authenticate(exchange, securityContext);
}
@Override
public ChallengeResult sendChallenge(HttpServerExchange exchange, SecurityContext securityContext) {
String authHeader = exchange.getRequestHeaders().getFirst(AUTHORIZATION);
if (silent || authHeader != null) {
return ChallengeResult.NOT_SENT;
}
return super.sendChallenge(exchange, securityContext);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment