Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package com.onelogin.saml2.logout;
import java.io.IOException;
import java.net.URL;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.xpath.XPathExpressionException;
import org.apache.commons.lang3.text.StrSubstitutor;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import com.onelogin.saml2.exception.ValidationError;
import com.onelogin.saml2.exception.XMLEntityException;
import com.onelogin.saml2.exception.SettingsException;
import com.onelogin.saml2.http.HttpRequest;
import com.onelogin.saml2.settings.Saml2Settings;
import com.onelogin.saml2.util.Util;
import com.onelogin.saml2.util.Constants;
import com.onelogin.saml2.util.SchemaFactory;
/**
* LogoutRequest class of OneLogin's Java Toolkit.
*
* A class that implements SAML 2 Logout Request builder/parser/validator
*/
public class LogoutRequest {
/**
* Private property to construct a logger for this class.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(LogoutRequest.class);
/**
* SAML LogoutRequest string
*/
private final String logoutRequestString;
/**
* SAML LogoutRequest ID.
*/
public String id;
/**
* Settings data.
*/
private final Saml2Settings settings;
/**
* HttpRequest object to be processed (Contains GET and POST parameters, request URL, ...).
*/
private final HttpRequest request;
/**
* NameID.
*/
private String nameId;
/**
* NameID Format.
*/
private String nameIdFormat;
/**
* nameId NameQualifier
*/
private String nameIdNameQualifier;
/**
* nameId SP NameQualifier
*/
private String nameIdSPNameQualifier;
/**
* SessionIndex. When the user is logged, this stored it from the AuthnStatement of the SAML Response
*/
private String sessionIndex;
/**
* URL of the current host + current view
*/
private String currentUrl;
/**
* Time when the Logout Request was created
*/
private Calendar issueInstant;
/**
* After validation, if it fails this property has the cause of the problem
*/
private String error;
/**
* Constructs the LogoutRequest object.
*
* @param settings
* OneLogin_Saml2_Settings
* @param request
* the HttpRequest object to be processed (Contains GET and POST parameters, request URL, ...).
* @param nameId
* The NameID that will be set in the LogoutRequest.
* @param sessionIndex
* The SessionIndex (taken from the SAML Response in the SSO process).
* @param nameIdFormat
* The nameIdFormat that will be set in the LogoutRequest.
* @param nameIdNameQualifier
* The NameID NameQualifier that will be set in the LogoutRequest.
* @param nameIdSPNameQualifier
* The SP Name Qualifier that will be set in the LogoutRequest.
*
* @throws XMLEntityException
*/
public LogoutRequest(Saml2Settings settings, HttpRequest request, String nameId, String sessionIndex, String nameIdFormat, String nameIdNameQualifier, String nameIdSPNameQualifier) throws XMLEntityException {
this.settings = settings;
this.request = request;
String samlLogoutRequest = null;
if (request != null) {
samlLogoutRequest = request.getParameter("SAMLRequest");
currentUrl = request.getRequestURL();
}
if (samlLogoutRequest == null) {
id = Util.generateUniqueID(settings.getUniqueIDPrefix());
issueInstant = Calendar.getInstance();
this.nameId = nameId;
this.nameIdFormat = nameIdFormat;
this.nameIdNameQualifier = nameIdNameQualifier;
this.nameIdSPNameQualifier = nameIdSPNameQualifier;
this.sessionIndex = sessionIndex;
StrSubstitutor substitutor = generateSubstitutor(settings);
logoutRequestString = substitutor.replace(getLogoutRequestTemplate());
} else {
logoutRequestString = Util.base64decodedInflated(samlLogoutRequest);
id = getId(logoutRequestString);
}
}
/**
* Constructs the LogoutRequest object.
*
* @param settings
* OneLogin_Saml2_Settings
* @param request
* the HttpRequest object to be processed (Contains GET and POST parameters, request URL, ...).
* @param nameId
* The NameID that will be set in the LogoutRequest.
* @param sessionIndex
* The SessionIndex (taken from the SAML Response in the SSO process).
* @param nameIdFormat
* The nameIdFormat that will be set in the LogoutRequest.
* @param nameIdNameQualifier
* The NameID NameQualifier will be set in the LogoutRequest.
*
* @throws XMLEntityException
*/
public LogoutRequest(Saml2Settings settings, HttpRequest request, String nameId, String sessionIndex, String nameIdFormat, String nameIdNameQualifier) throws XMLEntityException {
this(settings, request, nameId, sessionIndex, nameIdFormat, nameIdNameQualifier, null);
}
/**
* Constructs the LogoutRequest object.
*
* @param settings
* OneLogin_Saml2_Settings
* @param request
* the HttpRequest object to be processed (Contains GET and POST parameters, request URL, ...).
* @param nameId
* The NameID that will be set in the LogoutRequest.
* @param sessionIndex
* The SessionIndex (taken from the SAML Response in the SSO process).
* @param nameIdFormat
* The nameIdFormat that will be set in the LogoutRequest.
*
* @throws XMLEntityException
*/
public LogoutRequest(Saml2Settings settings, HttpRequest request, String nameId, String sessionIndex, String nameIdFormat) throws XMLEntityException {
this(settings, request, nameId, sessionIndex, nameIdFormat, null);
}
/**
* Constructs the LogoutRequest object.
*
* @param settings
* OneLogin_Saml2_Settings
* @param request
* the HttpRequest object to be processed (Contains GET and POST parameters, request URL, ...).
* @param nameId
* The NameID that will be set in the LogoutRequest.
* @param sessionIndex
* The SessionIndex (taken from the SAML Response in the SSO process).
*
* @throws XMLEntityException
*/
public LogoutRequest(Saml2Settings settings, HttpRequest request, String nameId, String sessionIndex) throws XMLEntityException {
this(settings, request, nameId, sessionIndex, null);
}
/**
* Constructs the LogoutRequest object.
*
* @param settings
* OneLogin_Saml2_Settings
*
* @throws XMLEntityException
*/
public LogoutRequest(Saml2Settings settings) throws XMLEntityException {
this(settings, null, null, null);
}
/**
* Constructs the LogoutRequest object.
*
* @param settings
* OneLogin_Saml2_Settings
* @param request
* the HttpRequest object to be processed (Contains GET and POST parameters, request URL, ...).
*
* @throws XMLEntityException
*/
public LogoutRequest(Saml2Settings settings, HttpRequest request) throws XMLEntityException {
this(settings, request, null, null);
}
/**
* @return the base64 encoded unsigned Logout Request (deflated or not)
*
* @param deflated
* If deflated or not the encoded Logout Request
*
* @throws IOException
*/
public String getEncodedLogoutRequest(Boolean deflated) throws IOException {
String encodedLogoutRequest;
if (deflated == null) {
deflated = settings.isCompressRequestEnabled();
}
if (deflated) {
encodedLogoutRequest = Util.deflatedBase64encoded(getLogoutRequestXml());
} else {
encodedLogoutRequest = Util.base64encoder(getLogoutRequestXml());
}
return encodedLogoutRequest;
}
/**
* @return the base64 encoded unsigned Logout Request (deflated or not)
*
* @throws IOException
*/
public String getEncodedLogoutRequest() throws IOException {
return getEncodedLogoutRequest(null);
}
/**
* @return the plain XML Logout Request
*/
public String getLogoutRequestXml() {
return logoutRequestString;
}
/**
* Substitutes LogoutRequest variables within a string by values.
*
* @param settings
* Saml2Settings object. Setting data
*
* @return the StrSubstitutor object of the LogoutRequest
*/
private StrSubstitutor generateSubstitutor(Saml2Settings settings) {
Map valueMap = new HashMap();
valueMap.put("id", id);
String issueInstantString = Util.formatDateTime(issueInstant.getTimeInMillis());
valueMap.put("issueInstant", issueInstantString);
String destinationStr = "";
URL slo = settings.getIdpSingleLogoutServiceUrl();
if (slo != null) {
destinationStr = " Destination=\"" + slo.toString() + "\"";
}
valueMap.put("destinationStr", destinationStr);
valueMap.put("issuer", settings.getSpEntityId());
String nameIdFormat = null;
String spNameQualifier = this.nameIdSPNameQualifier;
String nameQualifier = this.nameIdNameQualifier;
if (nameId != null) {
if (this.nameIdFormat == null && !settings.getSpNameIDFormat().equals(Constants.NAMEID_UNSPECIFIED)) {
nameIdFormat = settings.getSpNameIDFormat();
} else {
nameIdFormat = this.nameIdFormat;
}
} else {
nameId = settings.getIdpEntityId();
nameIdFormat = Constants.NAMEID_ENTITY;
}
// From saml-core-2.0-os 8.3.6, when the entity Format is used: "The NameQualifier, SPNameQualifier, and
// SPProvidedID attributes MUST be omitted.
if (nameIdFormat != null && nameIdFormat.equals(Constants.NAMEID_ENTITY)) {
nameQualifier = null;
spNameQualifier = null;
}
// NameID Format UNSPECIFIED omitted
if (nameIdFormat != null && nameIdFormat.equals(Constants.NAMEID_UNSPECIFIED)) {
nameIdFormat = null;
}
X509Certificate cert = null;
if (settings.getNameIdEncrypted()) {
cert = settings.getIdpx509cert();
}
String nameIdStr = Util.generateNameId(nameId, spNameQualifier, nameIdFormat, nameQualifier, cert);
valueMap.put("nameIdStr", nameIdStr);
String sessionIndexStr = "";
if (sessionIndex != null) {
sessionIndexStr = " " + sessionIndex + "";
}
valueMap.put("sessionIndexStr", sessionIndexStr);
return new StrSubstitutor(valueMap);
}
/**
* @return the LogoutRequest's template
*/
private static StringBuilder getLogoutRequestTemplate() {
StringBuilder template = new StringBuilder();
template.append("");
template.append("${issuer}");
template.append("${nameIdStr}${sessionIndexStr}");
return template;
}
/**
* Determines if the SAML LogoutRequest is valid or not
*
* @return true if the SAML LogoutRequest is valid
*
* @throws Exception
*/
public Boolean isValid() throws Exception {
error = null;
try {
if (this.logoutRequestString == null || logoutRequestString.isEmpty()) {
throw new ValidationError("SAML Logout Request is not loaded", ValidationError.INVALID_XML_FORMAT);
}
if (this.request == null) {
throw new Exception("The HttpRequest of the current host was not established");
}
if (this.currentUrl == null || this.currentUrl.isEmpty()) {
throw new Exception("The URL of the current host was not established");
}
String signature = request.getParameter("Signature");
Document logoutRequestDocument = Util.loadXML(logoutRequestString);
if (settings.isStrict()) {
Element rootElement = logoutRequestDocument.getDocumentElement();
rootElement.normalize();
if (settings.getWantXMLValidation()) {
if (!Util.validateXML(logoutRequestDocument, SchemaFactory.SAML_SCHEMA_PROTOCOL_2_0)) {
throw new ValidationError("Invalid SAML Logout Request. Not match the saml-schema-protocol-2.0.xsd", ValidationError.INVALID_XML_FORMAT);
}
}
// Check NotOnOrAfter
if (rootElement.hasAttribute("NotOnOrAfter")) {
String notOnOrAfter = rootElement.getAttribute("NotOnOrAfter");
DateTime notOnOrAfterDate = Util.parseDateTime(notOnOrAfter);
if (notOnOrAfterDate.isEqualNow() || notOnOrAfterDate.isBeforeNow()) {
throw new ValidationError("Could not validate timestamp: expired. Check system clock.", ValidationError.RESPONSE_EXPIRED);
}
}
// Check destination
if (rootElement.hasAttribute("Destination")) {
String destinationUrl = rootElement.getAttribute("Destination");
if (destinationUrl != null) {
if (!destinationUrl.isEmpty() && !destinationUrl.equals(currentUrl)) {
throw new ValidationError("The LogoutRequest was received at " + currentUrl + " instead of "
+ destinationUrl, ValidationError.WRONG_DESTINATION);
}
}
}
// Try get the nameID
String nameID = getNameId(logoutRequestDocument, settings.getSPkey());
// Check the issuer
String issuer = getIssuer(logoutRequestDocument);
if (issuer != null && (issuer.isEmpty() || !issuer.equals(settings.getIdpEntityId()))) {
throw new ValidationError(
String.format("Invalid issuer in the Logout Request. Was '%s', but expected '%s'", issuer, settings.getIdpEntityId()),
ValidationError.WRONG_ISSUER
);
}
if (settings.getWantMessagesSigned() && (signature == null || signature.isEmpty())) {
throw new ValidationError("The Message of the Logout Request is not signed and the SP requires it", ValidationError.NO_SIGNED_MESSAGE);
}
}
if (signature != null && !signature.isEmpty()) {
X509Certificate cert = settings.getIdpx509cert();
if (cert == null) {
throw new SettingsException("In order to validate the sign on the Logout Request, the x509cert of the IdP is required", SettingsException.CERT_NOT_FOUND);
}
List certList = new ArrayList();
List multipleCertList = settings.getIdpx509certMulti();
if (multipleCertList != null && multipleCertList.size() != 0) {
certList.addAll(multipleCertList);
}
if (certList.isEmpty() || !certList.contains(cert)) {
certList.add(0, cert);
}
String signAlg = request.getParameter("SigAlg");
if (signAlg == null || signAlg.isEmpty()) {
signAlg = Constants.RSA_SHA1;
}
String relayState = request.getEncodedParameter("RelayState");
String signedQuery = "SAMLRequest=" + request.getEncodedParameter("SAMLRequest");
if (relayState != null && !relayState.isEmpty()) {
signedQuery += "&RelayState=" + relayState;
}
signedQuery += "&SigAlg=" + request.getEncodedParameter("SigAlg", signAlg);
if (!Util.validateBinarySignature(signedQuery, Util.base64decoder(signature), certList, signAlg)) {
throw new ValidationError("Signature validation failed. Logout Request rejected", ValidationError.INVALID_SIGNATURE);
}
}
LOGGER.debug("LogoutRequest validated --> " + logoutRequestString);
return true;
} catch (Exception e) {
error = e.getMessage();
LOGGER.debug("LogoutRequest invalid --> " + logoutRequestString);
LOGGER.error(error);
return false;
}
}
/**
* Returns the ID of the Logout Request Document.
*
* @param samlLogoutRequestDocument
* A DOMDocument object loaded from the SAML Logout Request.
*
* @return the ID of the Logout Request.
*/
public static String getId(Document samlLogoutRequestDocument) {
String id = null;
try {
Element rootElement = samlLogoutRequestDocument.getDocumentElement();
rootElement.normalize();
id = rootElement.getAttribute("ID");
} catch (Exception e) {}
return id;
}
/**
* Returns the ID of the Logout Request String.
*
* @param samlLogoutRequestString
* A Logout Request string.
*
* @return the ID of the Logout Request.
*
*/
public static String getId(String samlLogoutRequestString) {
Document doc = Util.loadXML(samlLogoutRequestString);
return getId(doc);
}
/**
* Gets the NameID Data from the the Logout Request Document.
*
* @param samlLogoutRequestDocument
* A DOMDocument object loaded from the SAML Logout Request.
* @param key
* The SP key to decrypt the NameID if encrypted
*
* @return the Name ID Data (Value, Format, NameQualifier, SPNameQualifier)
*
* @throws Exception
*/
public static Map getNameIdData(Document samlLogoutRequestDocument, PrivateKey key) throws Exception {
NodeList encryptedIDNodes = Util.query(samlLogoutRequestDocument, "/samlp:LogoutRequest/saml:EncryptedID");
NodeList nameIdNodes;
Element nameIdElem;
if (encryptedIDNodes.getLength() == 1) {
if (key == null) {
throw new SettingsException("Key is required in order to decrypt the NameID", SettingsException.PRIVATE_KEY_NOT_FOUND);
}
Element encryptedData = (Element) encryptedIDNodes.item(0);
Util.decryptElement(encryptedData, key);
nameIdNodes = Util.query(samlLogoutRequestDocument, "/samlp:LogoutRequest/saml:NameID");
if (nameIdNodes == null || nameIdNodes.getLength() != 1) {
throw new Exception("Not able to decrypt the EncryptedID and get a NameID");
}
}
else {
nameIdNodes = Util.query(samlLogoutRequestDocument, "/samlp:LogoutRequest/saml:NameID");
}
if (nameIdNodes != null && nameIdNodes.getLength() == 1) {
nameIdElem = (Element) nameIdNodes.item(0);
} else {
throw new ValidationError("No name id found in Logout Request.", ValidationError.NO_NAMEID);
}
Map nameIdData = new HashMap();
if (nameIdElem != null) {
nameIdData.put("Value", nameIdElem.getTextContent());
if (nameIdElem.hasAttribute("Format")) {
nameIdData.put("Format", nameIdElem.getAttribute("Format"));
}
if (nameIdElem.hasAttribute("SPNameQualifier")) {
nameIdData.put("SPNameQualifier", nameIdElem.getAttribute("SPNameQualifier"));
}
if (nameIdElem.hasAttribute("NameQualifier")) {
nameIdData.put("NameQualifier", nameIdElem.getAttribute("NameQualifier"));
}
}
return nameIdData;
}
/**
* Gets the NameID Data from the the Logout Request String.
*
* @param samlLogoutRequestString
* A DOMDocument object loaded from the SAML Logout Request.
* @param key
* The SP key to decrypt the NameID if encrypted
*
* @return the Name ID Data (Value, Format, NameQualifier, SPNameQualifier)
*
* @throws Exception
*/
public static Map getNameIdData(String samlLogoutRequestString, PrivateKey key) throws Exception {
Document doc = Util.loadXML(samlLogoutRequestString);
return getNameIdData(doc, key);
}
/**
* Gets the NameID value provided from the SAML Logout Request Document.
*
* @param samlLogoutRequestDocument
* A DOMDocument object loaded from the SAML Logout Request.
* @param key
* The SP key to decrypt the NameID if encrypted
*
* @return the Name ID value
*
* @throws Exception
*/
public static String getNameId(Document samlLogoutRequestDocument, PrivateKey key) throws Exception
{
Map nameIdData = getNameIdData(samlLogoutRequestDocument, key);
LOGGER.debug("LogoutRequest has NameID --> " + nameIdData.get("Value"));
return nameIdData.get("Value");
}
/**
* Gets the NameID value provided from the SAML Logout Request Document.
*
* @param samlLogoutRequestDocument
* A DOMDocument object loaded from the SAML Logout Request.
*
* @return the Name ID value
*
* @throws Exception
*/
public static String getNameId(Document samlLogoutRequestDocument) throws Exception
{
return getNameId(samlLogoutRequestDocument, null);
}
/**
* Gets the NameID value provided from the SAML Logout Request String.
*
* @param samlLogoutRequestString
* A Logout Request string.
* @param key
* The SP key to decrypt the NameID if encrypted
*
* @return the Name ID value
*
* @throws Exception
*/
public static String getNameId(String samlLogoutRequestString, PrivateKey key) throws Exception
{
Map nameId = getNameIdData(samlLogoutRequestString, key);
return nameId.get("Value");
}
/**
* Gets the NameID value provided from the SAML Logout Request String.
*
* @param samlLogoutRequestString
* A Logout Request string.
*
* @return the Name ID value
*
* @throws Exception
*/
public static String getNameId(String samlLogoutRequestString) throws Exception
{
return getNameId(samlLogoutRequestString, null);
}
/**
* Gets the Issuer from Logout Request Document.
*
* @param samlLogoutRequestDocument
* A DOMDocument object loaded from the SAML Logout Request.
*
* @return the issuer of the logout request
*
* @throws XPathExpressionException
*/
public static String getIssuer(Document samlLogoutRequestDocument) throws XPathExpressionException
{
String issuer = null;
NodeList nodes = Util.query(samlLogoutRequestDocument, "/samlp:LogoutRequest/saml:Issuer");
if (nodes.getLength() == 1) {
issuer = nodes.item(0).getTextContent();
}
return issuer;
}
/**
* Gets the Issuer from Logout Request String.
*
* @param samlLogoutRequestString
* A Logout Request string.
*
* @return the issuer of the logout request
*
* @throws XPathExpressionException
*/
public static String getIssuer(String samlLogoutRequestString) throws XPathExpressionException
{
Document doc = Util.loadXML(samlLogoutRequestString);
return getIssuer(doc);
}
/**
* Gets the SessionIndexes from the LogoutRequest.
*
* @param samlLogoutRequestDocument
* A DOMDocument object loaded from the SAML Logout Request.
* @return the SessionIndexes
*
* @throws XPathExpressionException
*/
public static List getSessionIndexes(Document samlLogoutRequestDocument) throws XPathExpressionException
{
List sessionIndexes = new ArrayList();
NodeList nodes = Util.query(samlLogoutRequestDocument, "/samlp:LogoutRequest/samlp:SessionIndex");
for (int i = 0; i < nodes.getLength(); i++) {
sessionIndexes.add(nodes.item(i).getTextContent());
}
return sessionIndexes;
}
/**
* Gets the SessionIndexes from the LogoutRequest.
*
* @param samlLogoutRequestString
* A Logout Request string.
* @return the SessionIndexes
*
* @throws XPathExpressionException
*/
public static List getSessionIndexes(String samlLogoutRequestString) throws XPathExpressionException
{
Document doc = Util.loadXML(samlLogoutRequestString);
return getSessionIndexes(doc);
}
/**
* After execute a validation process, if fails this method returns the cause
*
* @return the cause of the validation error
*/
public String getError() {
return error;
}
/**
* @return the ID of the Logout Request
*/
public String getId()
{
return id;
}
}