src/main/java/org/keycloak/protocol/cas/CASLoginProtocol.java
@@ -143,8 +143,8 @@ } private void sendSingleLogoutRequest(String logoutUrl, String serviceTicket) { HttpEntity requestEntity = LogoutHelper.buildSingleLogoutRequest(serviceTicket); try { HttpEntity requestEntity = LogoutHelper.buildSingleLogoutRequest(serviceTicket); LogoutHelper.postWithRedirect(session, logoutUrl, requestEntity); logger.debug("Sent CAS single logout for service " + logoutUrl); } catch (IOException e) { src/main/java/org/keycloak/protocol/cas/utils/LogoutHelper.java
@@ -2,8 +2,11 @@ import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.message.BasicNameValuePair; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.keycloak.connections.httpclient.HttpClientProvider; @@ -16,6 +19,8 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.UUID; import java.util.LinkedList; import java.util.List; public class LogoutHelper { //although it looks alike, the CAS SLO protocol has nothing to do with SAML; so we build the format @@ -25,12 +30,14 @@ " <samlp:SessionIndex>$SESSION_IDENTIFIER</samlp:SessionIndex>\n" + "</samlp:LogoutRequest>"; public static HttpEntity buildSingleLogoutRequest(String serviceTicket) { public static HttpEntity buildSingleLogoutRequest(String serviceTicket) throws IOException { String id = "ID_" + UUID.randomUUID().toString(); String issueInstant = new SimpleDateFormat("yyyy-MM-dd'T'H:mm:ss").format(new Date()); String document = TEMPLATE.replace("$ID", id).replace("$ISSUE_INSTANT", issueInstant) .replace("$SESSION_IDENTIFIER", serviceTicket); return new StringEntity(document, ContentType.APPLICATION_XML.withCharset(StandardCharsets.UTF_8)); List<NameValuePair> parameters = new LinkedList<>(); parameters.add(new BasicNameValuePair("logoutRequest", document)); return new UrlEncodedFormEntity(parameters); } public static void postWithRedirect(KeycloakSession session, String url, HttpEntity postBody) throws IOException { src/test/java/org/keycloak/protocol/cas/LogoutHelperTest.java
@@ -1,12 +1,17 @@ package org.keycloak.protocol.cas; import org.apache.http.HttpEntity; import org.apache.http.NameValuePair; import org.apache.http.client.utils.URLEncodedUtils; import org.junit.Test; import org.keycloak.protocol.cas.utils.LogoutHelper; import org.keycloak.saml.common.constants.JBossSAMLURIConstants; import org.keycloak.saml.common.util.DocumentUtil; import org.w3c.dom.Document; import org.w3c.dom.Node; import java.util.List; import java.util.stream.Collectors; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -15,7 +20,12 @@ @Test public void testLogoutRequest() throws Exception { HttpEntity requestEntity = LogoutHelper.buildSingleLogoutRequest("ST-test"); Document doc = DocumentUtil.getDocument(requestEntity.getContent()); List<NameValuePair> parameters = URLEncodedUtils.parse(requestEntity).stream().filter(parameter -> "logoutRequest".equals(parameter.getName())).collect(Collectors.toList()); assertEquals(1, parameters.size()); String logoutRequest = parameters.get(0).getValue(); Document doc = DocumentUtil.getDocument(logoutRequest); assertEquals("LogoutRequest", doc.getDocumentElement().getLocalName()); assertEquals(JBossSAMLURIConstants.PROTOCOL_NSURI.get(), doc.getDocumentElement().getNamespaceURI());