Search in sources :

Example 1 with KeyManager

use of org.keycloak.models.KeyManager in project keycloak by keycloak.

the class SamlProtocol method authenticated.

@Override
public Response authenticated(AuthenticationSessionModel authSession, UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
    AuthenticatedClientSessionModel clientSession = clientSessionCtx.getClientSession();
    ClientModel client = clientSession.getClient();
    SamlClient samlClient = new SamlClient(client);
    String requestID = authSession.getClientNote(SAML_REQUEST_ID);
    String relayState = authSession.getClientNote(GeneralConstants.RELAY_STATE);
    String redirectUri = authSession.getRedirectUri();
    String responseIssuer = getResponseIssuer(realm);
    String nameIdFormat = getNameIdFormat(samlClient, authSession);
    int assertionLifespan = samlClient.getAssertionLifespan();
    SAML2LoginResponseBuilder builder = new SAML2LoginResponseBuilder();
    builder.requestID(requestID).destination(redirectUri).issuer(responseIssuer).assertionExpiration(assertionLifespan <= 0 ? realm.getAccessCodeLifespan() : assertionLifespan).subjectExpiration(assertionLifespan <= 0 ? realm.getAccessTokenLifespan() : assertionLifespan).sessionExpiration(realm.getSsoSessionMaxLifespan()).requestIssuer(clientSession.getClient().getClientId()).authMethod(JBossSAMLURIConstants.AC_UNSPECIFIED.get());
    String sessionIndex = SamlSessionUtils.getSessionIndex(clientSession);
    builder.sessionIndex(sessionIndex);
    if (!samlClient.includeAuthnStatement()) {
        builder.disableAuthnStatement(true);
    }
    builder.includeOneTimeUseCondition(samlClient.includeOneTimeUseCondition());
    List<ProtocolMapperProcessor<SAMLAttributeStatementMapper>> attributeStatementMappers = new LinkedList<>();
    List<ProtocolMapperProcessor<SAMLLoginResponseMapper>> loginResponseMappers = new LinkedList<>();
    AtomicReference<ProtocolMapperProcessor<SAMLRoleListMapper>> roleListMapper = new AtomicReference<>(null);
    List<ProtocolMapperProcessor<SAMLNameIdMapper>> samlNameIdMappers = new LinkedList<>();
    ProtocolMapperUtils.getSortedProtocolMappers(session, clientSessionCtx).forEach(entry -> {
        ProtocolMapperModel mapping = entry.getKey();
        ProtocolMapper mapper = entry.getValue();
        if (mapper instanceof SAMLAttributeStatementMapper) {
            attributeStatementMappers.add(new ProtocolMapperProcessor<>((SAMLAttributeStatementMapper) mapper, mapping));
        }
        if (mapper instanceof SAMLLoginResponseMapper) {
            loginResponseMappers.add(new ProtocolMapperProcessor<>((SAMLLoginResponseMapper) mapper, mapping));
        }
        if (mapper instanceof SAMLRoleListMapper) {
            roleListMapper.set(new ProtocolMapperProcessor<>((SAMLRoleListMapper) mapper, mapping));
        }
        if (mapper instanceof SAMLNameIdMapper) {
            samlNameIdMappers.add(new ProtocolMapperProcessor<>((SAMLNameIdMapper) mapper, mapping));
        }
    });
    Document samlDocument = null;
    ResponseType samlModel = null;
    KeyManager keyManager = session.keys();
    KeyManager.ActiveRsaKey keys = keyManager.getActiveRsaKey(realm);
    boolean postBinding = isPostBinding(authSession);
    String keyName = samlClient.getXmlSigKeyInfoKeyNameTransformer().getKeyName(keys.getKid(), keys.getCertificate());
    String nameId = getSAMLNameId(samlNameIdMappers, nameIdFormat, session, userSession, clientSession);
    if (nameId == null) {
        return samlErrorMessage(null, samlClient, isPostBinding(authSession), redirectUri, JBossSAMLURIConstants.STATUS_INVALID_NAMEIDPOLICY, relayState);
    }
    builder.nameIdentifier(nameIdFormat, nameId);
    // save NAME_ID and format in clientSession as they may be persistent or
    // transient or email and not username
    // we'll need to send this back on a logout
    clientSession.setNote(SAML_NAME_ID, nameId);
    clientSession.setNote(SAML_NAME_ID_FORMAT, nameIdFormat);
    try {
        if ((!postBinding) && samlClient.requiresRealmSignature() && samlClient.addExtensionsElementWithKeyInfo()) {
            builder.addExtension(new KeycloakKeySamlExtensionGenerator(keyName));
        }
        samlModel = builder.buildModel();
        final AttributeStatementType attributeStatement = populateAttributeStatements(attributeStatementMappers, session, userSession, clientSession);
        populateRoles(roleListMapper.get(), session, userSession, clientSessionCtx, attributeStatement);
        // SAML Spec 2.7.3 AttributeStatement must contain one or more Attribute or EncryptedAttribute
        if (attributeStatement.getAttributes().size() > 0) {
            AssertionType assertion = samlModel.getAssertions().get(0).getAssertion();
            assertion.addStatement(attributeStatement);
        }
        samlModel = transformLoginResponse(loginResponseMappers, samlModel, session, userSession, clientSessionCtx);
    } catch (Exception e) {
        logger.error("failed", e);
        return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.FAILED_TO_PROCESS_RESPONSE);
    }
    JaxrsSAML2BindingBuilder bindingBuilder = new JaxrsSAML2BindingBuilder(session);
    bindingBuilder.relayState(relayState);
    if ("true".equals(clientSession.getNote(JBossSAMLURIConstants.SAML_HTTP_ARTIFACT_BINDING.get()))) {
        try {
            return buildArtifactAuthenticatedResponse(clientSession, redirectUri, samlModel, bindingBuilder);
        } catch (Exception e) {
            logger.error("failed", e);
            return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.FAILED_TO_PROCESS_RESPONSE);
        }
    }
    if (samlClient.requiresRealmSignature() || samlClient.requiresAssertionSignature()) {
        String canonicalization = samlClient.getCanonicalizationMethod();
        if (canonicalization != null) {
            bindingBuilder.canonicalizationMethod(canonicalization);
        }
        bindingBuilder.signatureAlgorithm(samlClient.getSignatureAlgorithm()).signWith(keyName, keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate());
        if (samlClient.requiresRealmSignature())
            bindingBuilder.signDocument();
        if (samlClient.requiresAssertionSignature())
            bindingBuilder.signAssertions();
    }
    if (samlClient.requiresEncryption()) {
        PublicKey publicKey = null;
        try {
            publicKey = SamlProtocolUtils.getEncryptionKey(client);
        } catch (Exception e) {
            logger.error("failed", e);
            return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.FAILED_TO_PROCESS_RESPONSE);
        }
        bindingBuilder.encrypt(publicKey);
    }
    try {
        samlDocument = builder.buildDocument(samlModel);
        return buildAuthenticatedResponse(clientSession, redirectUri, samlDocument, bindingBuilder);
    } catch (Exception e) {
        logger.error("failed", e);
        return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.FAILED_TO_PROCESS_RESPONSE);
    }
}
Also used : ProtocolMapper(org.keycloak.protocol.ProtocolMapper) SAMLNameIdMapper(org.keycloak.protocol.saml.mappers.SAMLNameIdMapper) Document(org.w3c.dom.Document) KeycloakKeySamlExtensionGenerator(org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator) SAMLAttributeStatementMapper(org.keycloak.protocol.saml.mappers.SAMLAttributeStatementMapper) SAMLLoginResponseMapper(org.keycloak.protocol.saml.mappers.SAMLLoginResponseMapper) SAML2LoginResponseBuilder(org.keycloak.saml.SAML2LoginResponseBuilder) KeyManager(org.keycloak.models.KeyManager) SAMLRoleListMapper(org.keycloak.protocol.saml.mappers.SAMLRoleListMapper) PublicKey(java.security.PublicKey) AttributeStatementType(org.keycloak.dom.saml.v2.assertion.AttributeStatementType) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) AtomicReference(java.util.concurrent.atomic.AtomicReference) AssertionType(org.keycloak.dom.saml.v2.assertion.AssertionType) LinkedList(java.util.LinkedList) ParsingException(org.keycloak.saml.common.exceptions.ParsingException) ProcessingException(org.keycloak.saml.common.exceptions.ProcessingException) ConfigurationException(org.keycloak.saml.common.exceptions.ConfigurationException) IOException(java.io.IOException) ProtocolMapperModel(org.keycloak.models.ProtocolMapperModel) ArtifactResponseType(org.keycloak.dom.saml.v2.protocol.ArtifactResponseType) ResponseType(org.keycloak.dom.saml.v2.protocol.ResponseType) StatusResponseType(org.keycloak.dom.saml.v2.protocol.StatusResponseType) ClientModel(org.keycloak.models.ClientModel)

Example 2 with KeyManager

use of org.keycloak.models.KeyManager in project keycloak by keycloak.

the class ClientAttributeCertificateResource method getKeystore.

private byte[] getKeystore(KeyStoreConfig config, String privatePem, String certPem) {
    try {
        String format = config.getFormat();
        KeyStore keyStore;
        if (format.equals("JKS"))
            keyStore = KeyStore.getInstance("JKS");
        else
            keyStore = KeyStore.getInstance(format, "BC");
        keyStore.load(null, null);
        String keyAlias = config.getKeyAlias();
        if (keyAlias == null)
            keyAlias = client.getClientId();
        if (privatePem != null) {
            PrivateKey privateKey = PemUtils.decodePrivateKey(privatePem);
            X509Certificate clientCert = PemUtils.decodeCertificate(certPem);
            Certificate[] chain = { clientCert };
            keyStore.setKeyEntry(keyAlias, privateKey, config.getKeyPassword().trim().toCharArray(), chain);
        } else {
            X509Certificate clientCert = PemUtils.decodeCertificate(certPem);
            keyStore.setCertificateEntry(keyAlias, clientCert);
        }
        if (config.isRealmCertificate() == null || config.isRealmCertificate().booleanValue()) {
            KeyManager keys = session.keys();
            String kid = keys.getActiveRsaKey(realm).getKid();
            Certificate certificate = keys.getRsaCertificate(realm, kid);
            String certificateAlias = config.getRealmAlias();
            if (certificateAlias == null)
                certificateAlias = realm.getName();
            keyStore.setCertificateEntry(certificateAlias, certificate);
        }
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        keyStore.store(stream, config.getStorePassword().trim().toCharArray());
        stream.flush();
        stream.close();
        byte[] rtn = stream.toByteArray();
        return rtn;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
Also used : PrivateKey(java.security.PrivateKey) ByteArrayOutputStream(java.io.ByteArrayOutputStream) KeyStore(java.security.KeyStore) KeyManager(org.keycloak.models.KeyManager) X509Certificate(java.security.cert.X509Certificate) ErrorResponseException(org.keycloak.services.ErrorResponseException) BadRequestException(javax.ws.rs.BadRequestException) NotAcceptableException(javax.ws.rs.NotAcceptableException) IOException(java.io.IOException) NotFoundException(javax.ws.rs.NotFoundException) X509Certificate(java.security.cert.X509Certificate) Certificate(java.security.cert.Certificate)

Example 3 with KeyManager

use of org.keycloak.models.KeyManager in project keycloak by keycloak.

the class SamlProtocol method samlErrorMessage.

private Response samlErrorMessage(AuthenticationSessionModel authSession, SamlClient samlClient, boolean isPostBinding, String destination, JBossSAMLURIConstants statusDetail, String relayState) {
    JaxrsSAML2BindingBuilder binding = new JaxrsSAML2BindingBuilder(session).relayState(relayState);
    SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder().destination(destination).issuer(getResponseIssuer(realm)).status(statusDetail.get());
    KeyManager keyManager = session.keys();
    if (samlClient.requiresRealmSignature()) {
        KeyManager.ActiveRsaKey keys = keyManager.getActiveRsaKey(realm);
        String keyName = samlClient.getXmlSigKeyInfoKeyNameTransformer().getKeyName(keys.getKid(), keys.getCertificate());
        String canonicalization = samlClient.getCanonicalizationMethod();
        if (canonicalization != null) {
            binding.canonicalizationMethod(canonicalization);
        }
        binding.signatureAlgorithm(samlClient.getSignatureAlgorithm()).signWith(keyName, keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate()).signDocument();
    }
    try {
        // There is no support for encrypting status messages in SAML.
        // Only assertions, attributes, base ID and name ID can be encrypted
        // See Chapter 6 of saml-core-2.0-os.pdf
        Document document = builder.buildDocument();
        return buildErrorResponse(isPostBinding, destination, binding, document);
    } catch (Exception e) {
        return ErrorPage.error(session, authSession, Response.Status.BAD_REQUEST, Messages.FAILED_TO_PROCESS_RESPONSE);
    }
}
Also used : SAML2ErrorResponseBuilder(org.keycloak.saml.SAML2ErrorResponseBuilder) Document(org.w3c.dom.Document) KeyManager(org.keycloak.models.KeyManager) ParsingException(org.keycloak.saml.common.exceptions.ParsingException) ProcessingException(org.keycloak.saml.common.exceptions.ProcessingException) ConfigurationException(org.keycloak.saml.common.exceptions.ConfigurationException) IOException(java.io.IOException)

Example 4 with KeyManager

use of org.keycloak.models.KeyManager in project keycloak by keycloak.

the class SamlService method artifactResponseMessage.

private Response artifactResponseMessage(ArtifactResolveType artifactResolveMessage, Document artifactResponseDocument, ClientModel clientModel) throws ProcessingException, ConfigurationException {
    // Add "inResponseTo" to artifactResponse
    if (artifactResolveMessage.getID() != null && !artifactResolveMessage.getID().trim().isEmpty()) {
        Element artifactResponseElement = artifactResponseDocument.getDocumentElement();
        artifactResponseElement.setAttribute("InResponseTo", artifactResolveMessage.getID());
    }
    JaxrsSAML2BindingBuilder bindingBuilder = new JaxrsSAML2BindingBuilder(session);
    if (clientModel != null) {
        SamlClient samlClient = new SamlClient(clientModel);
        // Sign document/assertion if necessary, necessary to do this here, as the "inResponseTo" can only be set at this point
        if (samlClient.requiresRealmSignature() || samlClient.requiresAssertionSignature()) {
            KeyManager keyManager = session.keys();
            KeyManager.ActiveRsaKey keys = keyManager.getActiveRsaKey(realm);
            String keyName = samlClient.getXmlSigKeyInfoKeyNameTransformer().getKeyName(keys.getKid(), keys.getCertificate());
            String canonicalization = samlClient.getCanonicalizationMethod();
            if (canonicalization != null) {
                bindingBuilder.canonicalizationMethod(canonicalization);
            }
            bindingBuilder.signatureAlgorithm(samlClient.getSignatureAlgorithm()).signWith(keyName, keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate());
            if (samlClient.requiresRealmSignature())
                bindingBuilder.signDocument();
            if (samlClient.requiresAssertionSignature())
                bindingBuilder.signAssertions();
        }
        // Encrypt assertion if client requires it
        if (samlClient.requiresEncryption()) {
            PublicKey publicKey = null;
            try {
                publicKey = SamlProtocolUtils.getEncryptionKey(clientModel);
            } catch (Exception e) {
                logger.error("Failed to obtain encryption key for client", e);
                return emptyArtifactResponseMessage(artifactResolveMessage, null);
            }
            bindingBuilder.encrypt(publicKey);
        }
    }
    bindingBuilder.postBinding(artifactResponseDocument);
    Soap.SoapMessageBuilder messageBuilder = Soap.createMessage();
    messageBuilder.addToBody(artifactResponseDocument);
    if (logger.isDebugEnabled()) {
        String artifactResponse = DocumentUtil.asString(artifactResponseDocument);
        logger.debugf("Sending artifactResponse message for artifact %s. Message: \n %s", artifactResolveMessage.getArtifact(), artifactResponse);
    }
    return messageBuilder.build();
}
Also used : PublicKey(java.security.PublicKey) Element(org.w3c.dom.Element) Soap(org.keycloak.protocol.saml.profile.util.Soap) KeyManager(org.keycloak.models.KeyManager) ParsingException(org.keycloak.saml.common.exceptions.ParsingException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) VerificationException(org.keycloak.common.VerificationException) NotFoundException(javax.ws.rs.NotFoundException) ProcessingException(org.keycloak.saml.common.exceptions.ProcessingException) ConfigurationException(org.keycloak.saml.common.exceptions.ConfigurationException) ParserConfigurationException(javax.xml.parsers.ParserConfigurationException)

Aggregations

IOException (java.io.IOException)4 KeyManager (org.keycloak.models.KeyManager)4 ConfigurationException (org.keycloak.saml.common.exceptions.ConfigurationException)3 ParsingException (org.keycloak.saml.common.exceptions.ParsingException)3 ProcessingException (org.keycloak.saml.common.exceptions.ProcessingException)3 PublicKey (java.security.PublicKey)2 NotFoundException (javax.ws.rs.NotFoundException)2 Document (org.w3c.dom.Document)2 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 URISyntaxException (java.net.URISyntaxException)1 KeyStore (java.security.KeyStore)1 PrivateKey (java.security.PrivateKey)1 Certificate (java.security.cert.Certificate)1 X509Certificate (java.security.cert.X509Certificate)1 LinkedList (java.util.LinkedList)1 AtomicReference (java.util.concurrent.atomic.AtomicReference)1 BadRequestException (javax.ws.rs.BadRequestException)1 NotAcceptableException (javax.ws.rs.NotAcceptableException)1 ParserConfigurationException (javax.xml.parsers.ParserConfigurationException)1 VerificationException (org.keycloak.common.VerificationException)1