/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2007 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: QueryClient.java,v 1.9 2009/10/29 00:19:21 madan_ranganath Exp $
*
* Portions Copyrighted 2015-2016 ForgeRock AS.
* Portions Copyrighted 2016 Nomura Research Institute, Ltd.
*/
package com.sun.identity.saml2.soapbinding;
import static org.forgerock.openam.utils.Time.*;
import com.sun.identity.saml.xmlsig.KeyProvider;
import com.sun.identity.saml2.assertion.Assertion;
import com.sun.identity.saml2.assertion.AssertionFactory;
import com.sun.identity.saml2.assertion.EncryptedAssertion;
import com.sun.identity.saml2.assertion.Issuer;
import com.sun.identity.saml2.common.SAML2Constants;
import com.sun.identity.saml2.common.SAML2Exception;
import com.sun.identity.saml2.common.SAML2SDKUtils;
import com.sun.identity.saml2.common.SAML2Utils;
import com.sun.identity.saml2.jaxb.entityconfig.XACMLAuthzDecisionQueryConfigElement;
import com.sun.identity.saml2.jaxb.entityconfig.XACMLPDPConfigElement;
import com.sun.identity.saml2.jaxb.metadata.XACMLAuthzDecisionQueryDescriptorElement;
import com.sun.identity.saml2.jaxb.metadata.XACMLAuthzServiceElement;
import com.sun.identity.saml2.jaxb.metadata.XACMLPDPDescriptorElement;
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.protocol.ProtocolFactory;
import com.sun.identity.saml2.protocol.RequestAbstract;
import com.sun.identity.saml2.protocol.Response;
import com.sun.identity.saml2.protocol.impl.ResponseImpl;
import com.sun.identity.xacml.saml2.XACMLAuthzDecisionQuery;
import javax.xml.soap.SOAPException;
import com.sun.identity.shared.jaxrpc.SOAPClient;
import com.sun.identity.shared.debug.Debug;
import com.sun.identity.shared.xml.XMLUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.Key;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import javax.xml.soap.SOAPConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* The <code>QueryClient</code> class provides Query Requester clients with
* a method to send requests using SOAP connection to SOAP endpoint.
*
*/
public class QueryClient {
public static Debug debug = Debug.getInstance("libSAML2");
private static SAML2MetaManager saml2MetaManager = null;
static {
try {
saml2MetaManager =
new SAML2MetaManager();
} catch (SAML2MetaException sme) {
debug.error("Error retreiving metadata",sme);
}
}
private QueryClient() {}
/**
* Returns SAMLv2 <code>Response</code>.
* SAMLv2 request is sent enclosed in the body of a SOAP Message
* to a SOAP endpoint.
* Prior to sending the request query, attributes required for completeness
* of the SAMLv2 Request will be set (eg. Issuer) if not already set.
* Message will be signed if signing is enabled.
* SAMLv2 Query Request will be enclosed in the SOAP Body to create a SOAP
* message to send to the server.
*
* @param request the SAMLv2 <code>RequestAbstract</code> object.
* @param pepEntityID entity identifier of the hosted query requester.
* @param pdpEntityID entity identifier of the remote server.
* @return SAMLv2 <code>Response</code> received from the
* Query Responder.
* @throws SAML2Exception if there is an error processing the query.
*/
public static Response processXACMLQuery(RequestAbstract request,
String pepEntityID,
String pdpEntityID)
throws SAML2Exception {
String classMethod = "QueryClient:processXACMLQuery";
String realm = "/";
Response samlResponse = null;
Response response = null;
// retreive pepEntityID metadata
if (pepEntityID == null || pepEntityID.length() == 0 ) {
debug.error(classMethod + "PEP Identifier is null");
String[] data = { pepEntityID };
LogUtil.error(Level.INFO,LogUtil.INVALID_PEP_ID,data);
throw new SAML2Exception(
SAML2SDKUtils.bundle.getString("nullPEP"));
}
// retreive pdpEntityID metadata
if (pdpEntityID == null || pdpEntityID.length() == 0) {
debug.error(classMethod + "PDP Identifier is null");
String[] data = { pdpEntityID };
LogUtil.error(Level.INFO,LogUtil.INVALID_PDP_ID,data);
throw new SAML2Exception(
SAML2SDKUtils.bundle.getString("nullPDP"));
}
if (request != null ) {
// set properties in the request.
XACMLAuthzDecisionQuery xacmlQuery =
(XACMLAuthzDecisionQuery) request;
if (xacmlQuery != null) {
// set Issuer
Issuer issuer = createIssuer(pepEntityID);
xacmlQuery.setIssuer(issuer);
//generate ID
String requestID = SAML2SDKUtils.generateID();
xacmlQuery.setID(requestID);
xacmlQuery.setVersion(SAML2Constants.VERSION_2_0);
xacmlQuery.setIssueInstant(newDate());
XACMLPDPConfigElement pdpConfig = getPDPConfig(realm,
pdpEntityID);
if (pdpConfig != null) {
String wantQuerySigned = getAttributeValueFromPDPConfig(
pdpConfig,
"wantXACMLAuthzDecisionQuerySigned");
if (wantQuerySigned != null &&
wantQuerySigned.equals("true")) {
signAttributeQuery(xacmlQuery,realm,pepEntityID, false);
}
}
String xmlString = xacmlQuery.toXMLString(true,true);
if (debug.messageEnabled()) {
debug.message(classMethod + "XACML Query XML String :"
+ xmlString);
}
// retrieve endpoint from meta data
String endPoint = null;
XACMLAuthzDecisionQueryConfigElement pepConfig =
getPEPConfig(realm,pepEntityID);
endPoint = getPDPEndPoint(pdpEntityID);
if (debug.messageEnabled()) {
debug.message(classMethod + " ResponseLocation is :" +
endPoint);
}
// create SOAP message
try {
String soapMessage =
SAML2SDKUtils.createSOAPMessageString(xmlString);
endPoint =
SAML2SDKUtils.fillInBasicAuthInfo(
pepConfig,endPoint);
String[] urls = { endPoint };
SOAPClient soapClient = new SOAPClient(urls);
if (debug.messageEnabled()) {
debug.message(classMethod + "soapMessage :" +
soapMessage);
}
InputStream soapIn =
soapClient.call(soapMessage,null,null);
StringBuffer reply = new StringBuffer();
String line;
BufferedReader reader = new BufferedReader(
new InputStreamReader(soapIn, "UTF-8"));
while ((line = reader.readLine()) != null) {
reply.append(line).append("\n");
}
// check the SOAP message for any SOAP related errors
// before passing control to SAML processor
xmlString = reply.toString();
if (debug.messageEnabled()) {
debug.message("Response Message:\n"+ xmlString);
}
samlResponse = getSAMLResponse(xmlString);
issuer = samlResponse.getIssuer();
String issuerID = null;
if (issuer != null) {
issuerID = issuer.getValue().trim();
}
boolean isTrusted = verifyResponseIssuer(realm,
pepEntityID,issuerID);
if (!isTrusted) {
if (debug.messageEnabled()) {
debug.message(classMethod +
"Issuer in Request is not valid.");
}
String[] args = {realm, pepEntityID, pdpEntityID};
LogUtil.error(Level.INFO,
LogUtil.INVALID_ISSUER_IN_PEP_REQUEST,
args);
throw new SAML2Exception("invalidIssuerInRequest");
}
if (samlResponse != null) {
xmlString =samlResponse.toXMLString(true,true);
if (debug.messageEnabled()) {
debug.message(classMethod + "Response: "
+ xmlString);
}
response =
verifyResponse(realm,pepEntityID,samlResponse);
if (debug.messageEnabled()) {
debug.message(classMethod +
"Response with decrypted Assertion: "
+ response.toXMLString(true,true));
}
}
} catch (SOAPException soae) {
if (debug.messageEnabled()) {
debug.message(classMethod + "SOAPException :",soae);
}
throw new SAML2Exception(soae.getMessage());
} catch (Exception e) {
if (debug.messageEnabled()) {
debug.message(classMethod + "Exception " , e);
}
throw new SAML2Exception(e.getMessage());
}
}
}
return response;
}
/**
* Returns <code>Issuer</code> for the entity identifier.
*
* @param entityID entity identifier.
* @return the <code>Issuer</code> object.
* @exception <code>SAML2Exception</code> if there is an error creating
* the issuer.
*/
private static Issuer createIssuer(String entityID)
throws SAML2Exception {
Issuer issuer = AssertionFactory.getInstance().createIssuer();
issuer.setValue(entityID);
return issuer;
}
/**
* Returns SAMLv2 <code>Response</code> object. The <code>Response</code>
* object is created from the String representation of the object.
*
* @param xmlString the String representation of the object.
* @return the <code>Response</code> object.
* @exception <code>IOException</code> if there is an error processing the
* response.
* @exception <code>SAML2Exception</code> if there is an error processing
* the response.
*/
private static Response getSAMLResponse(String xmlString)
throws IOException,SAML2Exception {
String classMethod="QueryClient:getSAMLResponse";
if (xmlString == null || xmlString.length() == 0) {
throw new SAML2Exception(
SAML2SDKUtils.bundle.getString("nullResponse"));
}
if (debug.messageEnabled()) {
debug.message(classMethod + "Response String : " + xmlString);
}
Response samlResponse = null;
Document doc = XMLUtils.toDOMDocument(xmlString, debug);
Element root= doc.getDocumentElement();
String rootName = root.getLocalName();
if (!(rootName.equals("Envelope")) ||
(!(root.getNamespaceURI().equals(
SOAPConstants.URI_NS_SOAP_ENVELOPE)))) {
SAML2SDKUtils.debug.error("Wrong Envelope tag or namespace.");
throw new SAML2Exception(
SAML2SDKUtils.bundle.getString("serverError"));
}
//examine the child element of <SOAP-ENV:Envelope>
NodeList nodes = root.getChildNodes();
int nodeCount = nodes.getLength();
if (nodeCount <= 0) {
SAML2SDKUtils.debug.error("Envelope does not contain a SOAP body.");
throw new SAML2Exception(
SAML2SDKUtils.bundle.getString("missingSOAPBody"));
}
String tagName = null;
String ctagName = null;
Node currentNode = null;
Node cnode = null;
for (int i = 0; i < nodeCount; i++) {
currentNode = nodes.item(i);
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
tagName = currentNode.getLocalName();
if ((tagName == null) || tagName.length() == 0) {
SAML2SDKUtils.debug.error(classMethod +
"Child element is missing tag name");
throw new SAML2Exception(
SAML2SDKUtils.bundle.getString("missingChildTagName"));
}
if (tagName.equals("Body")) {
NodeList cNodes = currentNode.getChildNodes();
int cnodeCount = cNodes.getLength();
for (int j = 0; j < cnodeCount; j++) {
cnode = cNodes.item(j);
if (cnode.getNodeType() == Node.ELEMENT_NODE){
ctagName = cnode.getLocalName();
if ((ctagName == null) || ctagName.length() == 0) {
SAML2SDKUtils.debug.error("Missing tag name " +
"of child element of <SOAP-ENV:Body>");
throw new SAML2Exception(
SAML2SDKUtils.bundle.getString(
"missingChildTagName"));
}
if (ctagName.equals("Fault")) {
SAML2SDKUtils.debug.error("SOAPFault error.");
throw new SAML2Exception(
XMLUtils.print(cnode));
} else if (ctagName.equals("Response")) {
samlResponse = ProtocolFactory.getInstance()
.createResponse((Element)cnode);
break;
} else {
SAML2SDKUtils.debug.error("Invalid child " +
"element in SOAPBody");
throw new SAML2Exception(
SAML2SDKUtils.bundle.getString(
"invalidSOAPBody"));
}
}
} // end of for(int j=0; j <cnodeCount; j++)
} else if (tagName.equals("Header")) {
if (SAML2SDKUtils.debug.messageEnabled()) {
SAML2SDKUtils.debug.message("SOAP Header in Response");
}
} else {
SAML2SDKUtils.debug.error("Invalid element in Envelope");
throw new SAML2Exception(
SAML2SDKUtils.bundle.getString("invalidSOAPElement"));
}
} // end of if (currentNode.getNodeType() == Node.ELEMENT_NODE)
} // end of for (int i = 0; i < nodeCount; i++)
return samlResponse;
}
/**
* Returns true if the PEP and PDP entities are in the same Circle of
* Trust. Verifies <code>Issuer</code> in <code>Response</code> to
* retreive the PDP entity identity.
*
* @param realm realm of the entity.
* @param pepEntityID PEP entity identifier
* @param pdpEntityID <code>Response</code> issuer identifier.
* @return true if issuer is valid.
* @throws SAML2Exception if there is an error during verification.
*/
private static boolean verifyResponseIssuer(String realm,String pepEntityID,
String pdpEntityID) throws SAML2Exception {
boolean isTrusted = false;
try {
isTrusted = saml2MetaManager.
isTrustedXACMLProvider(realm,pepEntityID,
pdpEntityID,SAML2Constants.PEP_ROLE);
} catch (SAML2MetaException sme) {
debug.error("Error retreiving meta",sme);
}
return isTrusted;
}
/**
* Returns the Policy Decision Point End Point (PDP) URL.
*
* @param pdpEntityID entity Identifier of the PDP.
* @return the PDP endpoint URL.
* @exception if there is an error retreiving the endpoint from the
* configuration.
*/
private static String getPDPEndPoint(String pdpEntityID)
throws SAML2Exception {
String endPoint = null;
String classMethod = "QueryClient:getPDPEndPoint";
if (saml2MetaManager != null) {
try {
XACMLPDPDescriptorElement pdpDescriptor =
saml2MetaManager.
getPolicyDecisionPointDescriptor(null,
pdpEntityID);
if (pdpDescriptor != null) {
List xacmlPDP = pdpDescriptor.getXACMLAuthzService();
if (xacmlPDP != null) {
Iterator i = xacmlPDP.iterator();
while (i.hasNext()) {
Object o = (Object) i.next();
if (o instanceof XACMLAuthzServiceElement) {
XACMLAuthzServiceElement xType =
(XACMLAuthzServiceElement) o;
endPoint = xType.getLocation();
if (debug.messageEnabled()) {
debug.message(classMethod +
"EndPoint :" + endPoint);
}
}
break;
}
}
}
} catch (SAML2MetaException sme) {
if (debug.messageEnabled()) {
debug.message(classMethod+"Error retreiving PDP Meta",sme);
}
String[] args = { pdpEntityID };
LogUtil.error(Level.INFO,LogUtil.PDP_METADATA_ERROR,args);
throw new SAML2Exception(SAML2SDKUtils.BUNDLE_NAME,
"pdpMetaRetreivalError",args);
}
}
return endPoint;
}
/**
* Returns the extended Policy Enforcement Point Configuration.
*
* @param realm the realm of the entity.
* @param pepEntityId identifier of the PEP.
* @return the <code>XACMLAuthzDecisionQueryConfigElement</code> object.
* @exception <code>SAML2Exception</code> if there is an error retreiving
* the extended configuration.
*/
private static XACMLAuthzDecisionQueryConfigElement getPEPConfig(
String realm,
String pepEntityID) throws SAML2Exception {
XACMLAuthzDecisionQueryConfigElement pepConfig = null;
String classMethod = "QueryClient:getPEPConfig";
if (saml2MetaManager != null) {
try {
pepConfig =
saml2MetaManager.
getPolicyEnforcementPointConfig(realm,pepEntityID);
} catch (SAML2MetaException sme) {
if (debug.messageEnabled()) {
debug.message(classMethod+"Error retreiving PEP meta",sme);
}
String[] args = { pepEntityID };
LogUtil.error(Level.INFO,LogUtil.PEP_METADATA_ERROR,args);
throw new SAML2Exception(SAML2SDKUtils.BUNDLE_NAME,
"pepMetaRetreivalError",args);
}
}
return pepConfig;
}
/**
* Returns the extended Policy Decision Point Configuration.
*
* @param realm the realm of the entity.
* @param pdpEntityId identifier of the PDP.
* @return the <code>XACMLPDPConfigElement</code> object.
* @exception <code>SAML2Exception</code> if there is an error retreiving
* the extended configuration.
*/
private static XACMLPDPConfigElement getPDPConfig(
String realm,
String pdpEntityID) throws SAML2Exception {
XACMLPDPConfigElement pdpConfig = null;
String classMethod = "QueryClient:getPDPConfig";
if (saml2MetaManager != null) {
try {
pdpConfig =
saml2MetaManager.getPolicyDecisionPointConfig(realm,
pdpEntityID);
} catch (SAML2MetaException sme) {
if (debug.messageEnabled()) {
debug.message(classMethod+"Error retreiving PDP meta",sme);
}
String[] args = { pdpEntityID };
LogUtil.error(Level.INFO,LogUtil.PEP_METADATA_ERROR,args);
throw new SAML2Exception(SAML2SDKUtils.BUNDLE_NAME,
"pdpMetaRetreivalError",args);
}
}
return pdpConfig;
}
/**
* Returns SAMLv2 <code>Response</code> after validation of the
* response. A new <code>Response</code> object is created which
* contains decrypted assertion if the assertions were encrypted.
*
* @param realm the realm of the entity.
* @param pepEntityID entity identifier of the PEP.
* @param samlResponse the <code>Response</code>.
* @exception <code>SAML2Exception</code> if there is an error.
*/
private static Response verifyResponse(String realm,String pepEntityID,
Response samlResponse) throws SAML2Exception {
Response response = samlResponse;
String classMethod = "QueryClient:verifyResponse";
if (samlResponse != null) {
//validate issuer trust.
Issuer issuer = samlResponse.getIssuer();
String issuerID = null;
if (issuer != null) {
issuerID = issuer.getValue().trim();
}
String pdpEntityID = issuerID;
boolean isTrusted =
verifyResponseIssuer(realm,pepEntityID,issuerID);
if (!isTrusted) {
if (debug.messageEnabled()) {
debug.message(classMethod +
"Issuer in Response is not valid.");
}
String[] args = {realm, pepEntityID, issuerID};
LogUtil.error(Level.INFO,
LogUtil.INVALID_ISSUER_RESPONSE,
args);
throw new SAML2Exception(
SAML2SDKUtils.BUNDLE_NAME,"invalidIssuerInResponse", args);
}
// verify signed response
verifySignedResponse(pepEntityID,pdpEntityID, samlResponse);
try {
// check if assertion needs to be encrypted,signed.
XACMLAuthzDecisionQueryConfigElement pepConfig =
saml2MetaManager.getPolicyEnforcementPointConfig(realm,
pepEntityID);
String assertionEncrypted = getAttributeValueFromPEPConfig(
pepConfig,SAML2Constants.WANT_ASSERTION_ENCRYPTED);
boolean wantAssertionEncrypted = (assertionEncrypted != null &&
assertionEncrypted.equalsIgnoreCase("true"))
? true:false;
boolean wantAssertionSigned =
wantAssertionSigned(realm,pepEntityID);
String respID = samlResponse.getID();
List assertions = samlResponse.getAssertion();
if (wantAssertionEncrypted && (assertions != null
&& (assertions.size() != 0))) {
String[] data = { issuerID , respID };
LogUtil.error(Level.INFO,
LogUtil.ASSERTION_FROM_PDP_NOT_ENCRYPTED,
data);
throw new SAML2Exception(
SAML2SDKUtils.bundle.getString(
"assertionNotEncrypted"));
}
Set<PrivateKey> decryptionKeys;
List<EncryptedAssertion> encAssertions = samlResponse.getEncryptedAssertion();
if (encAssertions != null) {
decryptionKeys = KeyUtil.getDecryptionKeys(pepConfig);
for (EncryptedAssertion encAssertion : encAssertions) {
Assertion assertion = encAssertion.decrypt(decryptionKeys);
if (assertions == null) {
assertions = new ArrayList<>();
}
assertions.add(assertion);
}
}
if (assertions == null || assertions.size() == 0) {
if (debug.messageEnabled()) {
debug.message(classMethod +
"no assertion in the Response.");
}
String[] data = {issuerID , respID};
LogUtil.error(Level.INFO,
LogUtil.MISSING_ASSERTION_IN_PDP_RESPONSE,data);
throw new SAML2Exception(
SAML2SDKUtils.bundle.getString("missingAssertion"));
}
// validate Issuer in Assertion
Iterator assertionIter = assertions.iterator();
Set<X509Certificate> verificationCerts = null;
XACMLPDPDescriptorElement pdpDesc = null;
if (wantAssertionSigned) {
pdpDesc =
saml2MetaManager.getPolicyDecisionPointDescriptor(
realm,pdpEntityID);
verificationCerts = KeyUtil.getPDPVerificationCerts(pdpDesc,pdpEntityID);
}
while (assertionIter.hasNext()) {
Assertion assertion = (Assertion) assertionIter.next();
String assertionID = assertion.getID();
String assertionIssuer =
assertion.getIssuer().getValue().trim();
isTrusted =
verifyResponseIssuer(
realm, pepEntityID,assertionIssuer);
if (!isTrusted) {
debug.error(classMethod +
"Assertion's source site is not valid.");
String[] data = {assertionIssuer,assertionID};
LogUtil.error(Level.INFO,
LogUtil.INVALID_ISSUER_IN_ASSERTION_FROM_PDP,data);
throw new SAML2Exception(SAML2SDKUtils.bundle.getString(
"invalidIssuerInAssertion"));
}
String respIssuer =
samlResponse.getIssuer().getValue().trim();
if (!respIssuer.equals(assertionIssuer)) {
if (debug.messageEnabled()) {
debug.message(classMethod + "Issuer in Assertion "+
assertionIssuer
+ "doesn't match the Issuer in Response."
+ respIssuer);
}
String[] data = {pdpEntityID , assertionIssuer};
LogUtil.error(Level.INFO,
LogUtil.MISMATCH_ISSUER_IN_ASSERTION_FROM_PDP,data);
throw new SAML2Exception(
SAML2SDKUtils.bundle.getString("mismatchIssuer"));
}
if (wantAssertionSigned) {
if (debug.messageEnabled()) {
debug.message(classMethod + "wantAssertionSigned "
+ wantAssertionSigned);
}
if (!assertion.isSigned() || !assertion.isSignatureValid(verificationCerts)) {
debug.error(classMethod +
"Assertion is not signed or signature " +
"is not valid.");
String[] data = {assertionIssuer , assertionID};
LogUtil.error(Level.INFO,
LogUtil.INVALID_SIGNATURE_ASSERTION_FROM_PDP,
data);
throw new SAML2Exception(
SAML2SDKUtils.bundle.getString(
"invalidSignatureOnAssertion"));
}
}
} //end while
if (wantAssertionEncrypted) {
response = createResponse(samlResponse,assertions);
}
if (debug.messageEnabled()) {
debug.message(classMethod + " Response : " +
response.toXMLString(true, true));
}
} catch (SAML2MetaException sme) {
if (debug.messageEnabled()) {
debug.message(classMethod + "Error retreiving meta",sme);
}
throw new SAML2Exception(
SAML2SDKUtils.bundle.getString("metaDataError"));
}
}
return response;
}
/**
* Returns SAMLv2 <code>Response</code> object.
* A new <code>Response</code> object is created from
* the received response to include decrypted assertion
* if the response contained encrypted assertion.
*
* @param samlResponse the <code>Response</code> object.
* @return <code>Response</code> object.
* @exception <code>SAML2Exception</code> if there is an error creating
* the response.
*/
private static Response createResponse(Response samlResponse,
List assertions) throws SAML2Exception {
Response response = new ResponseImpl();
response.setVersion(samlResponse.getVersion()) ;
response.setIssueInstant(samlResponse.getIssueInstant());
response.setID(samlResponse.getID());
response.setInResponseTo(samlResponse.getInResponseTo());
response.setIssuer(samlResponse.getIssuer());
response.setDestination(samlResponse.getDestination());
response.setExtensions(samlResponse.getExtensions());
response.setConsent(samlResponse.getConsent());
response.setStatus(samlResponse.getStatus());
response.setAssertion(assertions);
return response;
}
/**
* Returns value of an attribute in the PEP extended configuration.
*
* @param pepConfig the PEP extended configuration object.
* @param attrName the attribute name whose value is to be retreived.
* @return value of the attribute.
* @exception <code>SAML2MetaException</code> if there is an error
* retreiving the value.
*/
private static String getAttributeValueFromPEPConfig(
XACMLAuthzDecisionQueryConfigElement pepConfig,String attrName)
throws SAML2MetaException {
String classMethod = "QueryClient:getAttributeValueFromPEPConfig:";
if (debug.messageEnabled()) {
debug.message(classMethod + "attrName : " + attrName);
}
String result = null;
Map attrs = SAML2MetaUtils.getAttributes(pepConfig);
if (attrs != null) {
List value = (List) attrs.get(attrName);
if (value != null && value.size() != 0) {
result = (String) value.get(0);
}
}
if (debug.messageEnabled()) {
debug.message(classMethod + "Attribute value is : " + result);
}
return result;
}
/**
* Returns value of an attribute in the PDP extended configuration.
*
* @param pdpConfig the PDP extended configuration object.
* @param attrName the attribute name whose value is to be retreived.
* @return value of the attribute.
* @exception <code>SAML2MetaException</code> if there is an error
* retreiving the value.
*/
private static String getAttributeValueFromPDPConfig(
XACMLPDPConfigElement pdpConfig,String attrName)
throws SAML2MetaException {
String classMethod = "QueryClient:getAttributeValueFromPDPConfig:";
if (debug.messageEnabled()) {
debug.message(classMethod + "attrName : " + attrName);
}
String result = null;
Map attrs = SAML2MetaUtils.getAttributes(pdpConfig);
if (attrs != null) {
List value = (List) attrs.get(attrName);
if (value != null && value.size() != 0) {
result = (String) value.get(0);
}
}
if (debug.messageEnabled()) {
debug.message(classMethod + "Attribute value is : " + result);
}
return result;
}
/**
* Returns true if the assertion is to be signed.
* The PEP Standard metdata configuration is retreived to
* get the value of the attribute WantAssertionsSigned.
*
* @param realm the entity's realm.
* @param pepEntityID entity identifier of the PEP.
* @return true if the value of the attribute is true.
* @exception <code>SAML2MetaException</code> if there is an error
* retreiving the configuration.
*/
private static boolean wantAssertionSigned(String realm,String pepEntityID)
throws SAML2MetaException {
XACMLAuthzDecisionQueryDescriptorElement
pepDescriptor =
saml2MetaManager.
getPolicyEnforcementPointDescriptor(realm,
pepEntityID);
return pepDescriptor.isWantAssertionsSigned();
}
/**
*
* @param xacmlQuery XACML Query
* @param realm the entity's realm.
* @param pepEntityID entity identifier of PEP.
* @param pdpEntityID entity identifier of PDP.
* @throws <code>SAML2Exception</code> if error in verifying
* the signature.
*/
private static void signAttributeQuery(XACMLAuthzDecisionQuery xacmlQuery,
String realm, String pepEntityID, boolean includeCert) throws
SAML2Exception {
KeyProvider keyProvider = KeyUtil.getKeyProviderInstance();
XACMLAuthzDecisionQueryConfigElement pepConfig =
getPEPConfig(realm,pepEntityID);
String alias =
getAttributeValueFromPEPConfig(pepConfig,
"signingCertAlias");
PrivateKey signingKey = keyProvider.getPrivateKey(alias);
if (signingKey == null) {
throw new SAML2Exception(
SAML2Utils.bundle.getString("missingSigningCertAlias"));
}
X509Certificate signingCert = null;
if (includeCert) {
signingCert = keyProvider.getX509Certificate(alias);
}
if (signingKey != null) {
xacmlQuery.sign(signingKey, signingCert);
}
}
/**
* Verify the signature in <code>Response</code>.
*
* @param pepEntityID entity identifier of PEP.
* @param pdpEntityID entity identifier of PDP.
* @param response <code>Response</code> to be verified
* @return true if signature is valid.
* @throws <code>SAML2Exception</code> if error in verifying
* the signature.
*/
public static boolean verifySignedResponse(String pepEntityID,
String pdpEntityID, Response response) throws SAML2Exception {
String classMethod = "QueryClient:verifySignedResponse: ";
String realm = "/";
XACMLAuthzDecisionQueryConfigElement pepConfig =
getPEPConfig(realm,pepEntityID);
String wantResponseSigned =
getAttributeValueFromPEPConfig(pepConfig,
"wantXACMLAuthzDecisionResponseSigned");
boolean valid;
if (wantResponseSigned != null &&
wantResponseSigned.equalsIgnoreCase("true")) {
XACMLPDPDescriptorElement pdpDescriptor = saml2MetaManager.getPolicyDecisionPointDescriptor(null,
pdpEntityID);
Set<X509Certificate> signingCerts = KeyUtil.getPDPVerificationCerts(pdpDescriptor, pdpEntityID);
if (!signingCerts.isEmpty()) {
valid = response.isSignatureValid(signingCerts);
if (debug.messageEnabled()) {
debug.message(classMethod + "Signature is valid :" + valid);
}
} else {
debug.error(classMethod +
"Incorrect configuration for Signing Certificate.");
throw new SAML2Exception(
SAML2SDKUtils.bundle.getString("metaDataError"));
}
} else {
if (debug.messageEnabled()) {
debug.message(classMethod +
"Response doesn't need to be verified.");
}
valid = true;
}
return valid;
}
}