package com.intel.mtwilson.saml; import java.io.*; import java.security.*; import java.security.cert.CertificateException; import java.util.Collections; import javax.xml.crypto.MarshalException; import javax.xml.crypto.dsig.CanonicalizationMethod; import javax.xml.crypto.dsig.DigestMethod; import javax.xml.crypto.dsig.Reference; import javax.xml.crypto.dsig.SignatureMethod; import javax.xml.crypto.dsig.SignedInfo; import javax.xml.crypto.dsig.Transform; import javax.xml.crypto.dsig.XMLSignature; import javax.xml.crypto.dsig.XMLSignatureException; import javax.xml.crypto.dsig.XMLSignatureFactory; import javax.xml.crypto.dsig.dom.DOMSignContext; import javax.xml.crypto.dsig.keyinfo.KeyInfo; import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory; import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec; import javax.xml.crypto.dsig.spec.TransformParameterSpec; import com.intel.dcsg.cpg.configuration.Configuration; import com.intel.mtwilson.My; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * @author Will Provost (original author) * @author Jonathan Buhacoff * * Copyright 2009 Will Provost. All rights reserved by Capstone Courseware, LLC. * Used with permission. * * http://capcourse.com/Library/OpenSAML */ public class SAMLSignature { private XMLSignatureFactory factory; private KeyStore keyStore; private KeyPair keyPair; private KeyInfo keyInfo; /** * Get a KeyStore object given the keystore filename and password. */ public static KeyStore getKeyStore(InputStream in, String password) throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException { KeyStore result = KeyStore.getInstance(KeyStore.getDefaultType()); result.load(in, password.toCharArray()); return result; } /** * Loads a keystore and builds a stock key-info structure for use by base * classes. */ public SAMLSignature(Configuration configuration) throws ClassNotFoundException, KeyStoreException, NoSuchAlgorithmException, UnrecoverableEntryException, IllegalAccessException, InstantiationException, IOException, CertificateException { SamlConfiguration saml = new SamlConfiguration(configuration); String providerName = saml.getJsr105Provider(); //configuration.getString("jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI"); factory = XMLSignatureFactory.getInstance("DOM", (Provider) Class.forName(providerName).newInstance()); // URL keystore = getClass().getResource(config.getString ("saml.keystore.file")); // System.out.println("keystore url: "+keystore.toString()); // InputStream keystoreInputStream = keystore.openStream(); //File keystoreFile = new File(saml.getSamlKeystoreFile());// new File(configuration.getString("saml.keystore.file")); //ResourceFinder.getFile(config.getString("saml.keystore.file")); File keystoreFile = My.configuration().getSamlKeystoreFile(); // InputStream keystoreInputStream = keystoreResource.getInputStream(); // this obtains it from the database (or whatever resource is provided) // keyStore = KeyStoreUtil.getKeyStore(SAMLSignature.class.getResourceAsStream(config.getString ("keystore")),config.getString ("storepass")); try (FileInputStream keystoreInputStream = new FileInputStream(keystoreFile)) { keyStore = getKeyStore(keystoreInputStream, saml.getSamlKeystorePassword()); /*configuration.getString("saml.keystore.password"*//*,System.getenv("SAMLPASSWORD")*/ } KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(saml.getSamlKeyAlias(), // /*configuration.getString("saml.key.alias"),*/ new KeyStore.PasswordProtection(saml.getSamlKeyPassword().toCharArray())); //configuration.getString("saml.key.password"/*, System.getenv("SAMLPASSWORD")*/).toCharArray())); keyPair = new KeyPair(entry.getCertificate().getPublicKey(), entry.getPrivateKey()); KeyInfoFactory kFactory = factory.getKeyInfoFactory(); keyInfo = kFactory.newKeyInfo(Collections.singletonList(kFactory.newX509Data(Collections.singletonList(entry.getCertificate())))); } /** * Adds an enveloped signature to the given element. Then moves the * signature element so that it is in the correct position according to the * SAML assertion and protocol schema: it must immediately follow any Issuer * and precede everything else. */ public void signSAMLObject(Element target) throws GeneralSecurityException, XMLSignatureException, MarshalException { Reference ref = factory.newReference("#" + target.getAttribute("ID"), factory.newDigestMethod(DigestMethod.SHA1, null), Collections.singletonList(factory.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), null, null); SignedInfo signedInfo = factory.newSignedInfo(factory.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS, (C14NMethodParameterSpec) null), factory.newSignatureMethod(SignatureMethod.RSA_SHA1, null), Collections.singletonList(ref)); XMLSignature signature = factory.newXMLSignature(signedInfo, keyInfo); DOMSignContext signContext = new DOMSignContext(keyPair.getPrivate(), target); signature.sign(signContext); // For the result to be schema-valid, we have to move the signature // element from its place at the end of the child list to live // between Issuer and Subject elements. So, deep breath, and: Node signatureElement = target.getLastChild(); boolean foundIssuer = false; Node elementAfterIssuer = null; NodeList children = target.getChildNodes(); for (int c = 0; c < children.getLength(); ++c) { Node child = children.item(c); if (foundIssuer) { elementAfterIssuer = child; break; } if (child.getNodeType() == Node.ELEMENT_NODE && child.getLocalName().equals("Issuer")) { foundIssuer = true; } } // Place after the Issuer, or as first element if no Issuer: if (!foundIssuer || elementAfterIssuer != null) { target.removeChild(signatureElement); target.insertBefore(signatureElement, foundIssuer ? elementAfterIssuer : target.getFirstChild()); } } }