Skip to content

Commit

Permalink
Dynamically generate a keypair for use in the SAML signing tests
Browse files Browse the repository at this point in the history
  • Loading branch information
coheigea committed Aug 11, 2017
1 parent a22a6b5 commit d8d5fe5
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 19 deletions.
7 changes: 7 additions & 0 deletions fit/core-reference/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,23 @@
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;
Expand Down Expand Up @@ -71,6 +82,13 @@
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;
Expand All @@ -85,6 +103,8 @@
public class SAML2ITCase extends AbstractITCase {

private static SyncopeClient anonymous;
private static Path keystorePath;
private static Path truststorePath;

@BeforeClass
public static void setup() {
Expand All @@ -97,13 +117,17 @@ public static void setup() {
}

@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);
Expand All @@ -123,14 +147,17 @@ public static void importFromIdPMetadata() {
}

@AfterClass
public static void clearIdPs() {
public static void clearIdPs() throws Exception {
if (!SAML2SPDetector.isSAML2SPAvailable()) {
return;
}

for (SAML2IdPTO idp : saml2IdPService.list()) {
saml2IdPService.delete(idp.getKey());
}

Files.delete(keystorePath);
Files.delete(truststorePath);
}

@Test
Expand Down Expand Up @@ -409,16 +436,81 @@ private org.opensaml.saml.saml2.core.Response createResponse(
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());
}

}
14 changes: 1 addition & 13 deletions fit/core-reference/src/test/resources/fediz.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
2 changes: 2 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down

0 comments on commit d8d5fe5

Please sign in to comment.