Dynamically generate a keypair for use in the SAML signing tests
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/d8d5fe5e Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/d8d5fe5e Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/d8d5fe5e Branch: refs/heads/master Commit: d8d5fe5ee8c7e887f5c2fda8362aa9a0296635c9 Parents: a22a6b5 Author: Colm O hEigeartaigh <cohei...@apache.org> Authored: Fri Aug 11 12:38:06 2017 +0100 Committer: Colm O hEigeartaigh <cohei...@apache.org> Committed: Fri Aug 11 13:15:07 2017 +0100 ---------------------------------------------------------------------- fit/core-reference/pom.xml | 7 ++ .../apache/syncope/fit/core/SAML2ITCase.java | 104 +++++++++++++++++-- fit/core-reference/src/test/resources/fediz.xml | 14 +-- pom.xml | 2 + 4 files changed, 108 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/syncope/blob/d8d5fe5e/fit/core-reference/pom.xml ---------------------------------------------------------------------- diff --git a/fit/core-reference/pom.xml b/fit/core-reference/pom.xml index 5762a33..45a6214 100644 --- a/fit/core-reference/pom.xml +++ b/fit/core-reference/pom.xml @@ -176,6 +176,13 @@ under the License. <artifactId>junit</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcpkix-jdk15on</artifactId> + <version>${bouncycastle.version}</version> + <scope>test</scope> + </dependency> + </dependencies> <build> http://git-wip-us.apache.org/repos/asf/syncope/blob/d8d5fe5e/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java index 93608c2..9ee5653 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SAML2ITCase.java @@ -26,12 +26,23 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.io.File; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; +import java.math.BigInteger; import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.KeyPair; +import java.security.KeyPairGenerator; import java.security.KeyStore; +import java.security.SecureRandom; +import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.Collections; +import java.util.Date; import java.util.Optional; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -71,6 +82,13 @@ import org.apache.wss4j.common.util.Loader; import org.apache.wss4j.dom.WSConstants; import org.apache.wss4j.dom.engine.WSSConfig; import org.apache.xml.security.signature.XMLSignature; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.style.RFC4519Style; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.joda.time.DateTime; import org.junit.AfterClass; import org.junit.Assume; @@ -85,6 +103,8 @@ import org.w3c.dom.Element; public class SAML2ITCase extends AbstractITCase { private static SyncopeClient anonymous; + private static Path keystorePath; + private static Path truststorePath; @BeforeClass public static void setup() { @@ -97,13 +117,17 @@ public class SAML2ITCase extends AbstractITCase { } @BeforeClass - public static void importFromIdPMetadata() { + public static void importFromIdPMetadata() throws Exception { if (!SAML2SPDetector.isSAML2SPAvailable()) { return; } assertTrue(saml2IdPService.list().isEmpty()); + createKeystores(); + + updateMetadataWithCert(); + WebClient.client(saml2IdPService). accept(MediaType.APPLICATION_XML_TYPE). type(MediaType.APPLICATION_XML_TYPE); @@ -123,7 +147,7 @@ public class SAML2ITCase extends AbstractITCase { } @AfterClass - public static void clearIdPs() { + public static void clearIdPs() throws Exception { if (!SAML2SPDetector.isSAML2SPAvailable()) { return; } @@ -131,6 +155,9 @@ public class SAML2ITCase extends AbstractITCase { for (SAML2IdPTO idp : saml2IdPService.list()) { saml2IdPService.delete(idp.getKey()); } + + Files.delete(keystorePath); + Files.delete(truststorePath); } @Test @@ -409,16 +436,81 @@ public class SAML2ITCase extends AbstractITCase { if (signAssertion) { Crypto issuerCrypto = new Merlin(); KeyStore keyStore = KeyStore.getInstance("JKS"); - ClassLoader loader = Loader.getClassLoader(getClass()); - InputStream input = Merlin.loadInputStream(loader, "keystore"); - keyStore.load(input, "changeit".toCharArray()); + InputStream input = Files.newInputStream(keystorePath); + keyStore.load(input, "security".toCharArray()); ((Merlin) issuerCrypto).setKeyStore(keyStore); - assertion.signAssertion("sp", "changeit", issuerCrypto, false); + assertion.signAssertion("subject", "security", issuerCrypto, false); } response.getAssertions().add(assertion.getSaml2()); return response; } + + private static void createKeystores() throws Exception { + // Create KeyPair + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(1024, new SecureRandom()); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + + Date currentDate = new Date(); + Date expiryDate = new Date(currentDate.getTime() + 365L * 24L * 60L * 60L * 1000L); + + // Create X509Certificate + String issuerName = "CN=Issuer"; + String subjectName = "CN=Subject"; + BigInteger serial = new BigInteger("123456"); + X509v3CertificateBuilder certBuilder = + new X509v3CertificateBuilder(new X500Name(RFC4519Style.INSTANCE, issuerName), serial, currentDate, expiryDate, + new X500Name(RFC4519Style.INSTANCE, subjectName), + SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded())); + ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256WithRSAEncryption").build(keyPair.getPrivate()); + X509Certificate certificate = new JcaX509CertificateConverter().getCertificate(certBuilder.build(contentSigner)); + + // Store Private Key + Certificate in Keystore + KeyStore keystore = KeyStore.getInstance("JKS"); + keystore.load(null, "security".toCharArray()); + keystore.setKeyEntry("subject", keyPair.getPrivate(), "security".toCharArray(), new Certificate[] {certificate}); + + File keystoreFile = File.createTempFile("samlkeystore", ".jks"); + try (OutputStream output = Files.newOutputStream(keystoreFile.toPath())) { + keystore.store(output, "security".toCharArray()); + } + keystorePath = keystoreFile.toPath(); + + // Now store the Certificate in the truststore + KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + trustStore.load(null, "security".toCharArray()); + + trustStore.setCertificateEntry("subject", certificate); + + File truststoreFile = File.createTempFile("samltruststore", ".jks"); + try (OutputStream output = Files.newOutputStream(truststoreFile.toPath())) { + trustStore.store(output, "security".toCharArray()); + } + truststorePath = truststoreFile.toPath(); + } + + private static void updateMetadataWithCert() throws Exception { + // Get encoded truststore cert + KeyStore keyStore = KeyStore.getInstance("JKS"); + InputStream input = Files.newInputStream(truststorePath); + keyStore.load(input, "security".toCharArray()); + X509Certificate cert = (X509Certificate)keyStore.getCertificate("subject"); + String certEncoded = java.util.Base64.getMimeEncoder().encodeToString(cert.getEncoded()); + + // Replace the "cert-placeholder" string in the metadata with the actual cert + String basedir = System.getProperty("basedir"); + if (basedir == null) { + basedir = new File(".").getCanonicalPath(); + } + Path path = FileSystems.getDefault().getPath(basedir, "/src/test/resources/fediz.xml"); + String content = new String(Files.readAllBytes(path), StandardCharsets.UTF_8); + content = content.replaceAll("cert-placeholder", certEncoded); + + Path path2 = FileSystems.getDefault().getPath(basedir, "/target/test-classes/fediz.xml"); + Files.write(path2, content.getBytes()); + } + } http://git-wip-us.apache.org/repos/asf/syncope/blob/d8d5fe5e/fit/core-reference/src/test/resources/fediz.xml ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/test/resources/fediz.xml b/fit/core-reference/src/test/resources/fediz.xml index cbc8faa..b8cbda0 100644 --- a/fit/core-reference/src/test/resources/fediz.xml +++ b/fit/core-reference/src/test/resources/fediz.xml @@ -23,19 +23,7 @@ under the License. <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:X509Data> <ds:X509Certificate> -MIICwTCCAamgAwIBAgIEINqJ9TANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDEwZSRUFMTUEwHhcN -MTUwNjEwMTU0NDE3WhcNMjUwNDE4MTU0NDE3WjARMQ8wDQYDVQQDEwZSRUFMTUEwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCJDSXn2lDR+JM+AsJarFG3/XGH7K+9AfAbQIz2IgB9MCpO -KVWTUPCvuo1I+Fp5nEGreuHYLEwgIiam3o+C9tvpLgtDDaDkmXjDzkWpk8z6+im72HZ/ODF93Rqw -jIiY5ZCzgDumFyPzdKiGwChThamidy+rd6oheSoi6qRVSMMcnwiEUmvkfFvV3izXRqeT5nGQwsin -y9mCEiGx8jkfxP++H0RQjVjhOwzfQ7epsR7dTQNf2ZhkBR3o6wKV9QnF2IBWHZpA9EK58rWU9H6j -G7b631rYvwsbOUF9HcZ8DI2BFh+4p18jDN/fnjNGSLr9rYOExpsIiF1cHBK7Tr7WwCmDAgMBAAGj -ITAfMB0GA1UdDgQWBBRHy0qYoLm9jx/1L6r61NznHKun2jANBgkqhkiG9w0BAQsFAAOCAQEAR9rU -5Sp1FsOErdvKNFqeaKl0oq6Fuz7BWcGm2kK6+1ZbWE8IOv6Vh+BlLuOe5hF7aLUbm8UIjhKsmg0M -Ey5MBwkBZktT1qhQteMuiKgYR7CxayCxO0f125RYvvwntJa5rI7bUrzOqX29VQD1qQ/Tb+08fULT -L7oURP+g88Ff99dn3IpO4VZxZdsbl4+KZRtqQvPAdXNYjOajJtPzS489+/DtfWJ6wPm/7YZ4did4 -1fYcrdwyEZ15L0/5i931z7sztNickm5WhO40qEVDKN6KrlV2Eyea0+933v2Pwe4resTlko9G2T5h -dEaSbvht2Q/JOMMmT91daeto2oS8HTKhTA== +cert-placeholder </ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> http://git-wip-us.apache.org/repos/asf/syncope/blob/d8d5fe5e/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index fdd22f2..b3eb5e5 100644 --- a/pom.xml +++ b/pom.xml @@ -356,6 +356,8 @@ under the License. <properties> <syncope.version>${project.version}</syncope.version> + <bouncycastle.version>1.57</bouncycastle.version> + <connid.version>1.4.3.0</connid.version> <connid.soap.version>1.4.2-SNAPSHOT</connid.soap.version> <connid.rest.version>1.0.1</connid.rest.version>