Search in sources :

Example 1 with DigestAlgorithm

use of io.undertow.security.idm.DigestAlgorithm in project wildfly by wildfly.

the class DigestAuthenticationMechanism method handleDigestHeader.

public AuthenticationMechanismOutcome handleDigestHeader(HttpServerExchange exchange, final SecurityContext securityContext) {
    DigestContext context = exchange.getAttachment(DigestContext.ATTACHMENT_KEY);
    Map<DigestAuthorizationToken, String> parsedHeader = context.getParsedHeader();
    // Step 1 - Verify the set of tokens received to ensure valid values.
    Set<DigestAuthorizationToken> mandatoryTokens = new HashSet<>(MANDATORY_REQUEST_TOKENS);
    if (!supportedAlgorithms.contains(DigestAlgorithm.MD5)) {
        // If we don't support MD5 then the client must choose an algorithm as we can not fall back to MD5.
        mandatoryTokens.add(DigestAuthorizationToken.ALGORITHM);
    }
    if (!supportedQops.isEmpty() && !supportedQops.contains(DigestQop.AUTH)) {
        // If we do not support auth then we are mandating auth-int so force the client to send a QOP
        mandatoryTokens.add(DigestAuthorizationToken.MESSAGE_QOP);
    }
    DigestQop qop = null;
    // This check is early as is increases the list of mandatory tokens.
    if (parsedHeader.containsKey(DigestAuthorizationToken.MESSAGE_QOP)) {
        qop = DigestQop.forName(parsedHeader.get(DigestAuthorizationToken.MESSAGE_QOP));
        if (qop == null || !supportedQops.contains(qop)) {
            // We are also ensuring the client is not trying to force a qop that has been disabled.
            REQUEST_LOGGER.invalidTokenReceived(DigestAuthorizationToken.MESSAGE_QOP.getName(), parsedHeader.get(DigestAuthorizationToken.MESSAGE_QOP));
            // TODO - This actually needs to result in a HTTP 400 Bad Request response and not a new challenge.
            return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
        }
        context.setQop(qop);
        mandatoryTokens.add(DigestAuthorizationToken.CNONCE);
        mandatoryTokens.add(DigestAuthorizationToken.NONCE_COUNT);
    }
    // Check all mandatory tokens are present.
    mandatoryTokens.removeAll(parsedHeader.keySet());
    if (mandatoryTokens.size() > 0) {
        for (DigestAuthorizationToken currentToken : mandatoryTokens) {
            // TODO - Need a better check and possible concatenate the list of tokens - however
            // even having one missing token is not something we should routinely expect.
            REQUEST_LOGGER.missingAuthorizationToken(currentToken.getName());
        }
        // TODO - This actually needs to result in a HTTP 400 Bad Request response and not a new challenge.
        return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
    }
    // Perform some validation of the remaining tokens.
    if (!realmName.equals(parsedHeader.get(DigestAuthorizationToken.REALM))) {
        REQUEST_LOGGER.invalidTokenReceived(DigestAuthorizationToken.REALM.getName(), parsedHeader.get(DigestAuthorizationToken.REALM));
        // TODO - This actually needs to result in a HTTP 400 Bad Request response and not a new challenge.
        return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
    }
    if (parsedHeader.containsKey(DigestAuthorizationToken.OPAQUE)) {
        if (!OPAQUE_VALUE.equals(parsedHeader.get(DigestAuthorizationToken.OPAQUE))) {
            REQUEST_LOGGER.invalidTokenReceived(DigestAuthorizationToken.OPAQUE.getName(), parsedHeader.get(DigestAuthorizationToken.OPAQUE));
            return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
        }
    }
    DigestAlgorithm algorithm;
    if (parsedHeader.containsKey(DigestAuthorizationToken.ALGORITHM)) {
        algorithm = DigestAlgorithm.forName(parsedHeader.get(DigestAuthorizationToken.ALGORITHM));
        if (algorithm == null || !supportedAlgorithms.contains(algorithm)) {
            // We are also ensuring the client is not trying to force an algorithm that has been disabled.
            REQUEST_LOGGER.invalidTokenReceived(DigestAuthorizationToken.ALGORITHM.getName(), parsedHeader.get(DigestAuthorizationToken.ALGORITHM));
            // TODO - This actually needs to result in a HTTP 400 Bad Request response and not a new challenge.
            return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
        }
    } else {
        // We know this is safe as the algorithm token was made mandatory
        // if MD5 is not supported.
        algorithm = DigestAlgorithm.MD5;
    }
    try {
        context.setAlgorithm(algorithm);
    } catch (NoSuchAlgorithmException e) {
        /*
             * This should not be possible in a properly configured installation.
             */
        REQUEST_LOGGER.exceptionProcessingRequest(e);
        return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
    }
    final String userName = parsedHeader.get(DigestAuthorizationToken.USERNAME);
    final IdentityManager identityManager = getIdentityManager(securityContext);
    final Account account;
    if (algorithm.isSession()) {
        /* This can follow one of the following: -
             *   1 - New session so use DigestCredentialImpl with the IdentityManager to
             *       create a new session key.
             *   2 - Obtain the existing session key from the session store and validate it, just use
             *       IdentityManager to validate account is still active and the current role assignment.
             */
        throw new IllegalStateException("Not yet implemented.");
    } else {
        final DigestCredential credential = new DigestCredentialImpl(context);
        account = identityManager.verify(userName, credential);
    }
    if (account == null) {
        // Authentication has failed, this could either be caused by the user not-existing or it
        // could be caused due to an invalid hash.
        securityContext.authenticationFailed(MESSAGES.authenticationFailed(userName), mechanismName);
        return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
    }
    // Step 3 - Verify that the nonce was eligible to be used.
    if (!validateNonceUse(context, parsedHeader, exchange)) {
        // TODO - This is the right place to make use of the decision but the check needs to be much much sooner
        // otherwise a failure server
        // side could leave a packet that could be 're-played' after the failed auth.
        // The username and password verification passed but for some reason we do not like the nonce.
        context.markStale();
        // can easily hit this point.
        return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
    }
    // We have authenticated the remote user.
    //sendAuthenticationInfoHeader(exchange);
    securityContext.authenticationComplete(account, mechanismName, true);
    return AuthenticationMechanismOutcome.AUTHENTICATED;
// Step 4 - Set up any QOP related requirements.
// TODO - Do QOP
}
Also used : DigestAuthorizationToken(io.undertow.security.impl.DigestAuthorizationToken) DigestQop(io.undertow.security.impl.DigestQop) Account(io.undertow.security.idm.Account) IdentityManager(io.undertow.security.idm.IdentityManager) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) HashSet(java.util.HashSet) DigestAlgorithm(io.undertow.security.idm.DigestAlgorithm)

Example 2 with DigestAlgorithm

use of io.undertow.security.idm.DigestAlgorithm in project wildfly by wildfly.

the class DigestAuthenticationMechanism method sendChallenge.

@Override
public ChallengeResult sendChallenge(final HttpServerExchange exchange, final SecurityContext securityContext) {
    DigestContext context = exchange.getAttachment(DigestContext.ATTACHMENT_KEY);
    boolean stale = context == null ? false : context.isStale();
    StringBuilder rb = new StringBuilder(DIGEST_PREFIX);
    rb.append(Headers.REALM.toString()).append("=\"").append(realmName).append("\",");
    rb.append(Headers.DOMAIN.toString()).append("=\"").append(domain).append("\",");
    // based on security constraints.
    rb.append(Headers.NONCE.toString()).append("=\"").append(nonceManager.nextNonce(null, exchange)).append("\",");
    // Not currently using OPAQUE as it offers no integrity, used for session data leaves it vulnerable to
    // session fixation type issues as well.
    rb.append(Headers.OPAQUE.toString()).append("=\"00000000000000000000000000000000\"");
    if (stale) {
        rb.append(",stale=true");
    }
    if (supportedAlgorithms.size() > 0) {
        // This header will need to be repeated once for each algorithm.
        rb.append(",").append(Headers.ALGORITHM.toString()).append("=%s");
    }
    if (qopString != null) {
        rb.append(",").append(Headers.QOP.toString()).append("=\"").append(qopString).append("\"");
    }
    String theChallenge = rb.toString();
    HeaderMap responseHeader = exchange.getResponseHeaders();
    if (supportedAlgorithms.isEmpty()) {
        responseHeader.add(WWW_AUTHENTICATE, theChallenge);
    } else {
        for (DigestAlgorithm current : supportedAlgorithms) {
            responseHeader.add(WWW_AUTHENTICATE, String.format(theChallenge, current.getToken()));
        }
    }
    return new ChallengeResult(true, UNAUTHORIZED);
}
Also used : HeaderMap(io.undertow.util.HeaderMap) DigestAlgorithm(io.undertow.security.idm.DigestAlgorithm)

Example 3 with DigestAlgorithm

use of io.undertow.security.idm.DigestAlgorithm in project wildfly-swarm by wildfly-swarm.

the class SecureHttpContexts method secureHandler.

/**
 * Wraps the target handler and makes it inheritSecurity.
 * Includes a predicate for relevant web contexts.
 */
private HttpHandler secureHandler(final HttpHandler toWrap, SecurityRealm securityRealm) {
    HttpHandler handler = toWrap;
    handler = new AuthenticationCallHandler(handler);
    handler = new AuthenticationConstraintHandler(handler);
    RealmIdentityManager idm = new RealmIdentityManager(securityRealm);
    Set<AuthMechanism> mechanisms = securityRealm.getSupportedAuthenticationMechanisms();
    List<AuthenticationMechanism> undertowMechanisms = new ArrayList<AuthenticationMechanism>(mechanisms.size());
    undertowMechanisms.add(wrap(new CachedAuthenticatedSessionMechanism(), null));
    for (AuthMechanism current : mechanisms) {
        switch(current) {
            case DIGEST:
                List<DigestAlgorithm> digestAlgorithms = Collections.singletonList(DigestAlgorithm.MD5);
                List<DigestQop> digestQops = Collections.singletonList(DigestQop.AUTH);
                undertowMechanisms.add(wrap(new DigestAuthenticationMechanism(digestAlgorithms, digestQops, securityRealm.getName(), "Monitor", new SimpleNonceManager()), current));
                break;
            case PLAIN:
                undertowMechanisms.add(wrap(new BasicAuthenticationMechanism(securityRealm.getName()), current));
                break;
            case LOCAL:
                break;
            default:
        }
    }
    handler = new AuthenticationMechanismsHandler(handler, undertowMechanisms);
    handler = new SecurityInitialHandler(AuthenticationMode.PRO_ACTIVE, idm, handler);
    // the predicate handler takes care that all of the above
    // will only be enacted on relevant web contexts
    handler = new PredicateHandler(exchange -> {
        if (!monitor.getSecurityRealm().isPresent()) {
            return false;
        }
        if (Queries.isAggregatorEndpoint(monitor, exchange.getRelativePath())) {
            return true;
        }
        if (Queries.isDirectAccessToHealthEndpoint(monitor, exchange.getRelativePath())) {
            if (!hasTokenAuth(exchange)) {
                return true;
            }
            return false;
        }
        if (HttpContexts.getDefaultContextNames().contains(exchange.getRelativePath())) {
            return true;
        }
        return false;
    }, handler, toWrap);
    return handler;
}
Also used : DigestQop(io.undertow.security.impl.DigestQop) BasicAuthenticationMechanism(io.undertow.security.impl.BasicAuthenticationMechanism) HttpServerExchange(io.undertow.server.HttpServerExchange) NamingException(javax.naming.NamingException) SecurityRealm(org.jboss.as.domain.management.SecurityRealm) SecurityInitialHandler(io.undertow.security.handlers.SecurityInitialHandler) ArrayList(java.util.ArrayList) AuthenticationMechanismsHandler(io.undertow.security.handlers.AuthenticationMechanismsHandler) DigestAlgorithm(io.undertow.security.idm.DigestAlgorithm) AuthenticationMechanismWrapper(org.jboss.as.domain.http.server.security.AuthenticationMechanismWrapper) PredicateHandler(io.undertow.server.handlers.PredicateHandler) CachedAuthenticatedSessionMechanism(io.undertow.security.impl.CachedAuthenticatedSessionMechanism) DigestQop(io.undertow.security.impl.DigestQop) DigestAuthenticationMechanism(io.undertow.security.impl.DigestAuthenticationMechanism) Monitor(org.wildfly.swarm.microprofile.health.api.Monitor) Vetoed(javax.enterprise.inject.Vetoed) AuthenticationConstraintHandler(io.undertow.security.handlers.AuthenticationConstraintHandler) Set(java.util.Set) AuthenticationMode(io.undertow.security.api.AuthenticationMode) AuthMechanism(org.jboss.as.domain.management.AuthMechanism) HttpHandler(io.undertow.server.HttpHandler) List(java.util.List) SimpleNonceManager(io.undertow.security.impl.SimpleNonceManager) AuthenticationMechanism(io.undertow.security.api.AuthenticationMechanism) RealmIdentityManager(org.jboss.as.domain.http.server.security.RealmIdentityManager) AuthenticationCallHandler(io.undertow.security.handlers.AuthenticationCallHandler) Optional(java.util.Optional) Collections(java.util.Collections) HttpHandler(io.undertow.server.HttpHandler) AuthenticationConstraintHandler(io.undertow.security.handlers.AuthenticationConstraintHandler) DigestAuthenticationMechanism(io.undertow.security.impl.DigestAuthenticationMechanism) CachedAuthenticatedSessionMechanism(io.undertow.security.impl.CachedAuthenticatedSessionMechanism) BasicAuthenticationMechanism(io.undertow.security.impl.BasicAuthenticationMechanism) DigestAuthenticationMechanism(io.undertow.security.impl.DigestAuthenticationMechanism) AuthenticationMechanism(io.undertow.security.api.AuthenticationMechanism) RealmIdentityManager(org.jboss.as.domain.http.server.security.RealmIdentityManager) ArrayList(java.util.ArrayList) PredicateHandler(io.undertow.server.handlers.PredicateHandler) SimpleNonceManager(io.undertow.security.impl.SimpleNonceManager) AuthMechanism(org.jboss.as.domain.management.AuthMechanism) SecurityInitialHandler(io.undertow.security.handlers.SecurityInitialHandler) AuthenticationMechanismsHandler(io.undertow.security.handlers.AuthenticationMechanismsHandler) AuthenticationCallHandler(io.undertow.security.handlers.AuthenticationCallHandler) BasicAuthenticationMechanism(io.undertow.security.impl.BasicAuthenticationMechanism) DigestAlgorithm(io.undertow.security.idm.DigestAlgorithm)

Example 4 with DigestAlgorithm

use of io.undertow.security.idm.DigestAlgorithm in project wildfly-swarm by wildfly-swarm.

the class SecureHttpContexts method secureHandler.

/**
 * Wraps the target handler and makes it inheritSecurity.
 * Includes a predicate for relevant web contexts.
 */
@SuppressWarnings("deprecation")
private HttpHandler secureHandler(final HttpHandler toWrap, SecurityRealm securityRealm) {
    HttpHandler handler = toWrap;
    handler = new AuthenticationCallHandler(handler);
    handler = new AuthenticationConstraintHandler(handler);
    RealmIdentityManager idm = new RealmIdentityManager(securityRealm);
    Set<AuthMechanism> mechanisms = securityRealm.getSupportedAuthenticationMechanisms();
    List<AuthenticationMechanism> undertowMechanisms = new ArrayList<AuthenticationMechanism>(mechanisms.size());
    undertowMechanisms.add(wrap(new CachedAuthenticatedSessionMechanism(), null));
    for (AuthMechanism current : mechanisms) {
        switch(current) {
            case DIGEST:
                List<DigestAlgorithm> digestAlgorithms = Collections.singletonList(DigestAlgorithm.MD5);
                List<DigestQop> digestQops = Collections.singletonList(DigestQop.AUTH);
                undertowMechanisms.add(wrap(new DigestAuthenticationMechanism(digestAlgorithms, digestQops, securityRealm.getName(), "Monitor", new SimpleNonceManager()), current));
                break;
            case PLAIN:
                undertowMechanisms.add(wrap(new BasicAuthenticationMechanism(securityRealm.getName()), current));
                break;
            case LOCAL:
                break;
            default:
        }
    }
    handler = new AuthenticationMechanismsHandler(handler, undertowMechanisms);
    handler = new SecurityInitialHandler(AuthenticationMode.PRO_ACTIVE, idm, handler);
    // the predicate handler takes care that all of the above
    // will only be enacted on relevant web contexts
    handler = new PredicateHandler(exchange -> {
        if (!monitor.getSecurityRealm().isPresent()) {
            return false;
        }
        if (Queries.isAggregatorEndpoint(monitor, exchange.getRelativePath())) {
            return true;
        }
        if (Queries.isDirectAccessToHealthEndpoint(monitor, exchange.getRelativePath())) {
            if (!hasTokenAuth(exchange)) {
                return true;
            }
            return false;
        }
        if (HttpContexts.getDefaultContextNames().contains(exchange.getRelativePath())) {
            return true;
        }
        return false;
    }, handler, toWrap);
    return handler;
}
Also used : DigestQop(io.undertow.security.impl.DigestQop) BasicAuthenticationMechanism(io.undertow.security.impl.BasicAuthenticationMechanism) HttpServerExchange(io.undertow.server.HttpServerExchange) NamingException(javax.naming.NamingException) SecurityRealm(org.jboss.as.domain.management.SecurityRealm) SecurityInitialHandler(io.undertow.security.handlers.SecurityInitialHandler) ArrayList(java.util.ArrayList) AuthenticationMechanismsHandler(io.undertow.security.handlers.AuthenticationMechanismsHandler) DigestAlgorithm(io.undertow.security.idm.DigestAlgorithm) AuthenticationMechanismWrapper(org.jboss.as.domain.http.server.security.AuthenticationMechanismWrapper) PredicateHandler(io.undertow.server.handlers.PredicateHandler) CachedAuthenticatedSessionMechanism(io.undertow.security.impl.CachedAuthenticatedSessionMechanism) DigestQop(io.undertow.security.impl.DigestQop) DigestAuthenticationMechanism(io.undertow.security.impl.DigestAuthenticationMechanism) Vetoed(javax.enterprise.inject.Vetoed) AuthenticationConstraintHandler(io.undertow.security.handlers.AuthenticationConstraintHandler) Set(java.util.Set) AuthenticationMode(io.undertow.security.api.AuthenticationMode) AuthMechanism(org.jboss.as.domain.management.AuthMechanism) HttpHandler(io.undertow.server.HttpHandler) List(java.util.List) SimpleNonceManager(io.undertow.security.impl.SimpleNonceManager) AuthenticationMechanism(io.undertow.security.api.AuthenticationMechanism) RealmIdentityManager(org.jboss.as.domain.http.server.security.RealmIdentityManager) AuthenticationCallHandler(io.undertow.security.handlers.AuthenticationCallHandler) Optional(java.util.Optional) Collections(java.util.Collections) HttpHandler(io.undertow.server.HttpHandler) AuthenticationConstraintHandler(io.undertow.security.handlers.AuthenticationConstraintHandler) DigestAuthenticationMechanism(io.undertow.security.impl.DigestAuthenticationMechanism) CachedAuthenticatedSessionMechanism(io.undertow.security.impl.CachedAuthenticatedSessionMechanism) BasicAuthenticationMechanism(io.undertow.security.impl.BasicAuthenticationMechanism) DigestAuthenticationMechanism(io.undertow.security.impl.DigestAuthenticationMechanism) AuthenticationMechanism(io.undertow.security.api.AuthenticationMechanism) RealmIdentityManager(org.jboss.as.domain.http.server.security.RealmIdentityManager) ArrayList(java.util.ArrayList) PredicateHandler(io.undertow.server.handlers.PredicateHandler) SimpleNonceManager(io.undertow.security.impl.SimpleNonceManager) AuthMechanism(org.jboss.as.domain.management.AuthMechanism) SecurityInitialHandler(io.undertow.security.handlers.SecurityInitialHandler) AuthenticationMechanismsHandler(io.undertow.security.handlers.AuthenticationMechanismsHandler) AuthenticationCallHandler(io.undertow.security.handlers.AuthenticationCallHandler) BasicAuthenticationMechanism(io.undertow.security.impl.BasicAuthenticationMechanism) DigestAlgorithm(io.undertow.security.idm.DigestAlgorithm)

Example 5 with DigestAlgorithm

use of io.undertow.security.idm.DigestAlgorithm in project undertow by undertow-io.

the class DigestAuthenticationMechanism method handleDigestHeader.

private AuthenticationMechanismOutcome handleDigestHeader(HttpServerExchange exchange, final SecurityContext securityContext) {
    DigestContext context = exchange.getAttachment(DigestContext.ATTACHMENT_KEY);
    Map<DigestAuthorizationToken, String> parsedHeader = context.getParsedHeader();
    // Step 1 - Verify the set of tokens received to ensure valid values.
    Set<DigestAuthorizationToken> mandatoryTokens = EnumSet.copyOf(MANDATORY_REQUEST_TOKENS);
    if (!supportedAlgorithms.contains(DigestAlgorithm.MD5)) {
        // If we don't support MD5 then the client must choose an algorithm as we can not fall back to MD5.
        mandatoryTokens.add(DigestAuthorizationToken.ALGORITHM);
    }
    if (!supportedQops.isEmpty() && !supportedQops.contains(DigestQop.AUTH)) {
        // If we do not support auth then we are mandating auth-int so force the client to send a QOP
        mandatoryTokens.add(DigestAuthorizationToken.MESSAGE_QOP);
    }
    DigestQop qop = null;
    // This check is early as is increases the list of mandatory tokens.
    if (parsedHeader.containsKey(DigestAuthorizationToken.MESSAGE_QOP)) {
        qop = DigestQop.forName(parsedHeader.get(DigestAuthorizationToken.MESSAGE_QOP));
        if (qop == null || !supportedQops.contains(qop)) {
            // We are also ensuring the client is not trying to force a qop that has been disabled.
            REQUEST_LOGGER.invalidTokenReceived(DigestAuthorizationToken.MESSAGE_QOP.getName(), parsedHeader.get(DigestAuthorizationToken.MESSAGE_QOP));
            // TODO - This actually needs to result in a HTTP 400 Bad Request response and not a new challenge.
            return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
        }
        context.setQop(qop);
        mandatoryTokens.add(DigestAuthorizationToken.CNONCE);
        mandatoryTokens.add(DigestAuthorizationToken.NONCE_COUNT);
    }
    // Check all mandatory tokens are present.
    mandatoryTokens.removeAll(parsedHeader.keySet());
    if (mandatoryTokens.size() > 0) {
        for (DigestAuthorizationToken currentToken : mandatoryTokens) {
            // TODO - Need a better check and possible concatenate the list of tokens - however
            // even having one missing token is not something we should routinely expect.
            REQUEST_LOGGER.missingAuthorizationToken(currentToken.getName());
        }
        // TODO - This actually needs to result in a HTTP 400 Bad Request response and not a new challenge.
        return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
    }
    // Perform some validation of the remaining tokens.
    if (!realmName.equals(parsedHeader.get(DigestAuthorizationToken.REALM))) {
        REQUEST_LOGGER.invalidTokenReceived(DigestAuthorizationToken.REALM.getName(), parsedHeader.get(DigestAuthorizationToken.REALM));
        // TODO - This actually needs to result in a HTTP 400 Bad Request response and not a new challenge.
        return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
    }
    if (parsedHeader.containsKey(DigestAuthorizationToken.DIGEST_URI)) {
        String uri = parsedHeader.get(DigestAuthorizationToken.DIGEST_URI);
        String requestURI = exchange.getRequestURI();
        if (!exchange.getQueryString().isEmpty()) {
            requestURI = requestURI + "?" + exchange.getQueryString();
        }
        if (!uri.equals(requestURI)) {
            // it is possible we were given an absolute URI
            // we reconstruct the URI from the host header to make sure they match up
            // I am not sure if this is overly strict, however I think it is better
            // to be safe than sorry
            requestURI = exchange.getRequestURL();
            if (!exchange.getQueryString().isEmpty()) {
                requestURI = requestURI + "?" + exchange.getQueryString();
            }
            if (!uri.equals(requestURI)) {
                // just end the auth process
                exchange.setStatusCode(StatusCodes.BAD_REQUEST);
                exchange.endExchange();
                return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
            }
        }
    } else {
        return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
    }
    if (parsedHeader.containsKey(DigestAuthorizationToken.OPAQUE)) {
        if (!OPAQUE_VALUE.equals(parsedHeader.get(DigestAuthorizationToken.OPAQUE))) {
            REQUEST_LOGGER.invalidTokenReceived(DigestAuthorizationToken.OPAQUE.getName(), parsedHeader.get(DigestAuthorizationToken.OPAQUE));
            return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
        }
    }
    DigestAlgorithm algorithm;
    if (parsedHeader.containsKey(DigestAuthorizationToken.ALGORITHM)) {
        algorithm = DigestAlgorithm.forName(parsedHeader.get(DigestAuthorizationToken.ALGORITHM));
        if (algorithm == null || !supportedAlgorithms.contains(algorithm)) {
            // We are also ensuring the client is not trying to force an algorithm that has been disabled.
            REQUEST_LOGGER.invalidTokenReceived(DigestAuthorizationToken.ALGORITHM.getName(), parsedHeader.get(DigestAuthorizationToken.ALGORITHM));
            // TODO - This actually needs to result in a HTTP 400 Bad Request response and not a new challenge.
            return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
        }
    } else {
        // We know this is safe as the algorithm token was made mandatory
        // if MD5 is not supported.
        algorithm = DigestAlgorithm.MD5;
    }
    try {
        context.setAlgorithm(algorithm);
    } catch (NoSuchAlgorithmException e) {
        /*
             * This should not be possible in a properly configured installation.
             */
        REQUEST_LOGGER.exceptionProcessingRequest(e);
        return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
    }
    final String userName = parsedHeader.get(DigestAuthorizationToken.USERNAME);
    final IdentityManager identityManager = getIdentityManager(securityContext);
    final Account account;
    if (algorithm.isSession()) {
        /* This can follow one of the following: -
             *   1 - New session so use DigestCredentialImpl with the IdentityManager to
             *       create a new session key.
             *   2 - Obtain the existing session key from the session store and validate it, just use
             *       IdentityManager to validate account is still active and the current role assignment.
             */
        throw new IllegalStateException("Not yet implemented.");
    } else {
        final DigestCredential credential = new DigestCredentialImpl(context);
        account = identityManager.verify(userName, credential);
    }
    if (account == null) {
        // Authentication has failed, this could either be caused by the user not-existing or it
        // could be caused due to an invalid hash.
        securityContext.authenticationFailed(MESSAGES.authenticationFailed(userName), mechanismName);
        return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
    }
    // Step 3 - Verify that the nonce was eligible to be used.
    if (!validateNonceUse(context, parsedHeader, exchange)) {
        // TODO - This is the right place to make use of the decision but the check needs to be much much sooner
        // otherwise a failure server
        // side could leave a packet that could be 're-played' after the failed auth.
        // The username and password verification passed but for some reason we do not like the nonce.
        context.markStale();
        // can easily hit this point.
        return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
    }
    // We have authenticated the remote user.
    sendAuthenticationInfoHeader(exchange);
    securityContext.authenticationComplete(account, mechanismName, false);
    return AuthenticationMechanismOutcome.AUTHENTICATED;
// Step 4 - Set up any QOP related requirements.
// TODO - Do QOP
}
Also used : Account(io.undertow.security.idm.Account) IdentityManager(io.undertow.security.idm.IdentityManager) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) DigestCredential(io.undertow.security.idm.DigestCredential) DigestAlgorithm(io.undertow.security.idm.DigestAlgorithm)

Aggregations

DigestAlgorithm (io.undertow.security.idm.DigestAlgorithm)6 DigestQop (io.undertow.security.impl.DigestQop)3 AuthenticationMechanism (io.undertow.security.api.AuthenticationMechanism)2 AuthenticationMode (io.undertow.security.api.AuthenticationMode)2 AuthenticationCallHandler (io.undertow.security.handlers.AuthenticationCallHandler)2 AuthenticationConstraintHandler (io.undertow.security.handlers.AuthenticationConstraintHandler)2 AuthenticationMechanismsHandler (io.undertow.security.handlers.AuthenticationMechanismsHandler)2 SecurityInitialHandler (io.undertow.security.handlers.SecurityInitialHandler)2 Account (io.undertow.security.idm.Account)2 IdentityManager (io.undertow.security.idm.IdentityManager)2 BasicAuthenticationMechanism (io.undertow.security.impl.BasicAuthenticationMechanism)2 CachedAuthenticatedSessionMechanism (io.undertow.security.impl.CachedAuthenticatedSessionMechanism)2 DigestAuthenticationMechanism (io.undertow.security.impl.DigestAuthenticationMechanism)2 SimpleNonceManager (io.undertow.security.impl.SimpleNonceManager)2 HttpHandler (io.undertow.server.HttpHandler)2 HttpServerExchange (io.undertow.server.HttpServerExchange)2 PredicateHandler (io.undertow.server.handlers.PredicateHandler)2 HeaderMap (io.undertow.util.HeaderMap)2 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)2 ArrayList (java.util.ArrayList)2