Created
June 4, 2020 15:46
-
-
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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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