Search in sources :

Example 1 with ArtifactResolveType

use of org.keycloak.dom.saml.v2.protocol.ArtifactResolveType 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 2 with ArtifactResolveType

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

the class SamlService method artifactResolutionService.

/**
 * Handles SOAP messages. Chooses the correct response path depending on whether the message is of type ECP or Artifact
 * @param inputStream the data of the request.
 * @return The response to the SOAP message
 */
@POST
@Path(ARTIFACT_RESOLUTION_SERVICE_PATH)
@NoCache
@Consumes({ "application/soap+xml", MediaType.TEXT_XML })
public Response artifactResolutionService(InputStream inputStream) {
    Document soapBodyContents = Soap.extractSoapMessage(inputStream);
    ArtifactResolveType artifactResolveType = null;
    SAMLDocumentHolder samlDocumentHolder = null;
    try {
        samlDocumentHolder = SAML2Request.getSAML2ObjectFromDocument(soapBodyContents);
        if (samlDocumentHolder.getSamlObject() instanceof ArtifactResolveType) {
            logger.debug("Received artifact resolve message");
            artifactResolveType = (ArtifactResolveType) samlDocumentHolder.getSamlObject();
        }
    } catch (Exception e) {
        logger.errorf("Artifact resolution endpoint obtained request that contained no " + "ArtifactResolve message: %s", DocumentUtil.asString(soapBodyContents));
        return Soap.createFault().reason("").detail("").build();
    }
    if (artifactResolveType == null) {
        logger.errorf("Artifact resolution endpoint obtained request that contained no " + "ArtifactResolve message: %s", DocumentUtil.asString(soapBodyContents));
        return Soap.createFault().reason("").detail("").build();
    }
    try {
        return artifactResolve(artifactResolveType, samlDocumentHolder);
    } catch (Exception e) {
        try {
            return emptyArtifactResponseMessage(artifactResolveType, null, JBossSAMLURIConstants.STATUS_REQUEST_DENIED.getUri());
        } catch (ConfigurationException | ProcessingException configurationException) {
            String reason = "An error occurred while trying to return the artifactResponse";
            String detail = e.getMessage();
            if (detail == null) {
                detail = "";
            }
            logger.errorf("Failure during ArtifactResolve reason: %s, detail: %s", reason, detail);
            return Soap.createFault().reason(reason).detail(detail).build();
        }
    }
}
Also used : ArtifactResolveType(org.keycloak.dom.saml.v2.protocol.ArtifactResolveType) SAMLDocumentHolder(org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder) Document(org.w3c.dom.Document) 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) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Consumes(javax.ws.rs.Consumes) NoCache(org.jboss.resteasy.annotations.cache.NoCache)

Example 3 with ArtifactResolveType

use of org.keycloak.dom.saml.v2.protocol.ArtifactResolveType 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 ArtifactResolveType

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

the class SamlService method createArtifactResolve.

/**
 * Creates an ArtifactResolve document with the given issuer and artifact
 * @param issuer the value to set as "issuer"
 * @param artifact the value to set as "artifact"
 * @return the Document of the created ArtifactResolve message
 * @throws ProcessingException
 * @throws ParsingException
 * @throws ConfigurationException
 */
private Document createArtifactResolve(String issuer, String artifact) throws ProcessingException, ParsingException, ConfigurationException {
    ArtifactResolveType artifactResolve = new ArtifactResolveType(IDGenerator.create("ID_"), XMLTimeUtil.getIssueInstant());
    NameIDType nameIDType = new NameIDType();
    nameIDType.setValue(issuer);
    artifactResolve.setIssuer(nameIDType);
    artifactResolve.setArtifact(artifact);
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    XMLStreamWriter xmlStreamWriter = StaxUtil.getXMLStreamWriter(bos);
    new SAMLRequestWriter(xmlStreamWriter).write(artifactResolve);
    return DocumentUtil.getDocument(new ByteArrayInputStream(bos.toByteArray()));
}
Also used : ArtifactResolveType(org.keycloak.dom.saml.v2.protocol.ArtifactResolveType) ByteArrayInputStream(java.io.ByteArrayInputStream) XMLStreamWriter(javax.xml.stream.XMLStreamWriter) SAMLRequestWriter(org.keycloak.saml.processing.core.saml.v2.writers.SAMLRequestWriter) ByteArrayOutputStream(java.io.ByteArrayOutputStream) NameIDType(org.keycloak.dom.saml.v2.assertion.NameIDType)

Example 5 with ArtifactResolveType

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

the class SAMLRequestWriter method write.

public void write(ArtifactResolveType request) throws ProcessingException {
    StaxUtil.writeStartElement(writer, PROTOCOL_PREFIX, JBossSAMLConstants.ARTIFACT_RESOLVE.get(), PROTOCOL_NSURI.get());
    StaxUtil.writeNameSpace(writer, PROTOCOL_PREFIX, PROTOCOL_NSURI.get());
    StaxUtil.writeNameSpace(writer, ASSERTION_PREFIX, ASSERTION_NSURI.get());
    StaxUtil.writeDefaultNameSpace(writer, ASSERTION_NSURI.get());
    // Attributes
    StaxUtil.writeAttribute(writer, JBossSAMLConstants.ID.get(), request.getID());
    StaxUtil.writeAttribute(writer, JBossSAMLConstants.VERSION.get(), request.getVersion());
    StaxUtil.writeAttribute(writer, JBossSAMLConstants.ISSUE_INSTANT.get(), request.getIssueInstant().toString());
    URI destination = request.getDestination();
    if (destination != null)
        StaxUtil.writeAttribute(writer, JBossSAMLConstants.DESTINATION.get(), destination.toASCIIString());
    String consent = request.getConsent();
    if (StringUtil.isNotNull(consent))
        StaxUtil.writeAttribute(writer, JBossSAMLConstants.CONSENT.get(), consent);
    NameIDType issuer = request.getIssuer();
    if (issuer != null) {
        write(issuer, new QName(ASSERTION_NSURI.get(), JBossSAMLConstants.ISSUER.get(), ASSERTION_PREFIX));
    }
    Element sig = request.getSignature();
    if (sig != null) {
        StaxUtil.writeDOMElement(writer, sig);
    }
    ExtensionsType extensions = request.getExtensions();
    if (extensions != null && !extensions.getAny().isEmpty()) {
        write(extensions);
    }
    String artifact = request.getArtifact();
    if (StringUtil.isNotNull(artifact)) {
        StaxUtil.writeStartElement(writer, PROTOCOL_PREFIX, JBossSAMLConstants.ARTIFACT.get(), PROTOCOL_NSURI.get());
        StaxUtil.writeCharacters(writer, artifact);
        StaxUtil.writeEndElement(writer);
    }
    StaxUtil.writeEndElement(writer);
    StaxUtil.flush(writer);
}
Also used : QName(javax.xml.namespace.QName) Element(org.w3c.dom.Element) ExtensionsType(org.keycloak.dom.saml.v2.protocol.ExtensionsType) NameIDType(org.keycloak.dom.saml.v2.assertion.NameIDType) PROTOCOL_NSURI(org.keycloak.saml.common.constants.JBossSAMLURIConstants.PROTOCOL_NSURI) URI(java.net.URI) ASSERTION_NSURI(org.keycloak.saml.common.constants.JBossSAMLURIConstants.ASSERTION_NSURI)

Aggregations

ArtifactResolveType (org.keycloak.dom.saml.v2.protocol.ArtifactResolveType)6 ProcessingException (org.keycloak.saml.common.exceptions.ProcessingException)5 Document (org.w3c.dom.Document)5 ConfigurationException (org.keycloak.saml.common.exceptions.ConfigurationException)4 ParsingException (org.keycloak.saml.common.exceptions.ParsingException)4 ByteArrayInputStream (java.io.ByteArrayInputStream)3 ByteArrayOutputStream (java.io.ByteArrayOutputStream)3 ParserConfigurationException (javax.xml.parsers.ParserConfigurationException)3 XMLStreamWriter (javax.xml.stream.XMLStreamWriter)3 NameIDType (org.keycloak.dom.saml.v2.assertion.NameIDType)3 ArtifactResponseType (org.keycloak.dom.saml.v2.protocol.ArtifactResponseType)3 SAMLRequestWriter (org.keycloak.saml.processing.core.saml.v2.writers.SAMLRequestWriter)3 IOException (java.io.IOException)2 VerificationException (org.keycloak.common.VerificationException)2 StatusResponseType (org.keycloak.dom.saml.v2.protocol.StatusResponseType)2 SAMLDocumentHolder (org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder)2 StringWriter (java.io.StringWriter)1 URI (java.net.URI)1 URISyntaxException (java.net.URISyntaxException)1 PrivateKey (java.security.PrivateKey)1