Search in sources :

Example 1 with ArtifactResponseType

use of org.keycloak.dom.saml.v2.protocol.ArtifactResponseType in project keycloak by keycloak.

the class SamlProtocolUtilsTest method testBuildArtifactResponse.

@Test
public void testBuildArtifactResponse() throws ConfigurationException, ProcessingException, ParsingException {
    ResponseType response = new SAML2LoginResponseBuilder().requestID(IDGenerator.create("ID_")).destination("http://localhost:8180/auth/realms/demo/broker/saml-broker/endpoint").issuer("http://saml.idp/saml").assertionExpiration(1000000).subjectExpiration(1000000).requestIssuer("http://localhost:8180/auth/realms/demo").nameIdentifier(JBossSAMLURIConstants.NAMEID_FORMAT_EMAIL.get(), "a@b.c").authMethod(JBossSAMLURIConstants.AC_UNSPECIFIED.get()).sessionIndex("idp:" + UUID.randomUUID()).buildModel();
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    SAMLResponseWriter writer = new SAMLResponseWriter(StaxUtil.getXMLStreamWriter(bos));
    writer.write(response);
    Document responseDoc = DocumentUtil.getDocument(new ByteArrayInputStream(bos.toByteArray()));
    ArtifactResponseType artifactResponseType = SamlProtocolUtils.buildArtifactResponse(responseDoc);
    Document doc = SamlProtocolUtils.convert(artifactResponseType);
    String artifactResponse = DocumentUtil.asString(doc);
    assertThat(artifactResponse, containsString("samlp:ArtifactResponse"));
    assertThat(artifactResponse, containsString("samlp:Response"));
    assertThat(artifactResponse, containsString("saml:Assertion"));
    assertThat(artifactResponse.indexOf("samlp:ArtifactResponse"), lessThan(artifactResponse.indexOf("samlp:Response")));
    assertThat(artifactResponse.indexOf("samlp:Response"), lessThan(artifactResponse.indexOf("saml:Assertion")));
    assertThat(artifactResponse.split("\\Q<saml:Issuer>http://saml.idp/saml</saml:Issuer>\\E").length, is(4));
    assertThat(artifactResponse.split("\\Q<samlp:StatusCode Value=\"urn:oasis:names:tc:SAML:2.0:status:Success\"/>\\E").length, is(3));
}
Also used : SAMLResponseWriter(org.keycloak.saml.processing.core.saml.v2.writers.SAMLResponseWriter) ByteArrayInputStream(java.io.ByteArrayInputStream) ArtifactResponseType(org.keycloak.dom.saml.v2.protocol.ArtifactResponseType) ByteArrayOutputStream(java.io.ByteArrayOutputStream) Matchers.containsString(org.hamcrest.Matchers.containsString) SAML2LoginResponseBuilder(org.keycloak.saml.SAML2LoginResponseBuilder) Document(org.w3c.dom.Document) ArtifactResponseType(org.keycloak.dom.saml.v2.protocol.ArtifactResponseType) ResponseType(org.keycloak.dom.saml.v2.protocol.ResponseType) Test(org.junit.Test)

Example 2 with ArtifactResponseType

use of org.keycloak.dom.saml.v2.protocol.ArtifactResponseType in project keycloak by keycloak.

the class SamlService method emptyArtifactResponseMessage.

private Response emptyArtifactResponseMessage(ArtifactResolveType artifactResolveMessage, ClientModel clientModel, URI responseStatusCode) throws ProcessingException, ConfigurationException {
    ArtifactResponseType artifactResponse = SamlProtocolUtils.buildArtifactResponse(null, SAML2NameIDBuilder.value(RealmsResource.realmBaseUrl(session.getContext().getUri()).build(realm.getName()).toString()).build(), responseStatusCode);
    Document artifactResponseDocument;
    try {
        artifactResponseDocument = SamlProtocolUtils.convert(artifactResponse);
    } catch (ParsingException | ConfigurationException | ProcessingException e) {
        logger.errorf("Failed to obtain document from ArtifactResponse: %s.", artifactResponse);
        throw new ProcessingException(Errors.INVALID_SAML_ARTIFACT_RESPONSE, e);
    }
    return artifactResponseMessage(artifactResolveMessage, artifactResponseDocument, clientModel);
}
Also used : ConfigurationException(org.keycloak.saml.common.exceptions.ConfigurationException) ParserConfigurationException(javax.xml.parsers.ParserConfigurationException) ParsingException(org.keycloak.saml.common.exceptions.ParsingException) ArtifactResponseType(org.keycloak.dom.saml.v2.protocol.ArtifactResponseType) Document(org.w3c.dom.Document) ProcessingException(org.keycloak.saml.common.exceptions.ProcessingException)

Example 3 with ArtifactResponseType

use of org.keycloak.dom.saml.v2.protocol.ArtifactResponseType in project keycloak by keycloak.

the class SamlService method artifactResolve.

/**
 * Takes an artifact resolve message and returns the artifact response, if the artifact is found belonging to a session
 * of the issuer.
 * @param artifactResolveMessage The artifact resolve message sent by the client
 * @param artifactResolveHolder the document containing the artifact resolve message sent by the client
 * @return a Response containing the SOAP message with the ArifactResponse
 * @throws ParsingException
 * @throws ConfigurationException
 * @throws ProcessingException
 */
public Response artifactResolve(ArtifactResolveType artifactResolveMessage, SAMLDocumentHolder artifactResolveHolder) throws ParsingException, ConfigurationException, ProcessingException {
    logger.debug("Received artifactResolve message for artifact " + artifactResolveMessage.getArtifact() + "\n" + "Message: \n" + DocumentUtil.getDocumentAsString(artifactResolveHolder.getSamlDocument()));
    // Artifact from resolve request
    String artifact = artifactResolveMessage.getArtifact();
    if (artifact == null) {
        logger.errorf("Artifact to resolve was null");
        return emptyArtifactResponseMessage(artifactResolveMessage, null, JBossSAMLURIConstants.STATUS_REQUEST_DENIED.getUri());
    }
    ArtifactResolver artifactResolver = getArtifactResolver(artifact);
    if (artifactResolver == null) {
        logger.errorf("Cannot find ArtifactResolver for artifact %s", artifact);
        return emptyArtifactResponseMessage(artifactResolveMessage, null, JBossSAMLURIConstants.STATUS_REQUEST_DENIED.getUri());
    }
    // Obtain details of session that issued artifact and check if it corresponds to issuer of Resolve message
    SamlArtifactSessionMappingModel sessionMapping = getArtifactSessionMappingStore().get(artifact);
    if (sessionMapping == null) {
        logger.errorf("No data stored for artifact %s", artifact);
        return emptyArtifactResponseMessage(artifactResolveMessage, null);
    }
    UserSessionModel userSessionModel = session.sessions().getUserSession(realm, sessionMapping.getUserSessionId());
    if (userSessionModel == null) {
        logger.errorf("UserSession with id: %s, that corresponds to artifact: %s does not exist.", sessionMapping.getUserSessionId(), artifact);
        return emptyArtifactResponseMessage(artifactResolveMessage, null);
    }
    AuthenticatedClientSessionModel clientSessionModel = userSessionModel.getAuthenticatedClientSessions().get(sessionMapping.getClientSessionId());
    if (clientSessionModel == null) {
        logger.errorf("ClientSession with id: %s, that corresponds to artifact: %s and UserSession: %s does not exist.", sessionMapping.getClientSessionId(), artifact, sessionMapping.getUserSessionId());
        return emptyArtifactResponseMessage(artifactResolveMessage, null);
    }
    ClientModel clientModel = getAndCheckClientModel(sessionMapping.getClientSessionId(), artifactResolveMessage.getIssuer().getValue());
    SamlClient samlClient = new SamlClient(clientModel);
    // Check signature within ArtifactResolve request if client requires it
    if (samlClient.requiresClientSignature()) {
        try {
            SamlProtocolUtils.verifyDocumentSignature(clientModel, artifactResolveHolder.getSamlDocument());
        } catch (VerificationException e) {
            SamlService.logger.error("request validation failed", e);
            return emptyArtifactResponseMessage(artifactResolveMessage, clientModel);
        }
    }
    // Obtain artifactResponse from clientSessionModel
    String artifactResponseString;
    try {
        artifactResponseString = artifactResolver.resolveArtifact(clientSessionModel, artifact);
    } catch (ArtifactResolverProcessingException e) {
        logger.errorf(e, "Failed to resolve artifact: %s.", artifact);
        return emptyArtifactResponseMessage(artifactResolveMessage, clientModel);
    }
    // Artifact is successfully resolved, we can remove session mapping from storage
    getArtifactSessionMappingStore().remove(artifact);
    Document artifactResponseDocument = null;
    ArtifactResponseType artifactResponseType = null;
    try {
        SAMLDataMarshaller marshaller = new SAMLDataMarshaller();
        artifactResponseType = marshaller.deserialize(artifactResponseString, ArtifactResponseType.class);
        artifactResponseDocument = SamlProtocolUtils.convert(artifactResponseType);
    } catch (ParsingException | ConfigurationException | ProcessingException e) {
        logger.errorf(e, "Failed to obtain document from ArtifactResponseString: %s.", artifactResponseString);
        return emptyArtifactResponseMessage(artifactResolveMessage, clientModel);
    }
    // If clientSession is in LOGGING_OUT action, now we can move it to LOGGED_OUT
    if (CommonClientSessionModel.Action.LOGGING_OUT.name().equals(clientSessionModel.getAction())) {
        clientSessionModel.setAction(CommonClientSessionModel.Action.LOGGED_OUT.name());
        // If Keycloak sent LogoutResponse we need to also remove UserSession
        if (artifactResponseType.getAny() instanceof StatusResponseType && artifactResponseString.contains(JBossSAMLConstants.LOGOUT_RESPONSE.get())) {
            if (!UserSessionModel.State.LOGGED_OUT_UNCONFIRMED.equals(userSessionModel.getState())) {
                logger.warnf("Keycloak issued LogoutResponse for clientSession %s, however user session %s was not in LOGGED_OUT_UNCONFIRMED state.", clientSessionModel.getId(), userSessionModel.getId());
            }
            AuthenticationManager.finishUnconfirmedUserSession(session, realm, userSessionModel);
        }
    }
    return artifactResponseMessage(artifactResolveMessage, artifactResponseDocument, clientModel);
}
Also used : UserSessionModel(org.keycloak.models.UserSessionModel) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) Document(org.w3c.dom.Document) SAMLDataMarshaller(org.keycloak.broker.saml.SAMLDataMarshaller) StatusResponseType(org.keycloak.dom.saml.v2.protocol.StatusResponseType) SamlArtifactSessionMappingModel(org.keycloak.models.SamlArtifactSessionMappingModel) ClientModel(org.keycloak.models.ClientModel) ConfigurationException(org.keycloak.saml.common.exceptions.ConfigurationException) ParserConfigurationException(javax.xml.parsers.ParserConfigurationException) ParsingException(org.keycloak.saml.common.exceptions.ParsingException) VerificationException(org.keycloak.common.VerificationException) ArtifactResponseType(org.keycloak.dom.saml.v2.protocol.ArtifactResponseType) ProcessingException(org.keycloak.saml.common.exceptions.ProcessingException)

Example 4 with ArtifactResponseType

use of org.keycloak.dom.saml.v2.protocol.ArtifactResponseType in project keycloak by keycloak.

the class SAMLResponseWriter method write.

public void write(ArtifactResponseType response) throws ProcessingException {
    StaxUtil.writeStartElement(writer, PROTOCOL_PREFIX, JBossSAMLConstants.ARTIFACT_RESPONSE.get(), JBossSAMLURIConstants.PROTOCOL_NSURI.get());
    StaxUtil.writeNameSpace(writer, PROTOCOL_PREFIX, JBossSAMLURIConstants.PROTOCOL_NSURI.get());
    StaxUtil.writeNameSpace(writer, ASSERTION_PREFIX, JBossSAMLURIConstants.ASSERTION_NSURI.get());
    StaxUtil.writeDefaultNameSpace(writer, JBossSAMLURIConstants.ASSERTION_NSURI.get());
    writeBaseAttributes(response);
    NameIDType issuer = response.getIssuer();
    if (issuer != null) {
        write(issuer, new QName(JBossSAMLURIConstants.ASSERTION_NSURI.get(), JBossSAMLConstants.ISSUER.get(), ASSERTION_PREFIX));
    }
    Element sig = response.getSignature();
    if (sig != null) {
        StaxUtil.writeDOMElement(writer, sig);
    }
    ExtensionsType extensions = response.getExtensions();
    if (extensions != null && extensions.getAny() != null && !extensions.getAny().isEmpty()) {
        write(extensions);
    }
    StatusType status = response.getStatus();
    if (status != null) {
        write(status);
    }
    Object anyObj = response.getAny();
    if (anyObj instanceof AuthnRequestType) {
        AuthnRequestType authn = (AuthnRequestType) anyObj;
        SAMLRequestWriter requestWriter = new SAMLRequestWriter(writer);
        requestWriter.write(authn);
    } else if (anyObj instanceof LogoutRequestType) {
        LogoutRequestType logoutRequestType = (LogoutRequestType) anyObj;
        SAMLRequestWriter requestWriter = new SAMLRequestWriter(writer);
        requestWriter.write(logoutRequestType);
    } else if (anyObj instanceof ResponseType) {
        ResponseType rt = (ResponseType) anyObj;
        write(rt);
    } else if (anyObj instanceof StatusResponseType) {
        StatusResponseType rt = (StatusResponseType) anyObj;
        write(rt, new QName(PROTOCOL_NSURI.get(), JBossSAMLConstants.LOGOUT_RESPONSE.get(), "samlp"));
    }
    StaxUtil.writeEndElement(writer);
    StaxUtil.flush(writer);
}
Also used : AuthnRequestType(org.keycloak.dom.saml.v2.protocol.AuthnRequestType) QName(javax.xml.namespace.QName) StatusType(org.keycloak.dom.saml.v2.protocol.StatusType) Element(org.w3c.dom.Element) ExtensionsType(org.keycloak.dom.saml.v2.protocol.ExtensionsType) LogoutRequestType(org.keycloak.dom.saml.v2.protocol.LogoutRequestType) NameIDType(org.keycloak.dom.saml.v2.assertion.NameIDType) StatusResponseType(org.keycloak.dom.saml.v2.protocol.StatusResponseType) ArtifactResponseType(org.keycloak.dom.saml.v2.protocol.ArtifactResponseType) ResponseType(org.keycloak.dom.saml.v2.protocol.ResponseType) StatusResponseType(org.keycloak.dom.saml.v2.protocol.StatusResponseType)

Example 5 with ArtifactResponseType

use of org.keycloak.dom.saml.v2.protocol.ArtifactResponseType in project keycloak by keycloak.

the class SamlDocumentStepBuilder method saml2Object2String.

public static String saml2Object2String(final SAML2Object transformed) {
    try {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        XMLStreamWriter xmlStreamWriter = StaxUtil.getXMLStreamWriter(bos);
        if (transformed instanceof AuthnRequestType) {
            new SAMLRequestWriter(xmlStreamWriter).write((AuthnRequestType) transformed);
        } else if (transformed instanceof LogoutRequestType) {
            new SAMLRequestWriter(xmlStreamWriter).write((LogoutRequestType) transformed);
        } else if (transformed instanceof ArtifactResolveType) {
            new SAMLRequestWriter(xmlStreamWriter).write((ArtifactResolveType) transformed);
        } else if (transformed instanceof AttributeQueryType) {
            new SAMLRequestWriter(xmlStreamWriter).write((AttributeQueryType) transformed);
        } else if (transformed instanceof ResponseType) {
            new SAMLResponseWriter(xmlStreamWriter).write((ResponseType) transformed);
        } else if (transformed instanceof ArtifactResponseType) {
            new SAMLResponseWriter(xmlStreamWriter).write((ArtifactResponseType) transformed);
        } else if (transformed instanceof StatusResponseType) {
            new SAMLResponseWriter(xmlStreamWriter).write((StatusResponseType) transformed, SAMLProtocolQNames.LOGOUT_RESPONSE.getQName("samlp"));
        } else {
            Assert.assertNotNull("Unknown type: <null>", transformed);
            Assert.fail("Unknown type: " + transformed.getClass().getName());
        }
        return new String(bos.toByteArray(), GeneralConstants.SAML_CHARSET);
    } catch (ProcessingException ex) {
        throw new RuntimeException(ex);
    }
}
Also used : ArtifactResolveType(org.keycloak.dom.saml.v2.protocol.ArtifactResolveType) LogoutRequestType(org.keycloak.dom.saml.v2.protocol.LogoutRequestType) ByteArrayOutputStream(java.io.ByteArrayOutputStream) StatusResponseType(org.keycloak.dom.saml.v2.protocol.StatusResponseType) ResponseType(org.keycloak.dom.saml.v2.protocol.ResponseType) ArtifactResponseType(org.keycloak.dom.saml.v2.protocol.ArtifactResponseType) StatusResponseType(org.keycloak.dom.saml.v2.protocol.StatusResponseType) SAMLResponseWriter(org.keycloak.saml.processing.core.saml.v2.writers.SAMLResponseWriter) AuthnRequestType(org.keycloak.dom.saml.v2.protocol.AuthnRequestType) XMLStreamWriter(javax.xml.stream.XMLStreamWriter) SAMLRequestWriter(org.keycloak.saml.processing.core.saml.v2.writers.SAMLRequestWriter) ArtifactResponseType(org.keycloak.dom.saml.v2.protocol.ArtifactResponseType) AttributeQueryType(org.keycloak.dom.saml.v2.protocol.AttributeQueryType) ProcessingException(org.keycloak.saml.common.exceptions.ProcessingException)

Aggregations

ArtifactResponseType (org.keycloak.dom.saml.v2.protocol.ArtifactResponseType)25 Test (org.junit.Test)17 SAMLDocumentHolder (org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder)17 SamlClientBuilder (org.keycloak.testsuite.util.SamlClientBuilder)16 StatusResponseType (org.keycloak.dom.saml.v2.protocol.StatusResponseType)14 ResponseType (org.keycloak.dom.saml.v2.protocol.ResponseType)13 NameIDMappingResponseType (org.keycloak.dom.saml.v2.protocol.NameIDMappingResponseType)9 ProcessingException (org.keycloak.saml.common.exceptions.ProcessingException)7 Document (org.w3c.dom.Document)6 SamlDeployment (org.keycloak.adapters.saml.SamlDeployment)5 LogoutRequestType (org.keycloak.dom.saml.v2.protocol.LogoutRequestType)5 ParsingException (org.keycloak.saml.common.exceptions.ParsingException)5 ByteArrayInputStream (java.io.ByteArrayInputStream)4 ByteArrayOutputStream (java.io.ByteArrayOutputStream)3 IOException (java.io.IOException)3 Matchers.containsString (org.hamcrest.Matchers.containsString)3 Charsets (com.google.common.base.Charsets)2 URI (java.net.URI)2 URISyntaxException (java.net.URISyntaxException)2 MessageDigest (java.security.MessageDigest)2