Skip to content

Commit

Permalink
[ELY-2359] Support HTTP Digest when fronted by load balancer
Browse files Browse the repository at this point in the history
  • Loading branch information
Skyllarr committed May 30, 2023
1 parent 793e498 commit 143ec82
Show file tree
Hide file tree
Showing 11 changed files with 586 additions and 143 deletions.
Expand Up @@ -49,13 +49,15 @@ public final class MechanismConfiguration {
private final RealmMapper realmMapper;
private final Map<String, MechanismRealmConfiguration> mechanismRealms;
private final CredentialSource serverCredentialSource;
private final boolean sessionDigest;

MechanismConfiguration(final Function<Principal, Principal> preRealmRewriter, final Function<Principal, Principal> postRealmRewriter, final Function<Principal, Principal> finalRewriter, final RealmMapper realmMapper, final Collection<MechanismRealmConfiguration> mechanismRealms, final CredentialSource serverCredentialSource) {
MechanismConfiguration(final Function<Principal, Principal> preRealmRewriter, final Function<Principal, Principal> postRealmRewriter, final Function<Principal, Principal> finalRewriter, final RealmMapper realmMapper, final Collection<MechanismRealmConfiguration> mechanismRealms, final CredentialSource serverCredentialSource, final boolean sessionDigest) {
checkNotNullParam("mechanismRealms", mechanismRealms);
this.preRealmRewriter = preRealmRewriter;
this.postRealmRewriter = postRealmRewriter;
this.finalRewriter = finalRewriter;
this.realmMapper = realmMapper;
this.sessionDigest = sessionDigest;
final Iterator<MechanismRealmConfiguration> iterator = mechanismRealms.iterator();
if (! iterator.hasNext()) {
// zero
Expand Down Expand Up @@ -146,6 +148,9 @@ public MechanismRealmConfiguration getMechanismRealmConfiguration(String realmNa
return mechanismRealms.get(realmName);
}

public boolean getSessionDigest() {
return sessionDigest;
}
/**
* Obtain a new {@link Builder} capable of building a {@link MechanismConfiguration}.
*
Expand All @@ -167,6 +172,7 @@ public static final class Builder {
private RealmMapper realmMapper;
private List<MechanismRealmConfiguration> mechanismRealms;
private CredentialSource serverCredentialSource = CredentialSource.NONE;
private boolean sessionDigest = false;

/**
* Construct a new instance.
Expand Down Expand Up @@ -271,6 +277,12 @@ public Builder setServerCredentialSource(final CredentialSource serverCredential
return this;
}

public Builder setSessionDigest(final Boolean sessionDigest) {
checkNotNullParam("sessionDigest", sessionDigest);
this.sessionDigest = sessionDigest;
return this;
}

/**
* Build a new instance. If no mechanism realms are offered, an empty collection should be provided for
* {@code mechanismRealms}; otherwise, if the mechanism only supports one realm, the first will be used. If the
Expand All @@ -285,12 +297,12 @@ public MechanismConfiguration build() {
} else {
mechanismRealms = unmodifiableList(asList(mechanismRealms.toArray(NO_REALM_CONFIGS)));
}
return new MechanismConfiguration(preRealmRewriter, postRealmRewriter, finalRewriter, realmMapper, mechanismRealms, serverCredentialSource);
return new MechanismConfiguration(preRealmRewriter, postRealmRewriter, finalRewriter, realmMapper, mechanismRealms, serverCredentialSource, sessionDigest);
}
}

/**
* An empty mechanism configuration..
*/
public static final MechanismConfiguration EMPTY = new MechanismConfiguration(Function.identity(), Function.identity(), Function.identity(), null, emptyList(), CredentialSource.NONE);
public static final MechanismConfiguration EMPTY = new MechanismConfiguration(Function.identity(), Function.identity(), Function.identity(), null, emptyList(), CredentialSource.NONE, false);
}
Expand Up @@ -74,6 +74,7 @@ public String getMechanismName() {
public String getHostName() {
return null;
}

};

}
Expand Up @@ -51,6 +51,7 @@ private HttpConstants() {

public static final String CONFIG_VALIDATE_DIGEST_URI = CONFIG_BASE + ".validate-digest-uri";
public static final String CONFIG_SKIP_CERTIFICATE_VERIFICATION = CONFIG_BASE + ".skip-certificate-verification";
public static final String CONFIG_SESSION_DIGEST = CONFIG_BASE + ".session-digest";

/**
* The context relative path of the login page.
Expand Down
Expand Up @@ -65,6 +65,7 @@
import org.wildfly.security.http.HttpServerMechanismsResponder;
import org.wildfly.security.http.HttpServerRequest;
import org.wildfly.security.http.HttpServerResponse;
import org.wildfly.security.http.Scope;
import org.wildfly.security.mechanism.AuthenticationMechanismException;
import org.wildfly.security.mechanism.digest.DigestQuote;
import org.wildfly.security.mechanism.digest.PasswordDigestObtainer;
Expand Down Expand Up @@ -114,6 +115,17 @@ public String getMechanismName() {

@Override
public void evaluateRequest(final HttpServerRequest request) throws HttpAuthenticationException {

if (nonceManager instanceof PersistentNonceManager) {
if (request.getScope(Scope.SESSION) == null || !request.getScope(Scope.SESSION).exists()) {
request.getScope(Scope.SESSION).create();
}
PersistentNonceManager persistentNonceManager = (PersistentNonceManager) request.getScope(Scope.SESSION).getAttachment("persistentNonceManager");
if (persistentNonceManager != null) {
((PersistentNonceManager) nonceManager).refreshInfoFromSessionNonceManager(persistentNonceManager);
}
}

List<String> authorizationValues = request.getRequestHeaderValues(AUTHORIZATION);

if (authorizationValues != null) {
Expand All @@ -126,14 +138,13 @@ public void evaluateRequest(final HttpServerRequest request) throws HttpAuthenti
return;
} catch (AuthenticationMechanismException e) {
httpDigest.trace("Failed to parse or validate the response", e);
request.badRequest(e.toHttpAuthenticationException(), response -> prepareResponse(selectRealm(), response, false));
request.badRequest(e.toHttpAuthenticationException(), response -> prepareResponse(selectRealm(), response, false, request));
return;
}
}
}
}

request.noAuthenticationInProgress(response -> prepareResponse(selectRealm(), response, false));
request.noAuthenticationInProgress(response -> prepareResponse(selectRealm(), response, false, request));
}

private void validateResponse(HashMap<String, byte[]> responseTokens, final HttpServerRequest request) throws AuthenticationMechanismException, HttpAuthenticationException {
Expand Down Expand Up @@ -211,7 +222,7 @@ private void validateResponse(HashMap<String, byte[]> responseTokens, final Http
if (username.length() == 0) {
httpDigest.trace("Failed: no username");
fail();
request.authenticationFailed(httpDigest.authenticationFailed(), httpResponse -> prepareResponse(selectedRealm, httpResponse, false));
request.authenticationFailed(httpDigest.authenticationFailed(), httpResponse -> prepareResponse(selectedRealm, httpResponse, false, request));
return;
}

Expand All @@ -220,7 +231,7 @@ private void validateResponse(HashMap<String, byte[]> responseTokens, final Http
if (hA1 == null) {
httpDigest.trace("Failed: unable to get expected proof");
fail();
request.authenticationFailed(httpDigest.authenticationFailed(), httpResponse -> prepareResponse(selectedRealm, httpResponse, false));
request.authenticationFailed(httpDigest.authenticationFailed(), httpResponse -> prepareResponse(selectedRealm, httpResponse, false, request));
return;
}

Expand All @@ -229,13 +240,13 @@ private void validateResponse(HashMap<String, byte[]> responseTokens, final Http
if (MessageDigest.isEqual(response, calculatedResponse) == false) {
httpDigest.trace("Failed: invalid proof");
fail();
request.authenticationFailed(httpDigest.mechResponseTokenMismatch(getMechanismName()), httpResponse -> prepareResponse(selectedRealm, httpResponse, false));
request.authenticationFailed(httpDigest.mechResponseTokenMismatch(getMechanismName()), httpResponse -> prepareResponse(selectedRealm, httpResponse, false, request));
return;
}

if (nonceValid == false) {
httpDigest.trace("Failed: invalid nonce");
request.authenticationInProgress(httpResponse -> prepareResponse(selectedRealm, httpResponse, true));
request.authenticationInProgress(httpResponse -> prepareResponse(selectedRealm, httpResponse, true, request));
return;
}

Expand Down Expand Up @@ -379,7 +390,7 @@ private String[] getAvailableRealms() throws AuthenticationMechanismException {
}
}

private void prepareResponse(String realmName, HttpServerResponse response, boolean stale) throws HttpAuthenticationException {
private void prepareResponse(String realmName, HttpServerResponse response, boolean stale, HttpServerRequest request) throws HttpAuthenticationException {
StringBuilder sb = new StringBuilder(CHALLENGE_PREFIX);
sb.append(REALM).append("=\"").append(DigestQuote.quote(realmName)).append("\"");

Expand All @@ -396,6 +407,10 @@ private void prepareResponse(String realmName, HttpServerResponse response, bool

response.addResponseHeader(WWW_AUTHENTICATE, sb.toString());
response.setStatusCode(UNAUTHORIZED);

if ((nonceManager instanceof PersistentNonceManager) && request.getScope(Scope.SESSION) != null) {
request.getScope(Scope.SESSION).setAttachment("persistentNonceManager", this.nonceManager);
}
}

private boolean authorize(String username) throws AuthenticationMechanismException {
Expand Down
Expand Up @@ -21,6 +21,7 @@
import static org.wildfly.common.Assert.checkNotNullParam;
import static org.wildfly.security.http.HttpConstants.CONFIG_CONTEXT_PATH;
import static org.wildfly.security.http.HttpConstants.CONFIG_REALM;
import static org.wildfly.security.http.HttpConstants.CONFIG_SESSION_DIGEST;
import static org.wildfly.security.http.HttpConstants.DIGEST_NAME;
import static org.wildfly.security.http.HttpConstants.DIGEST_SHA256_NAME;
import static org.wildfly.security.http.HttpConstants.DIGEST_SHA512_256_NAME;
Expand Down Expand Up @@ -58,7 +59,7 @@ public DigestMechanismFactory() {
}

public DigestMechanismFactory(final Provider provider) {
this(new Provider[] { provider });
this(new Provider[]{provider});
}

public DigestMechanismFactory(final Provider... providers) {
Expand Down Expand Up @@ -100,6 +101,8 @@ public HttpServerAuthenticationMechanism createAuthenticationMechanism(String me

if (properties.containsKey("nonceManager")) {
nonceManager = (NonceManager) properties.get("nonceManager");
} else if (properties.get(CONFIG_SESSION_DIGEST) != null) {
nonceManager = new PersistentNonceManager(300000, 900000, true, 20, SHA256, ElytronMessages.httpDigest);
}

switch (mechanismName) {
Expand Down

0 comments on commit 143ec82

Please sign in to comment.