Search in sources :

Example 1 with SAML2LogoutResponseBuilder

use of org.keycloak.saml.SAML2LogoutResponseBuilder in project keycloak by keycloak.

the class LogoutTest method testLogoutWithPostBindingUnsetRedirectBindingSet.

@Test
public void testLogoutWithPostBindingUnsetRedirectBindingSet() {
    // https://issues.jboss.org/browse/KEYCLOAK-4779
    adminClient.realm(REALM_NAME).clients().get(sales2Rep.getId()).update(ClientBuilder.edit(sales2Rep).frontchannelLogout(true).attribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_POST_ATTRIBUTE, "").attribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_ATTRIBUTE, "http://url-to-sales-2").build());
    SAMLDocumentHolder samlResponse = prepareLogIntoTwoApps().logoutRequest(getAuthServerSamlEndpoint(REALM_NAME), SAML_CLIENT_ID_SALES_POST, POST).nameId(nameIdRef::get).sessionIndex(sessionIndexRef::get).build().processSamlResponse(REDIRECT).transformDocument(doc -> {
        // Expect logout request for sales-post2
        SAML2Object so = (SAML2Object) SAMLParser.getInstance().parse(new DOMSource(doc));
        assertThat(so, isSamlLogoutRequest("http://url-to-sales-2"));
        // Emulate successful logout response from sales-post2 logout
        return new SAML2LogoutResponseBuilder().destination(getAuthServerSamlEndpoint(REALM_NAME).toString()).issuer(SAML_CLIENT_ID_SALES_POST2).logoutRequestID(((LogoutRequestType) so).getID()).buildDocument();
    }).targetAttributeSamlResponse().targetUri(getAuthServerSamlEndpoint(REALM_NAME)).build().getSamlResponse(POST);
    // Expect final successful logout response from auth server signalling final successful logout
    assertThat(samlResponse.getSamlObject(), isSamlStatusResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
    assertThat(((StatusResponseType) samlResponse.getSamlObject()).getDestination(), is("http://url"));
    assertLogoutEvent(SAML_CLIENT_ID_SALES_POST2);
}
Also used : DOMSource(javax.xml.transform.dom.DOMSource) SAMLDocumentHolder(org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder) SAML2Object(org.keycloak.dom.saml.v2.SAML2Object) SAML2LogoutResponseBuilder(org.keycloak.saml.SAML2LogoutResponseBuilder) LogoutRequestType(org.keycloak.dom.saml.v2.protocol.LogoutRequestType) Test(org.junit.Test)

Example 2 with SAML2LogoutResponseBuilder

use of org.keycloak.saml.SAML2LogoutResponseBuilder in project keycloak by keycloak.

the class SamlProtocol method finishLogout.

@Override
public Response finishLogout(UserSessionModel userSession) {
    logger.debug("finishLogout");
    String logoutBindingUri = userSession.getNote(SAML_LOGOUT_BINDING_URI);
    if (logoutBindingUri == null) {
        logger.error("Can't finish SAML logout as there is no logout binding set.  Please configure the logout service url in the admin console for your client applications.");
        return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.FAILED_LOGOUT);
    }
    String logoutRelayState = userSession.getNote(SAML_LOGOUT_RELAY_STATE);
    SAML2LogoutResponseBuilder builder = new SAML2LogoutResponseBuilder();
    builder.logoutRequestID(userSession.getNote(SAML_LOGOUT_REQUEST_ID));
    builder.destination(logoutBindingUri);
    builder.issuer(getResponseIssuer(realm));
    JaxrsSAML2BindingBuilder binding = new JaxrsSAML2BindingBuilder(session);
    binding.relayState(logoutRelayState);
    String signingAlgorithm = userSession.getNote(SAML_LOGOUT_SIGNATURE_ALGORITHM);
    boolean postBinding = isLogoutPostBindingForInitiator(userSession);
    if (signingAlgorithm != null) {
        SignatureAlgorithm algorithm = SignatureAlgorithm.valueOf(signingAlgorithm);
        String canonicalization = userSession.getNote(SAML_LOGOUT_CANONICALIZATION);
        if (canonicalization != null) {
            binding.canonicalizationMethod(canonicalization);
        }
        KeyManager.ActiveRsaKey keys = session.keys().getActiveRsaKey(realm);
        XmlKeyInfoKeyNameTransformer transformer = XmlKeyInfoKeyNameTransformer.from(userSession.getNote(SAML_SERVER_SIGNATURE_KEYINFO_KEY_NAME_TRANSFORMER), SamlClient.DEFAULT_XML_KEY_INFO_KEY_NAME_TRANSFORMER);
        String keyName = transformer.getKeyName(keys.getKid(), keys.getCertificate());
        binding.signatureAlgorithm(algorithm).signWith(keyName, keys.getPrivateKey(), keys.getPublicKey(), keys.getCertificate()).signDocument();
        boolean addExtension = (!postBinding) && Objects.equals("true", userSession.getNote(SamlProtocol.SAML_LOGOUT_ADD_EXTENSIONS_ELEMENT_WITH_KEY_INFO));
        if (addExtension) {
            // Only include extension if REDIRECT binding and signing whole SAML protocol message
            builder.addExtension(new KeycloakKeySamlExtensionGenerator(keyName));
        }
    }
    Response response;
    try {
        response = buildLogoutResponse(userSession, logoutBindingUri, builder, binding);
    } catch (ConfigurationException | ProcessingException | IOException e) {
        throw new RuntimeException(e);
    }
    if (logoutBindingUri != null) {
        event.detail(Details.REDIRECT_URI, logoutBindingUri);
    }
    event.event(EventType.LOGOUT).detail(Details.AUTH_METHOD, userSession.getAuthMethod()).client(session.getContext().getClient()).user(userSession.getUser()).session(userSession).detail(Details.USERNAME, userSession.getLoginUsername()).detail(Details.RESPONSE_MODE, postBinding ? SamlProtocol.SAML_POST_BINDING : SamlProtocol.SAML_REDIRECT_BINDING).detail(SamlProtocol.SAML_LOGOUT_REQUEST_ID, userSession.getNote(SAML_LOGOUT_REQUEST_ID)).success();
    return response;
}
Also used : SAML2LogoutResponseBuilder(org.keycloak.saml.SAML2LogoutResponseBuilder) XmlKeyInfoKeyNameTransformer(org.keycloak.saml.common.util.XmlKeyInfoKeyNameTransformer) SignatureAlgorithm(org.keycloak.saml.SignatureAlgorithm) IOException(java.io.IOException) KeycloakKeySamlExtensionGenerator(org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator) Response(javax.ws.rs.core.Response) CloseableHttpResponse(org.apache.http.client.methods.CloseableHttpResponse) ConfigurationException(org.keycloak.saml.common.exceptions.ConfigurationException) KeyManager(org.keycloak.models.KeyManager) ProcessingException(org.keycloak.saml.common.exceptions.ProcessingException)

Example 3 with SAML2LogoutResponseBuilder

use of org.keycloak.saml.SAML2LogoutResponseBuilder in project keycloak by keycloak.

the class WebBrowserSsoAuthenticationHandler method logoutRequest.

@Override
protected AuthOutcome logoutRequest(LogoutRequestType request, String relayState) {
    if (request.getSessionIndex() == null || request.getSessionIndex().isEmpty()) {
        sessionStore.logoutByPrincipal(request.getNameID().getValue());
    } else {
        sessionStore.logoutBySsoId(request.getSessionIndex());
    }
    String issuerURL = deployment.getEntityID();
    SAML2LogoutResponseBuilder builder = new SAML2LogoutResponseBuilder();
    builder.logoutRequestID(request.getID());
    builder.destination(deployment.getIDP().getSingleLogoutService().getResponseBindingUrl());
    builder.issuer(issuerURL);
    BaseSAML2BindingBuilder binding = new BaseSAML2BindingBuilder().relayState(relayState);
    if (deployment.getIDP().getSingleLogoutService().signResponse()) {
        if (deployment.getSignatureCanonicalizationMethod() != null)
            binding.canonicalizationMethod(deployment.getSignatureCanonicalizationMethod());
        binding.signatureAlgorithm(deployment.getSignatureAlgorithm()).signWith(null, deployment.getSigningKeyPair()).signDocument();
    // TODO: As part of KEYCLOAK-3810, add KeyID to the SAML document
    // <related DocumentBuilder>.addExtension(new KeycloakKeySamlExtensionGenerator(<key ID>));
    }
    try {
        SamlUtil.sendSaml(false, facade, deployment.getIDP().getSingleLogoutService().getResponseBindingUrl(), binding, builder.buildDocument(), deployment.getIDP().getSingleLogoutService().getResponseBinding());
    } catch (Exception e) {
        log.error("Could not send logout response SAML request", e);
        return AuthOutcome.FAILED;
    }
    return AuthOutcome.NOT_ATTEMPTED;
}
Also used : SAML2LogoutResponseBuilder(org.keycloak.saml.SAML2LogoutResponseBuilder) BaseSAML2BindingBuilder(org.keycloak.saml.BaseSAML2BindingBuilder)

Example 4 with SAML2LogoutResponseBuilder

use of org.keycloak.saml.SAML2LogoutResponseBuilder in project keycloak by keycloak.

the class ArtifactBindingTest method testSessionStateDuringArtifactBindingLogoutWithMoreFrontChannelClients.

// Won't work with openshift, because openshift wouldn't see ArtifactResolutionService
@AuthServerContainerExclude(AuthServerContainerExclude.AuthServer.REMOTE)
@Test
public void testSessionStateDuringArtifactBindingLogoutWithMoreFrontChannelClients() {
    getCleanup().addCleanup(ClientAttributeUpdater.forClient(adminClient, REALM_NAME, SAML_CLIENT_ID_SALES_POST).setAttribute(SamlConfigAttributes.SAML_ARTIFACT_BINDING, "true").setAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_ARTIFACT_ATTRIBUTE, "http://url").setFrontchannelLogout(true).update()).addCleanup(ClientAttributeUpdater.forClient(adminClient, REALM_NAME, SAML_CLIENT_ID_SALES_POST2).setAttribute(SamlConfigAttributes.SAML_ARTIFACT_BINDING, "true").setAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_ARTIFACT_ATTRIBUTE, "http://url").setFrontchannelLogout(true).update());
    ClientRepresentation salesRep = adminClient.realm(REALM_NAME).clients().findByClientId(SAML_CLIENT_ID_SALES_POST).get(0);
    final String salesRepId = salesRep.getId();
    ClientRepresentation salesRep2 = adminClient.realm(REALM_NAME).clients().findByClientId(SAML_CLIENT_ID_SALES_POST2).get(0);
    final String salesRep2Id = salesRep2.getId();
    final AtomicReference<String> userSessionId = new AtomicReference<>();
    SAMLDocumentHolder response = new SamlClientBuilder().authnRequest(getAuthServerSamlEndpoint(REALM_NAME), SAML_CLIENT_ID_SALES_POST2, SAML_ASSERTION_CONSUMER_URL_SALES_POST2, REDIRECT).setProtocolBinding(JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.getUri()).build().login().user(bburkeUser).build().handleArtifact(getAuthServerSamlEndpoint(REALM_NAME), SAML_CLIENT_ID_SALES_POST2).setBeforeStepChecks(new SessionStateChecker(testingClient.server()).storeUserSessionId(userSessionId).expectedClientSession(salesRep2Id).expectedState(UserSessionModel.State.LOGGED_IN).expectedNumberOfClientSessions(1).consumeUserSession(userSessionModel -> assertThat(userSessionModel, notNullValue())).consumeClientSession(salesRep2Id, clientSession -> assertThat(clientSession, notNullValue()))).verifyRedirect(true).build().authnRequest(getAuthServerSamlEndpoint(REALM_NAME), SAML_CLIENT_ID_SALES_POST, SAML_ASSERTION_CONSUMER_URL_SALES_POST, REDIRECT).setProtocolBinding(JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.getUri()).build().handleArtifact(getAuthServerSamlEndpoint(REALM_NAME), SAML_CLIENT_ID_SALES_POST).setBeforeStepChecks(new SessionStateChecker(testingClient.server()).expectedUserSession(userSessionId).expectedState(UserSessionModel.State.LOGGED_IN).expectedClientSession(salesRepId).expectedNumberOfClientSessions(2).expectedAction(salesRep2Id, null).expectedAction(salesRepId, null)).verifyRedirect(true).build().logoutRequest(getAuthServerSamlEndpoint(REALM_NAME), SAML_CLIENT_ID_SALES_POST2, REDIRECT).build().handleArtifact(getAuthServerSamlEndpoint(REALM_NAME), SAML_CLIENT_ID_SALES_POST).setBeforeStepChecks(new SessionStateChecker(testingClient.server()).expectedUserSession(userSessionId).expectedState(UserSessionModel.State.LOGGING_OUT).expectedClientSession(salesRepId).expectedNumberOfClientSessions(2).expectedAction(salesRepId, CommonClientSessionModel.Action.LOGGING_OUT).expectedAction(salesRep2Id, CommonClientSessionModel.Action.LOGGING_OUT)).setAfterStepChecks(new SessionStateChecker(testingClient.server()).setUserSessionProvider(session -> userSessionId.get()).expectedState(UserSessionModel.State.LOGGING_OUT).expectedNumberOfClientSessions(2).expectedAction(salesRepId, CommonClientSessionModel.Action.LOGGED_OUT).expectedAction(salesRep2Id, CommonClientSessionModel.Action.LOGGING_OUT)).verifyRedirect(true).build().doNotFollowRedirects().processSamlResponse(ARTIFACT_RESPONSE).transformDocument(doc -> {
        // Send LogoutResponse
        SAML2Object so = (SAML2Object) SAMLParser.getInstance().parse(new DOMSource(doc));
        return new SAML2LogoutResponseBuilder().destination(getAuthServerSamlEndpoint(REALM_NAME).toString()).issuer(SAML_CLIENT_ID_SALES_POST).logoutRequestID(((LogoutRequestType) so).getID()).buildDocument();
    }).targetBinding(REDIRECT).targetAttributeSamlResponse().targetUri(getAuthServerSamlEndpoint(REALM_NAME)).build().handleArtifact(getAuthServerSamlEndpoint(REALM_NAME), SAML_CLIENT_ID_SALES_POST2).verifyRedirect(true).setBeforeStepChecks(new SessionStateChecker(testingClient.server()).expectedUserSession(userSessionId).expectedClientSession(salesRep2Id).expectedState(UserSessionModel.State.LOGGED_OUT_UNCONFIRMED).expectedNumberOfClientSessions(2).expectedAction(salesRepId, CommonClientSessionModel.Action.LOGGED_OUT).expectedAction(salesRep2Id, CommonClientSessionModel.Action.LOGGING_OUT)).setAfterStepChecks(new SessionStateChecker(testingClient.server()).consumeUserSession(userSessionModel -> assertThat(userSessionModel, nullValue())).setUserSessionProvider(session -> userSessionId.get())).build().executeAndTransform(this::getArtifactResponse);
    assertThat(response.getSamlObject(), instanceOf(ArtifactResponseType.class));
    ArtifactResponseType artifactResponse = (ArtifactResponseType) response.getSamlObject();
    assertThat(artifactResponse.getSignature(), nullValue());
    assertThat(artifactResponse, isSamlStatusResponse(JBossSAMLURIConstants.STATUS_SUCCESS));
    assertThat(artifactResponse.getAny(), instanceOf(StatusResponseType.class));
}
Also used : SamlProtocolUtils(org.keycloak.protocol.saml.SamlProtocolUtils) AssertionUtil(org.keycloak.saml.processing.core.saml.v2.util.AssertionUtil) ClientAttributeUpdater(org.keycloak.testsuite.updaters.ClientAttributeUpdater) Matchers.statusCodeIsHC(org.keycloak.testsuite.util.Matchers.statusCodeIsHC) URISyntaxException(java.net.URISyntaxException) Matchers.not(org.hamcrest.Matchers.not) ARTIFACT_RESPONSE(org.keycloak.testsuite.util.SamlClient.Binding.ARTIFACT_RESPONSE) POST(org.keycloak.testsuite.util.SamlClient.Binding.POST) SAML2LogoutResponseBuilder(org.keycloak.saml.SAML2LogoutResponseBuilder) Matchers.isSamlLogoutRequest(org.keycloak.testsuite.util.Matchers.isSamlLogoutRequest) HandleArtifactStepBuilder(org.keycloak.testsuite.util.saml.HandleArtifactStepBuilder) EntityUtils(org.apache.http.util.EntityUtils) InfinispanTestTimeServiceRule(org.keycloak.testsuite.util.InfinispanTestTimeServiceRule) SAML2Object(org.keycloak.dom.saml.v2.SAML2Object) Matcher(java.util.regex.Matcher) ByteArrayInputStream(java.io.ByteArrayInputStream) Document(org.w3c.dom.Document) NameIDMappingResponseType(org.keycloak.dom.saml.v2.protocol.NameIDMappingResponseType) Matchers.nullValue(org.hamcrest.Matchers.nullValue) SamlClient(org.keycloak.testsuite.util.SamlClient) SamlUtils(org.keycloak.testsuite.util.SamlUtils) URI(java.net.URI) SAMLDocumentHolder(org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder) Matchers.isEmptyOrNullString(org.hamcrest.Matchers.isEmptyOrNullString) Awaitility.await(org.awaitility.Awaitility.await) Matchers.isSamlResponse(org.keycloak.testsuite.util.Matchers.isSamlResponse) Matchers.notNullValue(org.hamcrest.Matchers.notNullValue) ArtifactResponseType(org.keycloak.dom.saml.v2.protocol.ArtifactResponseType) SamlProtocol(org.keycloak.protocol.saml.SamlProtocol) RealmAttributeUpdater(org.keycloak.testsuite.updaters.RealmAttributeUpdater) IOUtil(org.keycloak.testsuite.utils.io.IOUtil) ClientRepresentation(org.keycloak.representations.idm.ClientRepresentation) Matchers.instanceOf(org.hamcrest.Matchers.instanceOf) ParsingException(org.keycloak.saml.common.exceptions.ParsingException) Base64(java.util.Base64) Response(javax.ws.rs.core.Response) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) Matchers.equalTo(org.hamcrest.Matchers.equalTo) Matchers.isSamlStatusResponse(org.keycloak.testsuite.util.Matchers.isSamlStatusResponse) SamlMessageReceiver(org.keycloak.testsuite.util.saml.SamlMessageReceiver) Matchers.is(org.hamcrest.Matchers.is) Pattern(java.util.regex.Pattern) Matchers.containsString(org.hamcrest.Matchers.containsString) SamlUtils.getSPInstallationDescriptor(org.keycloak.testsuite.util.SamlUtils.getSPInstallationDescriptor) SamlClientBuilder(org.keycloak.testsuite.util.SamlClientBuilder) SAMLParser(org.keycloak.saml.processing.core.parsers.saml.SAMLParser) DOMSource(javax.xml.transform.dom.DOMSource) AuthServerContainerExclude(org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude) SAML2Request(org.keycloak.saml.processing.api.saml.v2.request.SAML2Request) MessageDigest(java.security.MessageDigest) GeneralConstants(org.keycloak.saml.common.constants.GeneralConstants) ResponseType(org.keycloak.dom.saml.v2.protocol.ResponseType) SamlConfigAttributes(org.keycloak.protocol.saml.SamlConfigAttributes) Matchers.bodyHC(org.keycloak.testsuite.util.Matchers.bodyHC) AtomicReference(java.util.concurrent.atomic.AtomicReference) ArtifactBindingUtils(org.keycloak.protocol.saml.util.ArtifactBindingUtils) REDIRECT(org.keycloak.testsuite.util.SamlClient.Binding.REDIRECT) ProcessingException(org.keycloak.saml.common.exceptions.ProcessingException) CloseableHttpResponse(org.apache.http.client.methods.CloseableHttpResponse) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) CommonClientSessionModel(org.keycloak.sessions.CommonClientSessionModel) Soap(org.keycloak.protocol.saml.profile.util.Soap) Charsets(com.google.common.base.Charsets) SPSSODescriptorType(org.keycloak.dom.saml.v2.metadata.SPSSODescriptorType) JBossSAMLURIConstants(org.keycloak.saml.common.constants.JBossSAMLURIConstants) Matchers(org.hamcrest.Matchers) Test(org.junit.Test) IOException(java.io.IOException) UserSessionModel(org.keycloak.models.UserSessionModel) StatusResponseType(org.keycloak.dom.saml.v2.protocol.StatusResponseType) TimeUnit(java.util.concurrent.TimeUnit) Rule(org.junit.Rule) SamlDeployment(org.keycloak.adapters.saml.SamlDeployment) SessionStateChecker(org.keycloak.testsuite.util.saml.SessionStateChecker) LogoutRequestType(org.keycloak.dom.saml.v2.protocol.LogoutRequestType) DOMSource(javax.xml.transform.dom.DOMSource) SamlClientBuilder(org.keycloak.testsuite.util.SamlClientBuilder) SAML2LogoutResponseBuilder(org.keycloak.saml.SAML2LogoutResponseBuilder) LogoutRequestType(org.keycloak.dom.saml.v2.protocol.LogoutRequestType) AtomicReference(java.util.concurrent.atomic.AtomicReference) Matchers.isEmptyOrNullString(org.hamcrest.Matchers.isEmptyOrNullString) Matchers.containsString(org.hamcrest.Matchers.containsString) SessionStateChecker(org.keycloak.testsuite.util.saml.SessionStateChecker) StatusResponseType(org.keycloak.dom.saml.v2.protocol.StatusResponseType) ClientRepresentation(org.keycloak.representations.idm.ClientRepresentation) SAMLDocumentHolder(org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder) SAML2Object(org.keycloak.dom.saml.v2.SAML2Object) ArtifactResponseType(org.keycloak.dom.saml.v2.protocol.ArtifactResponseType) AuthServerContainerExclude(org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude) Test(org.junit.Test)

Aggregations

SAML2LogoutResponseBuilder (org.keycloak.saml.SAML2LogoutResponseBuilder)4 IOException (java.io.IOException)2 Response (javax.ws.rs.core.Response)2 DOMSource (javax.xml.transform.dom.DOMSource)2 CloseableHttpResponse (org.apache.http.client.methods.CloseableHttpResponse)2 Test (org.junit.Test)2 SAML2Object (org.keycloak.dom.saml.v2.SAML2Object)2 LogoutRequestType (org.keycloak.dom.saml.v2.protocol.LogoutRequestType)2 Charsets (com.google.common.base.Charsets)1 ByteArrayInputStream (java.io.ByteArrayInputStream)1 URI (java.net.URI)1 URISyntaxException (java.net.URISyntaxException)1 MessageDigest (java.security.MessageDigest)1 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)1 Base64 (java.util.Base64)1 TimeUnit (java.util.concurrent.TimeUnit)1 AtomicReference (java.util.concurrent.atomic.AtomicReference)1 Matcher (java.util.regex.Matcher)1 Pattern (java.util.regex.Pattern)1 EntityUtils (org.apache.http.util.EntityUtils)1