Search in sources :

Example 1 with IdentityManager

use of io.undertow.security.idm.IdentityManager in project syncany by syncany.

the class WebServer method initServer.

private void initServer(DaemonConfigTO daemonConfigTO) throws Exception {
    WebServerTO webServerConfig = daemonConfigTO.getWebServer();
    // Bind address and port
    String bindAddress = webServerConfig.getBindAddress();
    int bindPort = webServerConfig.getBindPort();
    // Users (incl. CLI user!)
    List<UserTO> users = readWebServerUsers(daemonConfigTO);
    IdentityManager identityManager = new MapIdentityManager(users);
    // (Re-)generate keypair/certificate (if requested)
    boolean certificateAutoGenerate = webServerConfig.isCertificateAutoGenerate();
    String certificateCommonName = webServerConfig.getCertificateCommonName();
    if (certificateAutoGenerate && certificateCommonNameChanged(certificateCommonName)) {
        generateNewKeyPairAndCertificate(certificateCommonName);
    }
    // Set up the handlers for WebSocket, REST and the web interface
    HttpHandler pathHttpHandler = path().addPrefixPath(API_ENDPOINT_WS_XML, websocket(new InternalWebSocketHandler(this, certificateCommonName, RequestFormatType.XML))).addPrefixPath(API_ENDPOINT_WS_JSON, websocket(new InternalWebSocketHandler(this, certificateCommonName, RequestFormatType.JSON))).addPrefixPath(API_ENDPOINT_REST_XML, new InternalRestHandler(this, RequestFormatType.XML)).addPrefixPath(API_ENDPOINT_REST_JSON, new InternalRestHandler(this, RequestFormatType.JSON)).addPrefixPath("/", new InternalWebInterfaceHandler());
    // Add some security spices
    HttpHandler securityPathHttpHandler = addSecurity(pathHttpHandler, identityManager);
    SSLContext sslContext = UserConfig.createUserSSLContext();
    // And go for it!
    webServer = Undertow.builder().addHttpsListener(bindPort, bindAddress, sslContext).setHandler(securityPathHttpHandler).build();
    logger.log(Level.INFO, "Initialized web server.");
}
Also used : WebServerTO(org.syncany.config.to.WebServerTO) HttpHandler(io.undertow.server.HttpHandler) IdentityManager(io.undertow.security.idm.IdentityManager) InternalWebSocketHandler(org.syncany.operations.daemon.handlers.InternalWebSocketHandler) SSLContext(javax.net.ssl.SSLContext) InternalRestHandler(org.syncany.operations.daemon.handlers.InternalRestHandler) UserTO(org.syncany.config.to.UserTO) InternalWebInterfaceHandler(org.syncany.operations.daemon.handlers.InternalWebInterfaceHandler)

Example 2 with IdentityManager

use of io.undertow.security.idm.IdentityManager 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 3 with IdentityManager

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

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 = 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.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)

Example 4 with IdentityManager

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

the class FormAuthenticationMechanism method runFormAuth.

public AuthenticationMechanismOutcome runFormAuth(final HttpServerExchange exchange, final SecurityContext securityContext) {
    final FormDataParser parser = formParserFactory.createParser(exchange);
    if (parser == null) {
        UndertowLogger.SECURITY_LOGGER.debug("Could not authenticate as no form parser is present");
        // TODO - May need a better error signaling mechanism here to prevent repeated attempts.
        return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
    }
    try {
        final FormData data = parser.parseBlocking();
        final FormData.FormValue jUsername = data.getFirst("j_username");
        final FormData.FormValue jPassword = data.getFirst("j_password");
        if (jUsername == null || jPassword == null) {
            UndertowLogger.SECURITY_LOGGER.debugf("Could not authenticate as username or password was not present in the posted result for %s", exchange);
            return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
        }
        final String userName = jUsername.getValue();
        final String password = jPassword.getValue();
        AuthenticationMechanismOutcome outcome = null;
        PasswordCredential credential = new PasswordCredential(password.toCharArray());
        try {
            IdentityManager identityManager = getIdentityManager(securityContext);
            Account account = identityManager.verify(userName, credential);
            if (account != null) {
                securityContext.authenticationComplete(account, name, true);
                UndertowLogger.SECURITY_LOGGER.debugf("Authenticated user %s using for auth for %s", account.getPrincipal().getName(), exchange);
                outcome = AuthenticationMechanismOutcome.AUTHENTICATED;
            } else {
                securityContext.authenticationFailed(MESSAGES.authenticationFailed(userName), name);
            }
        } finally {
            if (outcome == AuthenticationMechanismOutcome.AUTHENTICATED) {
                handleRedirectBack(exchange);
                exchange.endExchange();
            }
            return outcome != null ? outcome : AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}
Also used : FormData(io.undertow.server.handlers.form.FormData) Account(io.undertow.security.idm.Account) IdentityManager(io.undertow.security.idm.IdentityManager) FormDataParser(io.undertow.server.handlers.form.FormDataParser) PasswordCredential(io.undertow.security.idm.PasswordCredential) IOException(java.io.IOException)

Example 5 with IdentityManager

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

the class GSSAPIAuthenticationMechanism method authenticate.

@Override
public AuthenticationMechanismOutcome authenticate(final HttpServerExchange exchange, final SecurityContext securityContext) {
    ServerConnection connection = exchange.getConnection();
    NegotiationContext negContext = connection.getAttachment(NegotiationContext.ATTACHMENT_KEY);
    if (negContext != null) {
        UndertowLogger.SECURITY_LOGGER.debugf("Existing negotiation context found for %s", exchange);
        exchange.putAttachment(NegotiationContext.ATTACHMENT_KEY, negContext);
        if (negContext.isEstablished()) {
            IdentityManager identityManager = getIdentityManager(securityContext);
            final Account account = identityManager.verify(new GSSContextCredential(negContext.getGssContext()));
            if (account != null) {
                securityContext.authenticationComplete(account, name, false);
                UndertowLogger.SECURITY_LOGGER.debugf("Authenticated as user %s with existing GSSAPI negotiation context for %s", account.getPrincipal().getName(), exchange);
                return AuthenticationMechanismOutcome.AUTHENTICATED;
            } else {
                UndertowLogger.SECURITY_LOGGER.debugf("Failed to authenticate with existing GSSAPI negotiation context for %s", exchange);
                return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
            }
        }
    }
    List<String> authHeaders = exchange.getRequestHeaders().get(AUTHORIZATION);
    if (authHeaders != null) {
        for (String current : authHeaders) {
            if (current.startsWith(NEGOTIATE_PREFIX)) {
                String base64Challenge = current.substring(NEGOTIATE_PREFIX.length());
                try {
                    ByteBuffer challenge = FlexBase64.decode(base64Challenge);
                    return runGSSAPI(exchange, challenge, securityContext);
                } catch (IOException e) {
                }
                // it was not correctly structured.
                return AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
            }
        }
    }
    // No suitable header was found so authentication was not even attempted.
    return AuthenticationMechanismOutcome.NOT_ATTEMPTED;
}
Also used : Account(io.undertow.security.idm.Account) IdentityManager(io.undertow.security.idm.IdentityManager) ServerConnection(io.undertow.server.ServerConnection) GSSContextCredential(io.undertow.security.idm.GSSContextCredential) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer)

Aggregations

IdentityManager (io.undertow.security.idm.IdentityManager)9 Account (io.undertow.security.idm.Account)6 HttpHandler (io.undertow.server.HttpHandler)3 IOException (java.io.IOException)3 HashMap (java.util.HashMap)3 DigestAlgorithm (io.undertow.security.idm.DigestAlgorithm)2 PasswordCredential (io.undertow.security.idm.PasswordCredential)2 ByteBuffer (java.nio.ByteBuffer)2 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)2 Undertow (io.undertow.Undertow)1 AuthenticationMechanism (io.undertow.security.api.AuthenticationMechanism)1 AuthenticationMechanismFactory (io.undertow.security.api.AuthenticationMechanismFactory)1 NotificationReceiver (io.undertow.security.api.NotificationReceiver)1 SecurityContext (io.undertow.security.api.SecurityContext)1 SecurityContextFactory (io.undertow.security.api.SecurityContextFactory)1 AuthenticationMechanismsHandler (io.undertow.security.handlers.AuthenticationMechanismsHandler)1 NotificationReceiverHandler (io.undertow.security.handlers.NotificationReceiverHandler)1 SecurityInitialHandler (io.undertow.security.handlers.SecurityInitialHandler)1 Credential (io.undertow.security.idm.Credential)1 DigestCredential (io.undertow.security.idm.DigestCredential)1