-
-
Save sharif2008/a14921405cac2aed5ebb5cf39303d343 to your computer and use it in GitHub Desktop.
Revisions
-
rponte revised this gist
Jul 30, 2019 . 1 changed file with 5 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -19,20 +19,22 @@ public class XmlSignerTest { @Test public void shouldSignXmlUsingAJavaKeyStore() throws Exception { // scenario InputStream xml = XmlSigner.class.getResourceAsStream("/xml-document-sample.xml"); InputStream jks = XmlSigner.class.getResourceAsStream("/my-private-key.jks"); String alias = "root"; String password = "secret"; // action SignedXml signedXml = new XmlSigner() .withXml( "\n<request> " + "\n <another-tag name='foo' /> " + "\n</request> ") // it supports InputStream as well .withKeyStore(jks, alias, password) .sign(); // validation String content = signedXml.getContent(); logger.info("\n" + content); // just prints the result -
rponte revised this gist
Oct 26, 2018 . 4 changed files with 15 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -2,6 +2,9 @@ import java.util.Base64; /** * Represents a signed XML */ public class SignedXml { private String content; This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -49,6 +49,9 @@ import org.w3c.dom.Document; import org.xml.sax.SAXException; /** * Responsible for signing a specific XML using private key certificate */ public class XmlSigner { private static final String C14NEXC = "http://www.w3.org/2001/10/xml-exc-c14n#"; @@ -57,6 +60,9 @@ public class XmlSigner { private InputStream sourceXml; /** * Signs a specific XML using a private key via Java Key Store format * * More information: * https://gist.github.com/rponte/4039958 * https://github.com/SUNET/eduid-mm-service/tree/master/src/main/java/se/gov/minameddelanden/common * https://stackoverflow.com/questions/5330049/java-equivalent-of-c-sharp-xml-signing-method This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -10,6 +10,9 @@ import org.apache.commons.io.IOUtils; /** * How to use XmlSigner */ public class XmlSignerTest { private static final Logger logger = LoggerFactory.getLogger(XmlSignerTest.class); This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -7,6 +7,9 @@ import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; /** * Holds information about the Java Key Store */ public class keyStoreInfo { private static final String KEY_STORE_TYPE = "JKS"; -
rponte revised this gist
Oct 26, 2018 . 1 changed file with 2 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -22,12 +22,11 @@ public void shouldSignXmlUsingAJavaKeyStore() throws Exception { String alias = "root"; String password = "secret"; SignedXml signedXml = new XmlSigner() .withXml( "\n<request> " + "\n <another-tag name='foo' /> " + "\n</request> ") // it supports InputStream too .withKeyStore(jks, alias, password) .sign(); -
rponte revised this gist
Oct 26, 2018 . 1 changed file with 10 additions and 8 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -25,17 +25,19 @@ public void shouldSignXmlUsingAJavaKeyStore() throws Exception { String parsedXml = IOUtils.toString(xml, StandardCharsets.UTF_8); SignedXml signedXml = new XmlSigner() .withXml( "\n<request> " + "\n <another-tag name=\"foo\"/> " + "\n</request> ") .withKeyStore(jks, alias, password) .sign(); String content = signedXml.getContent(); logger.info("\n" + content); // just prints the result assertThat(content) .contains("<X509Certificate>") .contains("</X509Data>") .contains("</Signature>") ; } } -
rponte renamed this gist
Oct 26, 2018 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
rponte revised this gist
Oct 26, 2018 . 1 changed file with 41 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,41 @@ package br.com.mdias.rponte.signature; import static org.assertj.core.api.Assertions.assertThat; import java.io.InputStream; import org.junit.Rule; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.commons.io.IOUtils; public class XmlSignerTest { private static final Logger logger = LoggerFactory.getLogger(XmlSignerTest.class); @Test public void shouldSignXmlUsingAJavaKeyStore() throws Exception { InputStream xml = XmlSigner.class.getResourceAsStream("/request-info.xml"); InputStream jks = XmlSigner.class.getResourceAsStream("/my-private-key.jks"); String alias = "root"; String password = "secret"; String parsedXml = IOUtils.toString(xml, StandardCharsets.UTF_8); SignedXml signedXml = new XmlSigner() .withXml(parsedXml) .withKeyStore(jks, alias, password) .sign(); String content = signedXml.getContent(); logger.info("\n" + content); // just prints the result assertThat(content) .contains("<X509Certificate>") .contains("</X509Data>") .contains("</Signature>") ; } } -
rponte revised this gist
Oct 26, 2018 . 1 changed file with 8 additions and 8 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -68,7 +68,7 @@ public SignedXml sign() throws NoSuchAlgorithmException, InvalidKeyException, Ke char[] password = keyStoreInfo.getPassword().toCharArray(); // Create a DOM XMLSignatureFactory that will be used to // generate the enveloped signature. XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); // Create a Reference to the enveloped document (in this case, @@ -113,18 +113,18 @@ public SignedXml sign() throws NoSuchAlgorithmException, InvalidKeyException, Ke DOMSignContext dsc = new DOMSignContext(key, doc.getDocumentElement()); // Adds <Signature> tag before a specific tag inside XML - with or without namespace /* Node assertionTag = doc.getElementsByTagName("saml2:Assertion").item(0); Node afterTag = doc.getElementsByTagName("saml2:Subject").item(0); DOMSignContext dsc = new DOMSignContext(key, assertionTag, afterTag); dsc.setDefaultNamespacePrefix("ds"); */ // Create the XMLSignature, but don't sign it yet. XMLSignature signature = fac.newXMLSignature(si, keyInfo); signature.sign(dsc); // Marshal, generate, and sign the enveloped signature. ByteArrayOutputStream output = new ByteArrayOutputStream(); TransformerFactory.newInstance() .newTransformer() .transform(new DOMSource(doc), new StreamResult(output)); -
rponte created this gist
Oct 26, 2018 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,21 @@ package br.com.mdias.rponte.signature; import java.util.Base64; public class SignedXml { private String content; public SignedXml(String content) { this.content = content; } public String getContent() { return content; } public String toBase64() { String base64Xml = Base64.getEncoder().encodeToString(content.getBytes()); return base64Xml; } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,163 @@ package br.com.rponte.signature; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.security.UnrecoverableEntryException; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Collections; import java.util.List; import javax.xml.crypto.MarshalException; import javax.xml.crypto.XMLStructure; 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.keyinfo.X509Data; import javax.xml.crypto.dsig.keyinfo.X509IssuerSerial; import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec; import javax.xml.crypto.dsig.spec.TransformParameterSpec; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.apache.commons.io.IOUtils; import org.w3c.dom.Document; import org.xml.sax.SAXException; public class XmlSigner { private static final String C14NEXC = "http://www.w3.org/2001/10/xml-exc-c14n#"; private keyStoreInfo keyStoreInfo; private InputStream sourceXml; /** * https://gist.github.com/rponte/4039958 * https://github.com/SUNET/eduid-mm-service/tree/master/src/main/java/se/gov/minameddelanden/common * https://stackoverflow.com/questions/5330049/java-equivalent-of-c-sharp-xml-signing-method */ public SignedXml sign() throws NoSuchAlgorithmException, InvalidKeyException, KeyStoreException, SignatureException, IOException, InvalidAlgorithmParameterException, ParserConfigurationException, SAXException, MarshalException, XMLSignatureException, TransformerConfigurationException, TransformerException, TransformerFactoryConfigurationError, UnrecoverableEntryException { KeyStore keyStore = keyStoreInfo.getKeyStore(); String alias = keyStoreInfo.getAlias(); char[] password = keyStoreInfo.getPassword().toCharArray(); // Create a DOM XMLSignatureFactory that will be used to // generate the enveloped signature. XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); // Create a Reference to the enveloped document (in this case, // you are signing the whole document, so a URI of "" signifies // that, and also specify the SHA1 digest algorithm and // the ENVELOPED Transform. Transform envelopedTransform = fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null); Transform c14NEXCTransform = fac.newTransform(C14NEXC, (TransformParameterSpec) null); List<Transform> transforms = Arrays.asList(envelopedTransform, c14NEXCTransform); DigestMethod digestMethod = fac.newDigestMethod(DigestMethod.SHA1, null); Reference ref = fac.newReference("", digestMethod, transforms, null, null); // Create the SignedInfo. CanonicalizationMethod canonicalizationMethod = fac.newCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE, (C14NMethodParameterSpec) null); SignatureMethod signatureMethod = fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null); SignedInfo si = fac.newSignedInfo(canonicalizationMethod, signatureMethod, Collections.singletonList(ref)); // Create the KeyInfo containing the X509Data. KeyInfoFactory keyInfoFactory = fac.getKeyInfoFactory(); X509Certificate certificate = (X509Certificate) keyStore.getCertificate(alias); X509Data newX509Data = keyInfoFactory.newX509Data(Arrays.asList(certificate)); X509IssuerSerial issuer = keyInfoFactory.newX509IssuerSerial(certificate.getIssuerX500Principal().getName(), certificate.getSerialNumber()); List<XMLStructure> data = Arrays.asList(newX509Data, issuer); KeyInfo keyInfo = keyInfoFactory.newKeyInfo(data); // Converts XML to Document DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); DocumentBuilder builder = dbf.newDocumentBuilder(); Document doc = builder.parse(sourceXml); // Create a DOMSignContext and specify the RSA PrivateKey and // location of the resulting XMLSignature's parent element. Key key = keyStore.getKey(alias, password); if (key == null) { throw new XmlSigningException("Private Key not found for alias '" + alias + "'"); } DOMSignContext dsc = new DOMSignContext(key, doc.getDocumentElement()); // Adds <Signature> tag before a specific tag inside XML - with or without namespace /* Node assertionTag = doc.getElementsByTagName("saml2:Assertion").item(0); Node afterTag = doc.getElementsByTagName("saml2:Subject").item(0); DOMSignContext dsc = new DOMSignContext(key, assertionTag, afterTag); dsc.setDefaultNamespacePrefix("ds"); */ // Create the XMLSignature, but don't sign it yet. XMLSignature signature = fac.newXMLSignature(si, keyInfo); signature.sign(dsc); // Marshal, generate, and sign the enveloped signature. ByteArrayOutputStream output = new ByteArrayOutputStream(); TransformerFactory.newInstance() .newTransformer() .transform(new DOMSource(doc), new StreamResult(output)); String rawSignedXml = new String(output.toByteArray()); SignedXml xml = new SignedXml(rawSignedXml); return xml; } public XmlSigner withKeyStore(InputStream keyStore, String alias, String password) { if (keyStore == null) throw new XmlSigningException("KeyStore without private key"); keyStoreInfo ksi = new keyStoreInfo(alias, password); ksi.load(keyStore); this.keyStoreInfo = ksi; return this; } public XmlSigner withXml(InputStream sourceXml) { if (sourceXml == null) throw new XmlSigningException("XML can not be null"); this.sourceXml = sourceXml; return this; } public XmlSigner withXml(String sourceXml) { InputStream input = IOUtils.toInputStream(sourceXml, StandardCharsets.UTF_8); return withXml(input); } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,15 @@ package br.com.mdias.rponte.signature; public class XmlSigningException extends RuntimeException { private static final long serialVersionUID = 1L; public XmlSigningException(String message) { super(message); } public XmlSigningException(String message, Throwable cause) { super(message, cause); } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,46 @@ package br.com.rponte.signature; import java.io.IOException; import java.io.InputStream; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; public class keyStoreInfo { private static final String KEY_STORE_TYPE = "JKS"; private String alias; private String password; private KeyStore keyStore; public keyStoreInfo(String alias, String password) { this.alias = alias; this.password = password; } /** * Loads KeyStore from the given Private Key */ public void load(InputStream privateKey) { try { this.keyStore = KeyStore.getInstance(KEY_STORE_TYPE); this.keyStore.load(privateKey, password.toCharArray()); } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) { e.printStackTrace(); throw new XmlSigningException("Error loading KeyStore", e); } } public String getAlias() { return alias; } public String getPassword() { return password; } public KeyStore getKeyStore() { return keyStore; } }