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 Mar 7, 2024
1 parent b80aa6a commit 285f024
Show file tree
Hide file tree
Showing 10 changed files with 559 additions and 143 deletions.
Original file line number Diff line number Diff line change
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 sessionBasedNonceManager;

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 sessionBasedNonceManager) {
checkNotNullParam("mechanismRealms", mechanismRealms);
this.preRealmRewriter = preRealmRewriter;
this.postRealmRewriter = postRealmRewriter;
this.finalRewriter = finalRewriter;
this.realmMapper = realmMapper;
this.sessionBasedNonceManager = sessionBasedNonceManager;
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 getUseSessionBasedNonceManager() {
return sessionBasedNonceManager;
}
/**
* 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 useSessionBasedNonceManager = false;

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

public Builder setUseSessionBasedNonceManager(final Boolean useSessionBasedNonceManager) {
checkNotNullParam("useSessionBasedNonceManager", useSessionBasedNonceManager);
this.useSessionBasedNonceManager = useSessionBasedNonceManager;
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, useSessionBasedNonceManager);
}
}

/**
* 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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public String getMechanismName() {
public String getHostName() {
return null;
}

};

}
Original file line number Diff line number Diff line change
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_BASED_DIGEST_NONCE_MANAGER = CONFIG_BASE + ".use-session-based-digest-nonce-manager";

/**
* The context relative path of the login page.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,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 All @@ -82,6 +83,7 @@ final class DigestAuthenticationMechanism implements HttpServerAuthenticationMec
private static final String CHALLENGE_PREFIX = "Digest ";
private static final String OPAQUE_VALUE = "00000000000000000000000000000000";
private static final byte COLON = ':';
public static final String PERSISTENT_NONCE_MANAGER = "persistentNonceManager";

private final Supplier<Provider[]> providers;
private final CallbackHandler callbackHandler;
Expand Down Expand Up @@ -116,6 +118,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(PERSISTENT_NONCE_MANAGER);
if (persistentNonceManager != null) {
((PersistentNonceManager) nonceManager).refreshInfoFromSessionNonceManager(persistentNonceManager);
}
}

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

if (authorizationValues != null) {
Expand All @@ -128,14 +141,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 @@ -213,7 +225,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 @@ -222,7 +234,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 @@ -231,13 +243,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 @@ -390,7 +402,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 @@ -407,6 +419,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(PERSISTENT_NONCE_MANAGER, this.nonceManager);
}
}

private boolean authorize(String username) throws AuthenticationMechanismException {
Expand Down
Original file line number Diff line number Diff line change
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_BASED_DIGEST_NONCE_MANAGER;
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 @@ -90,7 +91,7 @@ public String[] getMechanismNames(Map<String, ?> properties) {
}

/**
* @see org.wildfly.security.http.HttpServerAuthenticationMechanismFactory#createAuthenticationMechanism(java.lang.String, java.util.Map, javax.security.auth.callback.CallbackHandler)
* @see HttpServerAuthenticationMechanismFactory#createAuthenticationMechanism(String, Map, CallbackHandler)
*/
@Override
public HttpServerAuthenticationMechanism createAuthenticationMechanism(String mechanismName, Map<String, ?> properties, CallbackHandler callbackHandler) throws HttpAuthenticationException {
Expand All @@ -100,6 +101,10 @@ public HttpServerAuthenticationMechanism createAuthenticationMechanism(String me

if (properties.containsKey("nonceManager")) {
nonceManager = (NonceManager) properties.get("nonceManager");
} else if (properties.get(CONFIG_SESSION_BASED_DIGEST_NONCE_MANAGER) != null) {
if (Boolean.parseBoolean((String) properties.get(CONFIG_SESSION_BASED_DIGEST_NONCE_MANAGER))) {
nonceManager = new PersistentNonceManager(NonceManagerUtils.DEFAULT_VALIDITY_PERIOD, NonceManagerUtils.DEFAULT_NONCE_SESSION_TIME, true, NonceManagerUtils.DEFAULT_KEY_SIZE, SHA256, ElytronMessages.httpDigest);
}
}

switch (mechanismName) {
Expand Down
Loading

0 comments on commit 285f024

Please sign in to comment.