Skip to content

Commit

Permalink
Improve addSign method. Support DigestMethod. On decrypt method, veri…
Browse files Browse the repository at this point in the history
…fy that there is encrypted data
  • Loading branch information
pitbulk committed Jul 6, 2018
1 parent 1ebbb36 commit 21b6b9e
Show file tree
Hide file tree
Showing 9 changed files with 575 additions and 44 deletions.
13 changes: 10 additions & 3 deletions core/src/main/java/com/onelogin/saml2/authn/SamlResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -1065,20 +1065,27 @@ private NodeList query(String nameQuery, Node context) throws XPathExpressionExc
* @throws SAXException
* @throws ParserConfigurationException
* @throws SettingsException
* @throws ValidationError
*/
private Document decryptAssertion(Document dom) throws XPathExpressionException, ParserConfigurationException, SAXException, IOException, SettingsException {
private Document decryptAssertion(Document dom) throws XPathExpressionException, ParserConfigurationException, SAXException, IOException, SettingsException, ValidationError {
PrivateKey key = settings.getSPkey();

if (key == null) {
throw new SettingsException("No private key available for decrypt, check settings", SettingsException.PRIVATE_KEY_NOT_FOUND);
}

NodeList encryptedDataNodes = Util.query(dom, "/samlp:Response/saml:EncryptedAssertion/xenc:EncryptedData");
if (encryptedDataNodes.getLength() == 0) {
throw new ValidationError("No /samlp:Response/saml:EncryptedAssertion/xenc:EncryptedData element found", ValidationError.MISSING_ENCRYPTED_ELEMENT);
}
Element encryptedData = (Element) encryptedDataNodes.item(0);
Util.decryptElement(encryptedData, key);

// We need to Remove the saml:EncryptedAssertion Node
NodeList AssertionDataNodes = Util.query(dom, "/samlp:Response/saml:EncryptedAssertion/saml:Assertion");
if (encryptedDataNodes.getLength() == 0) {
throw new ValidationError("No /samlp:Response/saml:EncryptedAssertion/saml:Assertion element found", ValidationError.MISSING_ENCRYPTED_ELEMENT);
}
Node assertionNode = AssertionDataNodes.item(0);
assertionNode.getParentNode().getParentNode().replaceChild(assertionNode, assertionNode.getParentNode());

Expand All @@ -1099,7 +1106,7 @@ public String getSAMLResponseXml() {
if (encrypted) {
xml = Util.convertDocumentToString(decryptedDocument);
} else {
xml = samlResponseString;
xml = samlResponseString;
}
return xml;
}
Expand All @@ -1113,7 +1120,7 @@ protected Document getSAMLResponseDocument() {
if (encrypted) {
doc = decryptedDocument;
} else {
doc = samlResponseDocument;
doc = samlResponseDocument;
}
return doc;
}
Expand Down
30 changes: 27 additions & 3 deletions core/src/main/java/com/onelogin/saml2/settings/Metadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.onelogin.saml2.model.Organization;
import com.onelogin.saml2.model.AttributeConsumingService;
import com.onelogin.saml2.model.RequestedAttribute;
import com.onelogin.saml2.util.Constants;
import com.onelogin.saml2.util.Util;

/**
Expand Down Expand Up @@ -377,9 +378,32 @@ public final String getMetadataString() {
*/
public static String signMetadata(String metadata, PrivateKey key, X509Certificate cert, String signAlgorithm) throws XPathExpressionException, XMLSecurityException
{
Document metadataDoc = Util.loadXML(metadata);
String signedMetadata = Util.addSign(metadataDoc, key, cert, signAlgorithm);
LOGGER.debug("Signed metadata --> " + signedMetadata);
return signMetadata(metadata, key, cert, signAlgorithm, Constants.SHA1);
}

/**
* Signs the metadata with the key/cert provided
*
* @param metadata
* SAML Metadata XML
* @param key
* Private Key
* @param cert
* x509 Public certificate
* @param signAlgorithm
* Signature Algorithm
* @param digestAlgorithm
* Digest Algorithm
*
* @return string Signed Metadata
* @throws XMLSecurityException
* @throws XPathExpressionException
*/
public static String signMetadata(String metadata, PrivateKey key, X509Certificate cert, String signAlgorithm, String digestAlgorithm) throws XPathExpressionException, XMLSecurityException
{
Document metadataDoc = Util.loadXML(metadata);
String signedMetadata = Util.addSign(metadataDoc, key, cert, signAlgorithm, digestAlgorithm);
LOGGER.debug("Signed metadata --> " + signedMetadata);
return signedMetadata;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public class Saml2Settings {
private String requestedAuthnContextComparison = "exact";
private boolean wantXMLValidation = true;
private String signatureAlgorithm = Constants.RSA_SHA1;
private String digestAlgorithm = Constants.SHA1;
private boolean rejectUnsolicitedResponsesWithInResponseTo = false;

// Compress
Expand Down Expand Up @@ -318,6 +319,13 @@ public String getSignatureAlgorithm() {
return signatureAlgorithm;
}

/**
* @return the digestAlgorithm setting value
*/
public String getDigestAlgorithm() {
return digestAlgorithm;
}

/**
* @return SP Contact info
*/
Expand Down Expand Up @@ -681,6 +689,16 @@ public void setSignatureAlgorithm(String signatureAlgorithm) {
this.signatureAlgorithm = signatureAlgorithm;
}

/**
* Set the digestAlgorithm setting value
*
* @param digestAlgorithm
* the digestAlgorithm value to be set.
*/
public void setDigestAlgorithm(String digestAlgorithm) {
this.digestAlgorithm = digestAlgorithm;
}

/**
* Controls if unsolicited Responses are rejected if they contain an InResponseTo value.
*
Expand Down Expand Up @@ -951,7 +969,8 @@ public String getSPMetadata() throws CertificateEncodingException {
metadataString,
this.getSPkey(),
this.getSPcert(),
this.getSignatureAlgorithm()
this.getSignatureAlgorithm(),
this.getDigestAlgorithm()
);
} catch (Exception e) {
LOGGER.debug("Error executing signMetadata: " + e.getMessage(), e);
Expand Down
112 changes: 83 additions & 29 deletions core/src/main/java/com/onelogin/saml2/util/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
* A class that contains several auxiliary methods related to the SAML protocol
*/
public final class Util {

/**
* Private property to construct a logger for this class.
*/
Expand All @@ -109,6 +110,11 @@ public final class Util {
/** Indicates if JAXP 1.5 support has been detected. */
private static boolean JAXP_15_SUPPORTED = isJaxp15Supported();

static {
System.setProperty("org.apache.xml.security.ignoreLineBreaks", "true");
org.apache.xml.security.Init.init();
}

private Util() {
//not called
}
Expand Down Expand Up @@ -380,7 +386,6 @@ public static Document parseXML(InputSource inputSource) throws ParserConfigurat
* @return the Document object
*/
public static String convertDocumentToString(Document doc, Boolean c14n) {
org.apache.xml.security.Init.init();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (c14n) {
XMLUtils.outputDOMc14nWithComments(doc, baos);
Expand Down Expand Up @@ -525,8 +530,6 @@ public static X509Certificate loadCert(String certString) throws CertificateExce
* @throws GeneralSecurityException
*/
public static PrivateKey loadPrivateKey(String keyString) throws GeneralSecurityException {
org.apache.xml.security.Init.init();

String extractedKey = formatPrivateKey(keyString, false);
extractedKey = chunkString(extractedKey, 64);
KeyFactory kf = KeyFactory.getInstance("RSA");
Expand Down Expand Up @@ -808,8 +811,6 @@ public static String urlDecoder(String input) {
* @throws SignatureException
*/
public static byte[] sign(String text, PrivateKey key, String signAlgorithm) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
org.apache.xml.security.Init.init();

if (signAlgorithm == null) {
signAlgorithm = Constants.RSA_SHA1;
}
Expand Down Expand Up @@ -964,8 +965,6 @@ public static Boolean validateMetadataSign(Document doc, X509Certificate cert, S
public static Boolean validateSignNode(Node signNode, X509Certificate cert, String fingerprint, String alg) {
Boolean res = false;
try {
org.apache.xml.security.Init.init();

Element sigElement = (Element) signNode;
XMLSignature signature = new XMLSignature(sigElement, "", true);

Expand Down Expand Up @@ -1034,8 +1033,6 @@ public static boolean isAlgorithmWhitelisted(String alg) {
*/
public static void decryptElement(Element encryptedDataElement, PrivateKey inputKey) {
try {
org.apache.xml.security.Init.init();

XMLCipher xmlCipher = XMLCipher.getInstance();
xmlCipher.init(XMLCipher.DECRYPT_MODE, null);

Expand Down Expand Up @@ -1111,15 +1108,36 @@ public static Document copyDocument(Document source) throws ParserConfigurationE
* The public certificate
* @param signAlgorithm
* Signature Algorithm
*
*
* @return the signed document in string format
*
*
* @throws XMLSecurityException
* @throws XPathExpressionException
*/
public static String addSign(Document document, PrivateKey key, X509Certificate certificate, String signAlgorithm) throws XMLSecurityException, XPathExpressionException {
org.apache.xml.security.Init.init();
return addSign(document, key, certificate, signAlgorithm, Constants.SHA1);
}

/**
* Signs the Document using the specified signature algorithm with the private key and the public certificate.
*
* @param document
* The document to be signed
* @param key
* The private key
* @param certificate
* The public certificate
* @param signAlgorithm
* Signature Algorithm
* @param digestAlgorithm
* Digest Algorithm
*
* @return the signed document in string format
*
* @throws XMLSecurityException
* @throws XPathExpressionException
*/
public static String addSign(Document document, PrivateKey key, X509Certificate certificate, String signAlgorithm, String digestAlgorithm) throws XMLSecurityException, XPathExpressionException {
// Check arguments.
if (document == null) {
throw new IllegalArgumentException("Provided document was null");
Expand All @@ -1132,18 +1150,21 @@ public static String addSign(Document document, PrivateKey key, X509Certificate
if (key == null) {
throw new IllegalArgumentException("Provided key was null");
}

if (certificate == null) {
throw new IllegalArgumentException("Provided certificate was null");
}

if (signAlgorithm == null || signAlgorithm.isEmpty()) {
signAlgorithm = Constants.RSA_SHA1;
}
if (digestAlgorithm == null || digestAlgorithm.isEmpty()) {
digestAlgorithm = Constants.SHA1;
}

// document.normalizeDocument();
document.normalizeDocument();

String c14nMethod = Constants.C14NEXC_WC;
String c14nMethod = Constants.C14NEXC;

// Signature object
XMLSignature sig = new XMLSignature(document, null, signAlgorithm, c14nMethod);
Expand All @@ -1155,30 +1176,42 @@ public static String addSign(Document document, PrivateKey key, X509Certificate

// If Issuer, locate Signature after Issuer, Otherwise as first child.
NodeList issuerNodes = Util.query(document, "//saml:Issuer", null);
Element elemToSign = null;
if (issuerNodes.getLength() > 0) {
Node issuer = issuerNodes.item(0);
root.insertBefore(sig.getElement(), issuer.getNextSibling());
elemToSign = (Element) issuer.getParentNode();
} else {
root.insertBefore(sig.getElement(), root.getFirstChild());
NodeList entitiesDescriptorNodes = Util.query(document, "//md:EntitiesDescriptor", null);
if (entitiesDescriptorNodes.getLength() > 0) {
elemToSign = (Element)entitiesDescriptorNodes.item(0);
} else {
NodeList entityDescriptorNodes = Util.query(document, "//md:EntityDescriptor", null);
if (entityDescriptorNodes.getLength() > 0) {
elemToSign = (Element)entityDescriptorNodes.item(0);
} else {
elemToSign = root;
}
}
root.insertBefore(sig.getElement(), elemToSign.getFirstChild());
}

String id = root.getAttribute("ID");
String id = elemToSign.getAttribute("ID");

String reference = id;
if (!id.isEmpty()) {
root.setIdAttributeNS(null, "ID", true);
elemToSign.setIdAttributeNS(null, "ID", true);
reference = "#" + id;
}

// Create the transform for the document
Transforms transforms = new Transforms(document);
transforms.addTransform(Constants.ENVSIG);
//transforms.addTransform(Transforms.TRANSFORM_C14N_OMIT_COMMENTS);
transforms.addTransform(c14nMethod);
sig.addDocument(reference, transforms, Constants.SHA1);
sig.addDocument(reference, transforms, digestAlgorithm);

// Add the certification info
sig.addKeyInfo(certificate);
sig.addKeyInfo(certificate);

// Sign the document
sig.sign(key);
Expand All @@ -1197,14 +1230,16 @@ public static String addSign(Document document, PrivateKey key, X509Certificate
* The public certificate
* @param signAlgorithm
* Signature Algorithm
*
* @param digestAlgorithm
* Digest Algorithm
*
* @return the signed document in string format
*
* @throws ParserConfigurationException
* @throws XMLSecurityException
* @throws XPathExpressionException
*/
public static String addSign(Node node, PrivateKey key, X509Certificate certificate, String signAlgorithm) throws ParserConfigurationException, XPathExpressionException, XMLSecurityException {
public static String addSign(Node node, PrivateKey key, X509Certificate certificate, String signAlgorithm, String digestAlgorithm) throws ParserConfigurationException, XPathExpressionException, XMLSecurityException {
// Check arguments.
if (node == null) {
throw new IllegalArgumentException("Provided node was null");
Expand All @@ -1216,9 +1251,31 @@ public static String addSign(Node node, PrivateKey key, X509Certificate certific
Node newNode = doc.importNode(node, true);
doc.appendChild(newNode);

return addSign(doc, key, certificate, signAlgorithm);
}

return addSign(doc, key, certificate, signAlgorithm, digestAlgorithm);
}

/**
* Signs a Node using the specified signature algorithm with the private key and the public certificate.
*
* @param node
* The Node to be signed
* @param key
* The private key
* @param certificate
* The public certificate
* @param signAlgorithm
* Signature Algorithm
*
* @return the signed document in string format
*
* @throws ParserConfigurationException
* @throws XMLSecurityException
* @throws XPathExpressionException
*/
public static String addSign(Node node, PrivateKey key, X509Certificate certificate, String signAlgorithm) throws ParserConfigurationException, XPathExpressionException, XMLSecurityException {
return addSign(node, key, certificate, signAlgorithm, Constants.SHA1);
}

/**
* Validates signed binary data (Used to validate GET Signature).
*
Expand All @@ -1241,8 +1298,6 @@ public static String addSign(Node node, PrivateKey key, X509Certificate certific
public static Boolean validateBinarySignature(String signedQuery, byte[] signature, X509Certificate cert, String signAlg) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException {
Boolean valid = false;
try {
org.apache.xml.security.Init.init();

String convertedSigAlg = signatureAlgConversion(signAlg);

Signature sig = Signature.getInstance(convertedSigAlg); //, provider);
Expand Down Expand Up @@ -1278,7 +1333,6 @@ public static Boolean validateBinarySignature(String signedQuery, byte[] signatu
public static Boolean validateBinarySignature(String signedQuery, byte[] signature, List<X509Certificate> certList, String signAlg) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException {
Boolean valid = false;

org.apache.xml.security.Init.init();
String convertedSigAlg = signatureAlgConversion(signAlg);
Signature sig = Signature.getInstance(convertedSigAlg); //, provider);

Expand Down
Loading

0 comments on commit 21b6b9e

Please sign in to comment.