/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* https://opensso.dev.java.net/public/CDDLv1.0.html or
* opensso/legal/CDDLv1.0.txt
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at opensso/legal/CDDLv1.0.txt.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* $Id: LogoutUtil.java,v 1.16 2009/11/20 21:41:16 exu Exp $
*
* Portions Copyrighted 2012-2015 ForgeRock AS.
*/
package com.sun.identity.saml2.profile;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import com.sun.identity.saml2.common.SOAPCommunicator;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import com.sun.identity.plugin.session.SessionException;
import com.sun.identity.shared.encode.Base64;
import com.sun.identity.shared.encode.URLEncDec;
import com.sun.identity.shared.debug.Debug;
import com.sun.identity.shared.xml.XMLUtils;
import com.sun.identity.saml.common.SAMLUtils;
import com.sun.identity.saml.xmlsig.KeyProvider;
import com.sun.identity.saml2.assertion.EncryptedID;
import com.sun.identity.saml2.assertion.Issuer;
import com.sun.identity.saml2.assertion.NameID;
import com.sun.identity.saml2.common.SAML2Constants;
import com.sun.identity.saml2.common.SAML2Exception;
import com.sun.identity.saml2.common.SAML2Utils;
import com.sun.identity.saml2.jaxb.entityconfig.BaseConfigType;
import com.sun.identity.saml2.jaxb.metadata.EndpointType;
import com.sun.identity.saml2.jaxb.metadata.IDPSSODescriptorElement;
import com.sun.identity.saml2.jaxb.metadata.KeyDescriptorType;
import com.sun.identity.saml2.jaxb.metadata.SPSSODescriptorElement;
import com.sun.identity.saml2.jaxb.metadata.SingleLogoutServiceElement;
import com.sun.identity.saml2.key.EncInfo;
import com.sun.identity.saml2.key.KeyUtil;
import com.sun.identity.saml2.logging.LogUtil;
import com.sun.identity.saml2.meta.SAML2MetaException;
import com.sun.identity.saml2.meta.SAML2MetaManager;
import com.sun.identity.saml2.meta.SAML2MetaUtils;
import com.sun.identity.saml2.plugins.FedletAdapter;
import com.sun.identity.saml2.protocol.Extensions;
import com.sun.identity.saml2.protocol.LogoutRequest;
import com.sun.identity.saml2.protocol.LogoutResponse;
import com.sun.identity.saml2.protocol.ProtocolFactory;
import com.sun.identity.saml2.protocol.SessionIndex;
import com.sun.identity.saml2.protocol.Status;
import com.sun.identity.saml2.protocol.StatusDetail;
/**
* This class constructs the <code>LogoutRequest</code> and executes
* the required processing logic for sending <code>LogoutRequest</code>
* from SP to IDP.
*/
public class LogoutUtil {
static KeyProvider keyProvider = KeyUtil.getKeyProviderInstance();
static SAML2MetaManager metaManager = null;
static Debug debug = SAML2Utils.debug;
static {
metaManager= SAML2Utils.getSAML2MetaManager();
}
/**
* Builds the <code>LogoutRequest</code> and executes
* the required processing logic for sending <code>LogoutRequest</code>
* from SP to IDP.
*
* @param metaAlias the requester's metaAlais.
* @param recipientEntityID the recipient's entity ID.
* @param recipientSLOList recipient's Single Logout Service location
* URL list.
* @param extensionsList Extension list for request.
* @param binding binding used for this request.
* @param relayState the target URL on successful Single Logout.
* @param sessionIndex sessionIndex of the Assertion generated by the
* Identity Provider or Service Provider.
* @param nameID <code>NameID</code> of the Provider.
* @param response the HttpServletResponse.
* @param paramsMap Map of all other parameters.
* Following parameters names with their respective
* String values are allowed in this paramsMap.
* "realm" - MetaAlias for Service Provider. The format of
* this parameter is /realm_name/SP name.
* "RelayState" - the target URL on successful Single Logout
* "Destination" - A URI Reference indicating the address to
* which the request has been sent.
* "Consent" - Specifies a URI a SAML defined identifier
* known as Consent Identifiers.
* @param config entity base config for basic auth.
*
* @return Logout request ID
*
* @throws SAML2Exception if error initiating request to IDP.
* @throws SessionException if error initiating request to IDP.
*/
public static StringBuffer doLogout(
String metaAlias,
String recipientEntityID,
List<EndpointType> recipientSLOList,
List extensionsList,
String binding,
String relayState,
String sessionIndex,
NameID nameID,
HttpServletRequest request,
HttpServletResponse response,
Map paramsMap,
BaseConfigType config) throws SAML2Exception, SessionException {
EndpointType logoutEndpoint = null;
for (EndpointType endpoint : recipientSLOList) {
if (binding.equals(endpoint.getBinding())) {
logoutEndpoint = endpoint;
break;
}
}
return doLogout(metaAlias, recipientEntityID, extensionsList, logoutEndpoint, relayState, sessionIndex, nameID,
request, response, paramsMap, config);
}
public static StringBuffer doLogout(
String metaAlias,
String recipientEntityID,
List extensionsList,
EndpointType logoutEndpoint,
String relayState,
String sessionIndex,
NameID nameID,
HttpServletRequest request,
HttpServletResponse response,
Map paramsMap,
BaseConfigType config) throws SAML2Exception, SessionException {
StringBuffer logoutRequestID = new StringBuffer();
String classMethod = "LogoutUtil.doLogout: ";
String requesterEntityID = metaManager.getEntityByMetaAlias(metaAlias);
String realm = SAML2MetaUtils.getRealmByMetaAlias(metaAlias);
String hostEntityRole = SAML2Utils.getHostEntityRole(paramsMap);
String location = null;
String binding = null;
if (logoutEndpoint != null) {
location = logoutEndpoint.getLocation();
binding = logoutEndpoint.getBinding();
} else {
debug.error(classMethod + "Unable to find the recipient's single logout service with the binding "
+ binding);
throw new SAML2Exception(SAML2Utils.bundle.getString("sloServiceNotfound"));
}
if (debug.messageEnabled()) {
debug.message(classMethod + "Entering ..."
+ "\nrequesterEntityID=" + requesterEntityID
+ "\nrecipientEntityID=" + recipientEntityID
+ "\nbinding=" + binding
+ "\nrelayState=" + relayState
+ "\nsessionIndex=" + sessionIndex);
}
// generate unique request ID
String requestID = SAML2Utils.generateID();
if ((requestID == null) || (requestID.length() == 0)) {
throw new SAML2Exception(SAML2Utils.bundle.getString("cannotGenerateID"));
}
// retrieve data from the params map
// destinationURI required if message is signed.
String destinationURI = SAML2Utils.getParameter(paramsMap, SAML2Constants.DESTINATION);
String consent = SAML2Utils.getParameter(paramsMap, SAML2Constants.CONSENT);
Extensions extensions = createExtensions(extensionsList);
Issuer issuer = SAML2Utils.createIssuer(requesterEntityID);
// construct LogoutRequest
LogoutRequest logoutReq = null;
try {
logoutReq = ProtocolFactory.getInstance().createLogoutRequest();
} catch (Exception e) {
debug.error(classMethod + "Unable to create LogoutRequest : ", e);
throw new SAML2Exception(SAML2Utils.bundle.getString("errorCreatingLogoutRequest"));
}
// set required attributes / elements
logoutReq.setID(requestID);
logoutReq.setVersion(SAML2Constants.VERSION_2_0);
logoutReq.setIssueInstant(new Date());
setNameIDForSLORequest(logoutReq, nameID, realm, requesterEntityID, hostEntityRole, recipientEntityID);
// set optional attributes / elements
logoutReq.setDestination(XMLUtils.escapeSpecialCharacters(destinationURI));
logoutReq.setConsent(consent);
logoutReq.setIssuer(issuer);
if (hostEntityRole.equals(SAML2Constants.IDP_ROLE)) {
// use the assertion effective time (in seconds)
int effectiveTime = SAML2Constants.ASSERTION_EFFECTIVE_TIME;
String effectiveTimeStr = SAML2Utils.getAttributeValueFromSSOConfig(realm, requesterEntityID,
SAML2Constants.IDP_ROLE, SAML2Constants.ASSERTION_EFFECTIVE_TIME_ATTRIBUTE);
if (effectiveTimeStr != null) {
try {
effectiveTime = Integer.parseInt(effectiveTimeStr);
if (SAML2Utils.debug.messageEnabled()) {
SAML2Utils.debug.message(classMethod + "got effective time from config:" + effectiveTime);
}
} catch (NumberFormatException nfe) {
SAML2Utils.debug.error(classMethod + "Failed to get assertion effective time from "
+ "IDP SSO config: ", nfe);
effectiveTime = SAML2Constants.ASSERTION_EFFECTIVE_TIME;
}
}
Date date = new Date();
date.setTime(date.getTime() + effectiveTime * 1000);
logoutReq.setNotOnOrAfter(date);
}
if (extensions != null) {
logoutReq.setExtensions(extensions);
}
if (sessionIndex != null) {
List list = new ArrayList();
list.add(sessionIndex);
logoutReq.setSessionIndex(list);
}
debug.message(classMethod + "Recipient's single logout service location = " + location);
if (destinationURI == null || destinationURI.isEmpty()) {
logoutReq.setDestination(XMLUtils.escapeSpecialCharacters(location));
}
if (debug.messageEnabled()) {
debug.message(classMethod + "SLO Request before signing : ");
debug.message(logoutReq.toXMLString(true, true));
}
if (binding.equals(SAML2Constants.HTTP_REDIRECT)) {
try {
doSLOByHttpRedirect(logoutReq.toXMLString(true, true),
location,
relayState,
realm,
requesterEntityID,
hostEntityRole,
recipientEntityID,
response);
logoutRequestID.append(requestID);
String[] data = {location};
LogUtil.access(Level.INFO, LogUtil.REDIRECT_TO_IDP, data, null);
} catch (Exception e) {
debug.error("Exception :", e);
throw new SAML2Exception(SAML2Utils.bundle.getString("errorRedirectingLogoutRequest"));
}
} else if (binding.equals(SAML2Constants.SOAP)) {
logoutRequestID.append(requestID);
signSLORequest(logoutReq, realm, requesterEntityID, hostEntityRole, recipientEntityID);
if (debug.messageEnabled()) {
debug.message(classMethod + "SLO Request after signing : ");
debug.message(logoutReq.toXMLString(true, true));
}
location = SAML2Utils.fillInBasicAuthInfo(config, location);
doSLOBySOAP(requestID, logoutReq, location, realm, requesterEntityID, hostEntityRole, request, response);
} else if (binding.equals(SAML2Constants.HTTP_POST)) {
logoutRequestID.append(requestID);
signSLORequest(logoutReq, realm, requesterEntityID, hostEntityRole, recipientEntityID);
if (debug.messageEnabled()) {
debug.message(classMethod + "SLO Request after signing : ");
debug.message(logoutReq.toXMLString(true, true));
}
doSLOByPOST(requestID, logoutReq.toXMLString(true, true), location, relayState, realm, requesterEntityID,
hostEntityRole, response, request);
}
SPCache.logoutRequestIDHash.put(logoutRequestID.toString(), logoutReq);
return logoutRequestID;
}
static private void doSLOByHttpRedirect(
String sloRequestXMLString,
String sloURL,
String relayState,
String realm,
String hostEntity,
String hostEntityRole,
String remoteEntity,
HttpServletResponse response) throws SAML2Exception, IOException {
String method = "doSLOByHttpRedirect: ";
// encode the xml string
String encodedXML = SAML2Utils.encodeForRedirect(sloRequestXMLString);
StringBuffer queryString =
new StringBuffer().append(SAML2Constants.SAML_REQUEST)
.append(SAML2Constants.EQUAL)
.append(encodedXML);
// spec states that the relay state MUST NOT exceed 80
// chanracters, need to have some means to pass it when it
// exceeds 80 chars
if ((relayState != null) && (relayState.length() > 0)) {
String tmp = SAML2Utils.generateID();
if (hostEntityRole.equals(SAML2Constants.IDP_ROLE)) {
IDPCache.relayStateCache.put(tmp, relayState);
} else {
SPCache.relayStateHash.put(tmp, new CacheObject(relayState));
}
queryString.append("&").append(SAML2Constants.RELAY_STATE)
.append("=").append(tmp);
}
boolean needToSign = false;
if (hostEntityRole.equalsIgnoreCase(SAML2Constants.IDP_ROLE)) {
needToSign =
SAML2Utils.getWantLogoutRequestSigned(realm, remoteEntity,
SAML2Constants.SP_ROLE);
} else {
needToSign =
SAML2Utils.getWantLogoutRequestSigned(realm, remoteEntity,
SAML2Constants.IDP_ROLE);
}
String signedQueryString = queryString.toString();
if (needToSign == true) {
signedQueryString = SAML2Utils.signQueryString(signedQueryString,
realm, hostEntity, hostEntityRole);
}
String redirectURL = sloURL + (sloURL.contains("?") ? "&" : "?") +
signedQueryString;
if (debug.messageEnabled()) {
debug.message(method + "LogoutRequestXMLString : "
+ sloRequestXMLString);
debug.message(method + "LogoutRedirectURL : " + sloURL);
}
response.sendRedirect(redirectURL);
}
/**
* Performs SOAP logout, this method will send LogoutResuest to IDP using
* SOAP binding, and process LogoutResponse.
* @param requestID Request id.
* @param sloRequest a string representation of LogoutRequest.
* @param sloURL SOAP logout URL on IDP side.
* @param realm a string representation of LogoutRequest.
* @param hostEntity host entity is sending the request.
* @param hostRole SOAP logout URL on IDP side.
* @throws SAML2Exception if logout failed.
* @throws SessionException if logout failed.
*/
private static void doSLOBySOAP(
String requestID,
LogoutRequest sloRequest,
String sloURL,
String realm,
String hostEntity,
String hostRole,
HttpServletRequest request,
HttpServletResponse response) throws SAML2Exception, SessionException {
String sloRequestXMLString = sloRequest.toXMLString(true, true);
if (debug.messageEnabled()) {
debug.message("LogoutUtil.doSLOBySOAP : SLORequestXML: "
+ sloRequestXMLString + "\nSOAPURL : " + sloURL);
}
SOAPMessage resMsg = null;
try {
resMsg = SOAPCommunicator.getInstance().sendSOAPMessage(sloRequestXMLString, sloURL,
true);
} catch (SOAPException se) {
debug.error("Unable to send SOAPMessage to IDP ", se);
throw new SAML2Exception(se.getMessage());
}
// get the LogoutResponse element from SOAP message
Element respElem = SOAPCommunicator.getInstance().getSamlpElement(resMsg, "LogoutResponse");
LogoutResponse sloResponse = ProtocolFactory.getInstance()
.createLogoutResponse(respElem);
String userId = null;
// invoke SPAdapter for preSingleLogoutProcess : SP initiated SOAP
if ((hostRole != null) && hostRole.equals(SAML2Constants.SP_ROLE)) {
userId = SPSingleLogout.preSingleLogoutProcess(hostEntity, realm,
request, response, null, sloRequest, sloResponse,
SAML2Constants.SOAP);
}
if (sloResponse == null) {
debug.error("LogoutUtil.doSLOBySoap : null response");
throw new SAML2Exception(SAML2Utils.bundle.getString(
"nullLogoutResponse"));
}
if (debug.messageEnabled()) {
debug.message("LogoutUtil.doSLOBySOAP : " +
"LogoutResponse without SOAP envelope:\n" +
sloResponse.toXMLString());
}
Issuer resIssuer = sloResponse.getIssuer();
String requestId = sloResponse.getInResponseTo();
SAML2Utils.verifyResponseIssuer(
realm, hostEntity, resIssuer, requestId);
String remoteEntityID = sloResponse.getIssuer().getValue();
verifySLOResponse(sloResponse, realm, remoteEntityID, hostEntity,
hostRole);
boolean success = checkSLOResponse(sloResponse, requestID);
if (debug.messageEnabled()) {
debug.message("Request success : " + success);
}
if (success == false) {
if (SPCache.isFedlet) {
FedletAdapter fedletAdapter =
SAML2Utils.getFedletAdapterClass(hostEntity, realm);
if (fedletAdapter != null) {
fedletAdapter.onFedletSLOFailure(
request, response, sloRequest, sloResponse,
hostEntity, remoteEntityID, SAML2Constants.SOAP);
}
}
throw new SAML2Exception(SAML2Utils.bundle.getString("sloFailed"));
} else {
// invoke SPAdapter for postSLOSuccess : SP inited SOAP
if ((hostRole != null) && hostRole.equals(SAML2Constants.SP_ROLE)) {
if (SPCache.isFedlet) {
FedletAdapter fedletAdapter =
SAML2Utils.getFedletAdapterClass(hostEntity, realm);
if (fedletAdapter != null) {
fedletAdapter.onFedletSLOSuccess(
request, response, sloRequest, sloResponse,
hostEntity, remoteEntityID, SAML2Constants.SOAP);
}
} else {
SPSingleLogout.postSingleLogoutSuccess(hostEntity, realm,
request, response, userId, sloRequest, sloResponse,
SAML2Constants.SOAP);
}
}
}
}
private static boolean checkSLOResponse(LogoutResponse sloResponse,
String requestID)
throws SAML2Exception {
boolean success = false;
String retCode = sloResponse.getStatus().getStatusCode().getValue();
if (retCode.equalsIgnoreCase(SAML2Constants.SUCCESS)) {
String inResponseTo = sloResponse.getInResponseTo();
if (inResponseTo.equals(requestID)) {
if (debug.messageEnabled()) {
debug.message("LogoutUtil.doSLOBySOAP " +
"LogoutResponse inResponseTo matches LogoutRequest ID");
}
} else {
debug.error("LogoutUtil.doSLOBySOAP " +
"LogoutResponse inResponseTo does not match Request ID.");
throw new SAML2Exception(SAML2Utils.bundle.getString(
"inResponseToNoMatch"));
}
success = true;
} else {
if (debug.messageEnabled()) {
debug.message("LogoutUtil.doSLOBySOAP : " +
"return code : " + retCode);
}
success = false;
}
return success;
}
static LogoutResponse forwardToRemoteServer(LogoutRequest logoutReq,
String remoteLogoutURL) {
if (debug.messageEnabled()) {
debug.message("LogoutUtil.forwardToRemoteServer: " +
"remoteLogoutURL = " + remoteLogoutURL);
}
try {
SOAPMessage resMsg = SOAPCommunicator.getInstance().sendSOAPMessage(
logoutReq.toXMLString(true, true), remoteLogoutURL, true);
// get the LogoutResponse element from SOAP message
Element respElem = SOAPCommunicator.getInstance().getSamlpElement(resMsg,
"LogoutResponse");
return ProtocolFactory.getInstance().createLogoutResponse(respElem);
} catch (Exception ex) {
if (debug.messageEnabled()) {
debug.message("LogoutUtil.forwardToRemoteServer:", ex);
}
}
return null;
}
static List getSessionIndex(LogoutResponse logoutRes) {
StatusDetail statusDetail = logoutRes.getStatus().getStatusDetail();
if (statusDetail == null) {
return null;
}
List details = statusDetail.getAny();
if (details == null || details.isEmpty()) {
return null;
}
List sessionIndexList = new ArrayList();
for(Iterator iter = details.iterator(); iter.hasNext();) {
String detail = (String)iter.next();
Document doc = XMLUtils.toDOMDocument(detail, debug);
Element elem = doc.getDocumentElement();
String localName = elem.getLocalName();
if (SAML2Constants.SESSION_INDEX.equals(localName)) {
sessionIndexList.add(XMLUtils.getElementString(elem));
}
}
return sessionIndexList;
}
static void setSessionIndex(Status status, List sessionIndex) {
try {
StatusDetail sd=ProtocolFactory.getInstance().createStatusDetail();
status.setStatusDetail(sd);
if (sessionIndex != null && !sessionIndex.isEmpty()) {
List details = new ArrayList();
for(Iterator iter = sessionIndex.iterator(); iter.hasNext();) {
String si = (String)iter.next();
SessionIndex sIndex = ProtocolFactory.getInstance()
.createSessionIndex(si);
details.add(sIndex.toXMLString(true, true));
}
sd.setAny(details);
}
} catch (SAML2Exception e) {
debug.error("LogoutUtil.setSessionIndex: ", e);
}
}
/**
* Based on the preferred SAML binding this method tries to choose the most appropriate
* {@link SingleLogoutServiceElement} that can be used to send the logout request to. The algorithm itself is
* simple:
* <ul>
* <li>When asynchronous binding was used with the initial logout request, it is preferred to use asynchronous
* bindings, but if they are not available, a synchronous binding should be used.</li>
* <li>When synchronous binding is used with the initial request, only synchronous bindings can be used for the
* rest of the entities.</li>
* </ul>
*
* @param sloList The list of SLO endpoints for a given entity.
* @param preferredBinding The binding that was used to initiate the logout request.
* @return The most appropriate SLO service location that can be used for sending the logout request. If there is
* no appropriate logout endpoint, null is returned.
*/
public static SingleLogoutServiceElement getMostAppropriateSLOServiceLocation(
List<SingleLogoutServiceElement> sloList, String preferredBinding) {
//shortcut for the case when SLO isn't supported at all
if (sloList.isEmpty()) {
return null;
}
Map<String, SingleLogoutServiceElement> sloBindings =
new HashMap<String, SingleLogoutServiceElement>(sloList.size());
for (SingleLogoutServiceElement sloEndpoint : sloList) {
sloBindings.put(sloEndpoint.getBinding(), sloEndpoint);
}
SingleLogoutServiceElement endpoint = sloBindings.get(preferredBinding);
if (endpoint == null) {
//if the requested binding isn't supported let's try to find the most appropriate SLO endpoint
if (preferredBinding.equals(SAML2Constants.HTTP_POST)) {
endpoint = sloBindings.get(SAML2Constants.HTTP_REDIRECT);
} else if (preferredBinding.equals(SAML2Constants.HTTP_REDIRECT)) {
endpoint = sloBindings.get(SAML2Constants.HTTP_POST);
}
if (endpoint == null) {
//we ran out of asynchronous bindings, so our only chance is to try to use SOAP binding
//in case the preferred binding was SOAP from the beginning, then this code will just return null again
endpoint = sloBindings.get(SAML2Constants.SOAP);
}
}
return endpoint;
}
/**
* Gets Single Logout Service location URL.
*
* @param sloList list of configured <code>SingleLogoutElement</code>.
* @param desiredBinding desired binding of SingleLogout.
* @return url of desiredBinding.
*/
public static String getSLOServiceLocation(
List sloList,
String desiredBinding) {
String classMethod =
"LogoutUtil.getSLOserviceLocation: ";
int n = sloList.size();
if (debug.messageEnabled()) {
debug.message(
classMethod +
"Number of single logout services = " +
n);
}
SingleLogoutServiceElement slos = null;
String location = null;
String binding = null;
for (int i=0; i<n; i++) {
slos = (SingleLogoutServiceElement)sloList.get(i);
if (slos != null) {
binding = slos.getBinding();
}
if (debug.messageEnabled()) {
debug.message(
classMethod +
"Single logout service binding = " +
binding);
}
if ((binding != null) && (binding.equals(desiredBinding))) {
location = slos.getLocation();
if (debug.messageEnabled()) {
debug.message(
classMethod +
"Found the single logout service "+
"with the desired binding");
}
break;
}
}
return location;
}
/**
* Gets Single Logout Response Service location URL.
*
* @param sloList list of configured <code>SingleLogoutElement</code>.
* @param desiredBinding desired binding of SingleLogout.
* @return url of desiredBinding.
*/
public static String getSLOResponseServiceLocation(
List sloList,
String desiredBinding) {
String classMethod =
"LogoutUtil.getSLOResponseServiceLocation: ";
int n = sloList.size();
if (debug.messageEnabled()) {
debug.message(
classMethod +
"Number of single logout services = " +
n);
}
SingleLogoutServiceElement slos = null;
String resLocation = null;
String binding = null;
for (int i=0; i<n; i++) {
slos = (SingleLogoutServiceElement)sloList.get(i);
if (slos != null) {
binding = slos.getBinding();
}
if (debug.messageEnabled()) {
debug.message(
classMethod +
"Single logout service binding = " +
binding);
}
if ((binding != null) && (binding.equals(desiredBinding))) {
resLocation = slos.getResponseLocation();
if (debug.messageEnabled()) {
debug.message(
classMethod +
"Found the single logout service "+
"with the desired binding");
}
break;
}
}
return resLocation;
}
/* Creates Extensions */
private static com.sun.identity.saml2.protocol.Extensions
createExtensions(List extensionsList) throws SAML2Exception {
Extensions extensions = null;
if (extensionsList != null && !extensionsList.isEmpty()) {
extensions = ProtocolFactory.getInstance().createExtensions();
extensions.setAny(extensionsList);
}
return extensions;
}
/**
* Builds the <code>LogoutResponse</code> to be sent to IDP.
*
* @param status status of the response.
* @param inResponseTo inResponseTo.
* @param issuer issuer of the response, which is SP.
* @param realm inResponseTo.
* @param hostRole issuer of the response, which is SP.
* @param remoteEntity will get this response.
*
* @return <code>LogoutResponse</code>
*
*/
public static LogoutResponse generateResponse(
Status status,
String inResponseTo,
Issuer issuer,
String realm,
String hostRole,
String remoteEntity) {
if (status == null) {
status = SAML2Utils.generateStatus(SAML2Constants.SUCCESS,
SAML2Utils.bundle.getString("requestSuccess"));
}
LogoutResponse logoutResponse = ProtocolFactory.getInstance()
.createLogoutResponse();
String responseID = SAMLUtils.generateID();
try {
logoutResponse.setStatus(status);
logoutResponse.setID(responseID);
logoutResponse.setInResponseTo(inResponseTo);
logoutResponse.setVersion(SAML2Constants.VERSION_2_0);
logoutResponse.setIssueInstant(new Date());
logoutResponse.setIssuer(issuer);
} catch (SAML2Exception e) {
debug.error("Error in generating LogoutResponse.", e);
}
return logoutResponse;
}
/**
* Sign LogoutRequest.
*
* @param sloRequest SLO request will be signed.
* @param realm realm of host entity.
* @param hostEntity entity ID of host entity.
* @param hostEntityRole role of host entity.
* @param remoteEntity entity ID of remote host entity.
* @throws SAML2Exception if error in signing the request.
*/
public static void signSLORequest(LogoutRequest sloRequest,
String realm, String hostEntity,
String hostEntityRole, String remoteEntity)
throws SAML2Exception {
signSLORequest(sloRequest, realm, hostEntity,
hostEntityRole, remoteEntity, false);
}
static void signSLORequest(LogoutRequest sloRequest,
String realm, String hostEntity,
String hostEntityRole, String remoteEntity,
boolean includeCert)
throws SAML2Exception {
String method = "signSLORequest : ";
boolean needRequestSign = false;
if (hostEntityRole.equalsIgnoreCase(SAML2Constants.IDP_ROLE)) {
needRequestSign = SAML2Utils.getWantLogoutRequestSigned(realm,
remoteEntity, SAML2Constants.SP_ROLE);
} else {
needRequestSign = SAML2Utils.getWantLogoutRequestSigned(realm,
remoteEntity, SAML2Constants.IDP_ROLE);
}
if (needRequestSign == false) {
if (debug.messageEnabled()) {
debug.message(method + "SLORequest doesn't need to be signed.");
}
return;
}
String alias = SAML2Utils.getSigningCertAlias(realm, hostEntity, hostEntityRole);
String encryptedKeyPass = SAML2Utils.getSigningCertEncryptedKeyPass(realm, hostEntity, hostEntityRole);
if (debug.messageEnabled()) {
debug.message(method + "realm is : "+ realm);
debug.message(method + "hostEntity is : " + hostEntity);
debug.message(method + "Host Entity role is : " + hostEntityRole);
debug.message(method + "Cert Alias is : " + alias);
debug.message(method + "SLO Request before sign : "
+ sloRequest.toXMLString(true, true));
if (encryptedKeyPass != null && !encryptedKeyPass.isEmpty()) {
debug.message(method + "Using provided Cert KeyPass");
}
}
PrivateKey signingKey;
if (encryptedKeyPass == null || encryptedKeyPass.isEmpty()) {
signingKey = keyProvider.getPrivateKey(alias);
} else {
signingKey = keyProvider.getPrivateKey(alias, encryptedKeyPass);
}
X509Certificate signingCert = null;
if (includeCert) {
signingCert = keyProvider.getX509Certificate(alias);
}
if (signingKey != null) {
sloRequest.sign(signingKey, signingCert);
} else {
debug.error("Incorrect configuration for Signing Certificate.");
throw new SAML2Exception(
SAML2Utils.bundle.getString("metaDataError"));
}
if (debug.messageEnabled()) {
debug.message(method + "SLO Request after sign : "
+ sloRequest.toXMLString(true, true));
}
}
/**
* Verify the signature in LogoutRequest.
*
* @param sloRequest SLO request will be verified.
* @param realm realm of host entity.
* @param remoteEntity entity ID of remote host entity.
* @param hostEntity entity ID of host entity.
* @param hostEntityRole role of host entity.
* @return returns true if signature is valid.
* @throws SAML2Exception if error in verifying the signature.
* @throws SessionException if error in verifying the signature.
*/
public static boolean verifySLORequest(LogoutRequest sloRequest,
String realm, String remoteEntity,
String hostEntity, String hostEntityRole)
throws SAML2Exception, SessionException {
String method = "verifySLORequest : ";
boolean needVerifySignature =
SAML2Utils.getWantLogoutRequestSigned(realm, hostEntity,
hostEntityRole);
if (needVerifySignature == false) {
if (debug.messageEnabled()) {
debug.message(method+"SLORequest doesn't need to be verified.");
}
return true;
}
if (debug.messageEnabled()) {
debug.message(method + "realm is : "+ realm);
debug.message(method + "remoteEntity is : " + remoteEntity);
debug.message(method + "Host Entity role is : " + hostEntityRole);
}
boolean valid = false;
Set<X509Certificate> signingCerts;
if (hostEntityRole.equalsIgnoreCase(SAML2Constants.IDP_ROLE)) {
SPSSODescriptorElement spSSODesc = metaManager.getSPSSODescriptor(realm, remoteEntity);
signingCerts = KeyUtil.getVerificationCerts(spSSODesc, remoteEntity, SAML2Constants.SP_ROLE);
} else {
IDPSSODescriptorElement idpSSODesc = metaManager.getIDPSSODescriptor(realm, remoteEntity);
signingCerts = KeyUtil.getVerificationCerts(idpSSODesc, remoteEntity, SAML2Constants.IDP_ROLE);
}
if (!signingCerts.isEmpty()) {
valid = sloRequest.isSignatureValid(signingCerts);
if (debug.messageEnabled()) {
debug.message(method + "Signature is : " + valid);
}
} else {
debug.error("Incorrect configuration for Signing Certificate.");
throw new SAML2Exception(
SAML2Utils.bundle.getString("metaDataError"));
}
return valid;
}
/**
* Sign LogoutResponse.
*
* @param sloResponse SLO response will be signed.
* @param realm realm of host entity.
* @param hostEntity entity ID of host entity.
* @param hostEntityRole role of host entity.
* @param remoteEntity entity ID of remote host entity.
* @throws SAML2Exception if error in signing the request.
*/
public static void signSLOResponse(LogoutResponse sloResponse,
String realm, String hostEntity,
String hostEntityRole, String remoteEntity)
throws SAML2Exception {
signSLOResponse(sloResponse, realm, hostEntity,
hostEntityRole, remoteEntity, false);
}
static void signSLOResponse(LogoutResponse sloResponse,
String realm, String hostEntity,
String hostEntityRole, String remoteEntity,
boolean includeCert)
throws SAML2Exception {
String method = "signSLOResponse : ";
boolean needSignResponse = false;
if (hostEntityRole.equalsIgnoreCase(SAML2Constants.IDP_ROLE)) {
needSignResponse = SAML2Utils.getWantLogoutResponseSigned(realm,
remoteEntity, SAML2Constants.SP_ROLE);
} else {
needSignResponse = SAML2Utils.getWantLogoutResponseSigned(realm,
remoteEntity, SAML2Constants.IDP_ROLE);
}
if (needSignResponse == false) {
if (debug.messageEnabled()) {
debug.message(method +
"SLOResponse doesn't need to be signed.");
}
return;
}
String alias = SAML2Utils.getSigningCertAlias(realm, hostEntity, hostEntityRole);
String encryptedKeyPass = SAML2Utils.getSigningCertEncryptedKeyPass(realm, hostEntity, hostEntityRole);
if (debug.messageEnabled()) {
debug.message(method + "realm is : "+ realm);
debug.message(method + "hostEntity is : " + hostEntity);
debug.message(method + "Host Entity role is : " + hostEntityRole);
debug.message(method + "Cert Alias is : " + alias);
if (encryptedKeyPass != null && !encryptedKeyPass.isEmpty()) {
debug.message(method + "Using provided Cert KeyPass");
}
}
PrivateKey signingKey;
if (encryptedKeyPass == null || encryptedKeyPass.isEmpty()) {
signingKey = keyProvider.getPrivateKey(alias);
} else {
signingKey = keyProvider.getPrivateKey(alias, encryptedKeyPass);
}
X509Certificate signingCert = null;
if (includeCert) {
signingCert = keyProvider.getX509Certificate(alias);
}
if (signingKey != null) {
sloResponse.sign(signingKey, signingCert);
} else {
debug.error("Incorrect configuration for Signing Certificate.");
throw new SAML2Exception(
SAML2Utils.bundle.getString("metaDataError"));
}
}
/**
* Verify the signature in LogoutResponse.
*
* @param sloResponse SLO response will be verified.
* @param realm realm of host entity.
* @param remoteEntity entity ID of remote host entity.
* @param hostEntity entity ID of host entity.
* @param hostEntityRole role of host entity.
* @return returns true if signature is valid.
* @throws SAML2Exception if error in verifying the signature.
* @throws SessionException if error in verifying the signature.
*/
public static boolean verifySLOResponse(LogoutResponse sloResponse,
String realm, String remoteEntity,
String hostEntity, String hostEntityRole)
throws SAML2Exception, SessionException {
String method = "verifySLOResponse : ";
boolean needVerifySignature =
SAML2Utils.getWantLogoutResponseSigned(realm, hostEntity,
hostEntityRole);
if (needVerifySignature == false) {
if (debug.messageEnabled()) {
debug.message(method +
"SLOResponse doesn't need to be verified.");
}
return true;
}
Set<X509Certificate> signingCerts;
if (hostEntityRole.equalsIgnoreCase(SAML2Constants.IDP_ROLE)) {
SPSSODescriptorElement spSSODesc = metaManager.getSPSSODescriptor(realm, remoteEntity);
signingCerts = KeyUtil.getVerificationCerts(spSSODesc, remoteEntity, SAML2Constants.SP_ROLE);
} else {
IDPSSODescriptorElement idpSSODesc = metaManager.getIDPSSODescriptor(realm, remoteEntity);
signingCerts = KeyUtil.getVerificationCerts(idpSSODesc, remoteEntity, SAML2Constants.IDP_ROLE);
}
if (!signingCerts.isEmpty()) {
boolean valid = sloResponse.isSignatureValid(signingCerts);
if (debug.messageEnabled()) {
debug.message(method + "Signature is : " + valid);
}
return valid;
} else {
debug.error("Incorrect configuration for Signing Certificate.");
throw new SAML2Exception(
SAML2Utils.bundle.getString("metaDataError"));
}
}
public static void setNameIDForSLORequest(LogoutRequest request,
NameID nameID, String realm, String hostEntity,
String hostEntityRole, String remoteEntity)
throws SAML2Exception, SessionException {
String method = "setNameIDForSLORequest: ";
boolean needEncryptIt = false;
if (hostEntityRole.equalsIgnoreCase(SAML2Constants.IDP_ROLE)) {
needEncryptIt =
SAML2Utils.getWantNameIDEncrypted(realm, remoteEntity,
SAML2Constants.SP_ROLE);
} else {
needEncryptIt =
SAML2Utils.getWantNameIDEncrypted(realm, remoteEntity,
SAML2Constants.IDP_ROLE);
}
if (needEncryptIt == false) {
if (debug.messageEnabled()) {
debug.message(method + "NamID doesn't need to be encrypted.");
}
request.setNameID(nameID);
return;
}
EncInfo encryptInfo = null;
KeyDescriptorType keyDescriptor = null;
if (hostEntityRole.equalsIgnoreCase(SAML2Constants.IDP_ROLE)) {
SPSSODescriptorElement spSSODesc =
metaManager.getSPSSODescriptor(realm, remoteEntity);
keyDescriptor = KeyUtil.getKeyDescriptor(spSSODesc, "encryption");
encryptInfo = KeyUtil.getEncInfo(spSSODesc, remoteEntity,
SAML2Constants.SP_ROLE);
} else {
IDPSSODescriptorElement idpSSODesc =
metaManager.getIDPSSODescriptor(realm, remoteEntity);
keyDescriptor = KeyUtil.getKeyDescriptor(idpSSODesc, "encryption");
encryptInfo = KeyUtil.getEncInfo(idpSSODesc, remoteEntity,
SAML2Constants.IDP_ROLE);
}
if (debug.messageEnabled()) {
debug.message(method + "realm is : "+ realm);
debug.message(method + "hostEntity is : " + hostEntity);
debug.message(method + "Host Entity role is : " + hostEntityRole);
debug.message(method + "remoteEntity is : " + remoteEntity);
}
if (encryptInfo == null) {
debug.error("NO meta data for encrypt Info.");
throw new SAML2Exception(
SAML2Utils.bundle.getString("metaDataError"));
}
X509Certificate certificate = KeyUtil.getCert(keyDescriptor);
PublicKey recipientPublicKey = certificate.getPublicKey();
EncryptedID encryptedID = nameID.encrypt(recipientPublicKey,
encryptInfo.getDataEncAlgorithm(),
encryptInfo.getDataEncStrength(),
remoteEntity);
request.setEncryptedID(encryptedID);
}
static NameID getNameIDFromSLORequest(LogoutRequest request,
String realm, String hostEntity,
String hostEntityRole)
throws SAML2Exception {
String method = "getNameIDFromSLORequest: ";
boolean needDecryptIt =
SAML2Utils.getWantNameIDEncrypted(realm,hostEntity,hostEntityRole);
if (needDecryptIt == false) {
if (debug.messageEnabled()) {
debug.message(method + "NamID doesn't need to be decrypted.");
}
return request.getNameID();
}
if (debug.messageEnabled()) {
debug.message(method + "realm is : "+ realm);
debug.message(method + "hostEntity is : " + hostEntity);
debug.message(method + "Host Entity role is : " + hostEntityRole);
}
EncryptedID encryptedID = request.getEncryptedID();
return encryptedID.decrypt(KeyUtil.getDecryptionKeys(realm, hostEntity, hostEntityRole));
}
public static void sendSLOResponse(HttpServletResponse response,
LogoutResponse sloResponse, String sloURL, String relayState,
String realm, String hostEntity, String hostEntityRole,
String remoteEntity) throws SAML2Exception {
sendSLOResponseRedirect(response, sloResponse, sloURL, relayState,
realm, hostEntity, hostEntityRole, remoteEntity);
}
public static void sendSLOResponse(HttpServletResponse response, HttpServletRequest request,
LogoutResponse sloResponse, String sloURL, String relayState,
String realm, String hostEntity, String hostEntityRole,
String remoteEntity, String binding) throws SAML2Exception {
if (SAML2Constants.HTTP_POST.equals(binding)) {
sendSLOResponsePost(response, request, sloResponse, sloURL, relayState,
realm, hostEntity, hostEntityRole, remoteEntity);
} else {
sendSLOResponseRedirect(response, sloResponse, sloURL, relayState,
realm, hostEntity, hostEntityRole, remoteEntity);
}
}
public static void sendSLOResponsePost(HttpServletResponse response, HttpServletRequest request,
LogoutResponse sloResponse, String sloURL, String relayState,
String realm, String hostEntity, String hostEntityRole,
String remoteEntity) throws SAML2Exception {
signSLOResponse(sloResponse, realm, hostEntity, hostEntityRole,
remoteEntity);
String logoutResponseStr = sloResponse.toXMLString(true,true);
String encMsg = SAML2Utils.encodeForPOST(logoutResponseStr);
SAML2Utils.postToTarget(request, response, "SAMLResponse", encMsg, "RelayState", relayState, sloURL);
}
public static void sendSLOResponseRedirect(HttpServletResponse response,
LogoutResponse sloResponse,
String sloURL,
String relayState,
String realm,
String hostEntity,
String hostEntityRole,
String remoteEntity)
throws SAML2Exception {
try {
String logoutResXMLString = sloResponse.toXMLString(true,true);
// encode the xml string
String encodedXML =
SAML2Utils.encodeForRedirect(logoutResXMLString);
StringBuffer queryString =
new StringBuffer().append(SAML2Constants.SAML_RESPONSE)
.append(SAML2Constants.EQUAL)
.append(encodedXML);
if (relayState != null && relayState.length() > 0
&& relayState.getBytes("UTF-8").length <= 80) {
queryString.append("&").append(SAML2Constants.RELAY_STATE)
.append("=").append(URLEncDec.encode(relayState));
}
boolean needToSign = false;
if (hostEntityRole.equalsIgnoreCase(SAML2Constants.IDP_ROLE)) {
needToSign =
SAML2Utils.getWantLogoutResponseSigned(realm, remoteEntity,
SAML2Constants.SP_ROLE);
} else {
needToSign =
SAML2Utils.getWantLogoutResponseSigned(realm, remoteEntity,
SAML2Constants.IDP_ROLE);
}
String signedQueryString = queryString.toString();
if (needToSign == true) {
signedQueryString =
SAML2Utils.signQueryString(signedQueryString, realm,
hostEntity, hostEntityRole);
}
String redirectURL = sloURL+ (sloURL.contains("?") ? "&" : "?") +
signedQueryString;
if (debug.messageEnabled()) {
debug.message("redirectURL :" + redirectURL);
}
String[] data = {sloURL};
LogUtil.access(Level.INFO,LogUtil.REDIRECT_TO_SP,data,
null);
response.sendRedirect(redirectURL);
} catch (Exception e) {
debug.error("Exception :",e);
throw new SAML2Exception(SAML2Utils.bundle.getString(
"errorRedirectingLogoutResponse"));
}
}
/**
* Returns binding information of SLO Service for remote entity
* from request or meta configuration.
*
* @param request the HttpServletRequest.
* @param metaAlias entityID of hosted entity.
* @param hostEntityRole Role of hosted entity.
* @param remoteEntityID entityID of remote entity.
* @return return true if the processing is successful.
* @throws SAML2Exception if no binding information is configured.
*/
public static String getSLOBindingInfo(HttpServletRequest request,
String metaAlias,
String hostEntityRole,
String remoteEntityID)
throws SAML2Exception {
String binding = request.getParameter(SAML2Constants.BINDING);
try {
if (binding == null) {
String realm = SAML2MetaUtils.getRealmByMetaAlias(metaAlias);
SingleLogoutServiceElement sloService =
getSLOServiceElement(realm, remoteEntityID,
hostEntityRole, null);
if (sloService != null) {
binding = sloService.getBinding();
}
}
} catch (SessionException e) {
debug.error("Invalid SSOToken", e);
throw new SAML2Exception(
SAML2Utils.bundle.getString("metaDataError"));
}
if (binding == null) {
debug.error("Incorrect configuration for SingleLogout Service.");
throw new SAML2Exception(
SAML2Utils.bundle.getString("metaDataError"));
}
return binding;
}
private static SingleLogoutServiceElement getSLOServiceElement(
String realm, String entityID,
String hostEntityRole, String binding)
throws SAML2MetaException, SessionException, SAML2Exception {
SingleLogoutServiceElement sloService = null;
String method = "getSLOServiceElement: ";
if (debug.messageEnabled()) {
debug.message(method + "Realm : " + realm);
debug.message(method + "Entity ID : " + entityID);
debug.message(method + "Host Entity Role : " + hostEntityRole);
}
if (hostEntityRole.equalsIgnoreCase(SAML2Constants.SP_ROLE)) {
sloService = getIDPSLOConfig(realm, entityID, binding);
} else if (hostEntityRole.equalsIgnoreCase(SAML2Constants.IDP_ROLE)){
sloService = getSPSLOConfig(realm, entityID, binding);
} else {
debug.error("Hosted Entity role is missing .");
throw new SAML2Exception(
SAML2Utils.bundle.getString("nullIDPEntityID"));
}
return sloService;
}
/**
* Returns first SingleLogout configuration in an entity under
* the realm.
* @param realm The realm under which the entity resides.
* @param entityId ID of the entity to be retrieved.
* @param binding bind type need to has to be matched.
* @return <code>SingleLogoutServiceElement</code> for the entity or null
* @throws SAML2MetaException if unable to retrieve the first identity
* provider's SSO configuration.
* @throws SessionException invalid or expired single-sign-on session
*/
static public SingleLogoutServiceElement getIDPSLOConfig(
String realm,
String entityId,
String binding)
throws SAML2MetaException, SessionException {
SingleLogoutServiceElement slo = null;
IDPSSODescriptorElement idpSSODesc =
metaManager.getIDPSSODescriptor(realm, entityId);
if (idpSSODesc == null) {
debug.error("Identity Provider SSO config is missing.");
return null;
}
List list = idpSSODesc.getSingleLogoutService();
if ((list != null) && !list.isEmpty()) {
if (binding == null) {
return (SingleLogoutServiceElement)list.get(0);
}
Iterator it = list.iterator();
while (it.hasNext()) {
slo = (SingleLogoutServiceElement)it.next();
if (binding.equalsIgnoreCase(slo.getBinding())) {
break;
}
}
}
return slo;
}
/**
* Returns first SingleLogout configuration in an entity under
* the realm.
* @param realm The realm under which the entity resides.
* @param entityId ID of the entity to be retrieved.
* @param binding bind type need to has to be matched.
* @return <code>SingleLogoutServiceElement</code> for the entity or null
* @throws SAML2MetaException if unable to retrieve the first identity
* provider's SSO configuration.
* @throws SessionException invalid or expired single-sign-on session
*/
static public SingleLogoutServiceElement getSPSLOConfig(
String realm, String entityId,
String binding)
throws SAML2MetaException, SessionException {
SingleLogoutServiceElement slo = null;
SPSSODescriptorElement spSSODesc =
metaManager.getSPSSODescriptor(realm, entityId);
if (spSSODesc == null) {
return null;
}
List list = spSSODesc.getSingleLogoutService();
if ((list != null) && !list.isEmpty()) {
if (binding == null) {
return (SingleLogoutServiceElement)list.get(0);
}
Iterator it = list.iterator();
while (it.hasNext()) {
slo = (SingleLogoutServiceElement)it.next();
if (binding.equalsIgnoreCase(slo.getBinding())) {
break;
}
}
}
return slo;
}
/**
* Returns the extensions list
* @param paramsMap request paramsMap has extensions
* @return <code>List</code> for extensions params
*/
public static List getExtensionsList(Map paramsMap) {
List extensionsList = null;
// TODO Get the Extensions list from request parameter
return extensionsList;
}
private static void doSLOByPOST(String requestID,
String sloRequestXMLString, String sloURL, String relayState,
String realm, String hostEntity, String hostRole,
HttpServletResponse response, HttpServletRequest request) throws SAML2Exception, SessionException {
if (debug.messageEnabled()) {
debug.message("LogoutUtil.doSLOByPOST : SLORequestXML: "
+ sloRequestXMLString + "\nPOSTURL : " + sloURL);
debug.message("LogoutUtil.doSLOByPOST : relayState : "
+ sloRequestXMLString + "\nPOSTURL : " + relayState);
}
String encMsg = SAML2Utils.encodeForPOST(sloRequestXMLString);
SAML2Utils.postToTarget(request, response, "SAMLRequest", encMsg,
"RelayState", relayState, sloURL);
}
static LogoutResponse getLogoutResponseFromPost(String samlResponse,
HttpServletResponse response) throws SAML2Exception {
if (samlResponse == null) {
throw new SAML2Exception(SAML2Utils.bundle.getString(
"missingLogoutResponse"));
}
LogoutResponse resp = null;
ByteArrayInputStream bis = null;
try {
byte[] raw = Base64.decode(samlResponse);
if (raw != null) {
bis = new ByteArrayInputStream(raw);
Document doc = XMLUtils.toDOMDocument(bis, debug);
if (doc != null) {
resp = ProtocolFactory.getInstance().
createLogoutResponse(doc.getDocumentElement());
}
}
} catch (Exception e) {
debug.error("LogoutUtil.getLogoutResponseFromPost:", e);
} finally {
if (bis != null) {
try {
bis.close();
} catch (Exception ie) {
if (debug.messageEnabled()) {
debug.message("LogoutUtil.getLogoutResponseFromPost:",
ie);
}
}
}
}
if (resp == null) {
throw new SAML2Exception(SAML2Utils.bundle.getString(
"errorGettingLogoutResponse"));
}
return resp;
}
static LogoutRequest getLogoutRequestFromPost(String samlRequest,
HttpServletResponse response) throws SAML2Exception {
if (samlRequest == null) {
throw new SAML2Exception(SAML2Utils.bundle.getString(
"missingLogoutRequest"));
}
LogoutRequest req = null;
ByteArrayInputStream bis = null;
try {
byte[] raw = Base64.decode(samlRequest);
if (raw != null) {
bis = new ByteArrayInputStream(raw);
Document doc = XMLUtils.toDOMDocument(bis, debug);
if (doc != null) {
req = ProtocolFactory.getInstance().
createLogoutRequest(doc.getDocumentElement());
}
}
} catch (Exception e) {
debug.error("LogoutUtil.getLogoutRequestFromPost:", e);
} finally {
if (bis != null) {
try {
bis.close();
} catch (Exception ie) {
if (debug.messageEnabled()) {
debug.message("LogoutUtil.getLogoutRequestFromPost:",
ie);
}
}
}
}
if (req == null) {
throw new SAML2Exception(SAML2Utils.bundle.getString(
"errorGettingLogoutRequest"));
}
return req;
}
}