package org.keycloak.protocol.cas.utils;
import jakarta.ws.rs.core.HttpHeaders;
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.keycloak.connections.httpclient.HttpClientProvider;
import org.keycloak.models.KeycloakSession;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
public class LogoutHelper {
//although it looks alike, the CAS SLO protocol has nothing to do with SAML; so we build the format
//required by the spec manually
private static final String TEMPLATE = "\n" +
" @NOT_USED@\n" +
" $SESSION_IDENTIFIER\n" +
"";
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);
List 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 {
HttpClient httpClient = session.getProvider(HttpClientProvider.class).getHttpClient();
for (int i = 0; i < 2; i++) { // follow redirects once
HttpPost post = new HttpPost(url);
post.setEntity(postBody);
HttpResponse response = httpClient.execute(post);
try {
int status = response.getStatusLine().getStatusCode();
if (status == 302 && !url.endsWith("/")) {
String redirect = response.getFirstHeader(HttpHeaders.LOCATION).getValue();
String withSlash = url + "/";
if (withSlash.equals(redirect)) {
url = withSlash;
continue;
}
}
} finally {
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream is = entity.getContent();
if (is != null)
is.close();
}
}
break;
}
}
}