You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by co...@apache.org on 2017/08/11 12:39:52 UTC

[1/5] syncope git commit: SYNCOPE-1194 - Sign the SAML SSO Service Provider Metadata

Repository: syncope
Updated Branches:
  refs/heads/2_0_X 5160df7ba -> 6b3ace024


SYNCOPE-1194 - Sign the SAML SSO Service Provider Metadata


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/919584f3
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/919584f3
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/919584f3

Branch: refs/heads/2_0_X
Commit: 919584f3f780a54b3447dd4f397a29eea438af94
Parents: 5160df7
Author: Colm O hEigeartaigh <co...@apache.org>
Authored: Fri Aug 11 11:59:08 2017 +0100
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Fri Aug 11 13:15:33 2017 +0100

----------------------------------------------------------------------
 .../apache/syncope/core/logic/SAML2SPLogic.java   |  1 +
 .../core/logic/saml2/SAML2ReaderWriter.java       |  3 +--
 .../org/apache/syncope/fit/core/SAML2ITCase.java  | 18 ++++++++++++++++++
 3 files changed, 20 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/919584f3/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
index 87b7eb6..31ef8c4 100644
--- a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
+++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
@@ -200,6 +200,7 @@ public class SAML2SPLogic extends AbstractSAML2Logic<AbstractBaseBean> {
             }
 
             spEntityDescriptor.getRoleDescriptors().add(spSSODescriptor);
+            saml2rw.sign(spEntityDescriptor);
 
             saml2rw.write(new OutputStreamWriter(os), spEntityDescriptor, true);
         } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/919584f3/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
index 62e90e7..22b0fd1 100644
--- a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
+++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
@@ -151,14 +151,13 @@ public class SAML2ReaderWriter {
         return responseObject;
     }
 
-    public void sign(final RequestAbstractType request) throws SecurityException {
+    public void sign(final SignableSAMLObject signableObject) throws SecurityException {
         org.opensaml.xmlsec.signature.Signature signature = OpenSAMLUtil.buildSignature();
         signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
         signature.setSignatureAlgorithm(sigAlgo);
         signature.setSigningCredential(loader.getCredential());
         signature.setKeyInfo(keyInfoGenerator.generate(loader.getCredential()));
 
-        SignableSAMLObject signableObject = (SignableSAMLObject) request;
         signableObject.setSignature(signature);
         signableObject.releaseDOM();
         signableObject.releaseChildrenDOM(true);

http://git-wip-us.apache.org/repos/asf/syncope/blob/919584f3/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 6967e73..e8a5add 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
@@ -30,9 +30,12 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
 import java.security.KeyStore;
+import java.security.cert.X509Certificate;
 import java.util.Collections;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import javax.xml.namespace.QName;
+
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.collections4.IterableUtils;
 import org.apache.commons.collections4.Predicate;
@@ -68,6 +71,7 @@ import org.apache.wss4j.common.util.DOM2Writer;
 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.joda.time.DateTime;
 import org.junit.AfterClass;
 import org.junit.Assume;
@@ -75,6 +79,7 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 import org.opensaml.saml.common.xml.SAMLConstants;
 import org.opensaml.saml.saml2.core.Status;
+import org.opensaml.xmlsec.signature.support.SignatureConstants;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
@@ -143,6 +148,19 @@ public class SAML2ITCase extends AbstractITCase {
                     new InputStreamReader((InputStream) response.getEntity(), StandardCharsets.UTF_8));
             assertEquals("EntityDescriptor", responseDoc.getDocumentElement().getLocalName());
             assertEquals("urn:oasis:names:tc:SAML:2.0:metadata", responseDoc.getDocumentElement().getNamespaceURI());
+
+            // Get the signature
+            QName signatureQName = new QName(SignatureConstants.XMLSIG_NS, "Signature");
+            Element signatureElement =
+                DOMUtils.getFirstChildWithName(responseDoc.getDocumentElement(), signatureQName);
+            assertNotNull(signatureElement);
+
+            // Validate the signature
+            XMLSignature signature = new XMLSignature(signatureElement, null);
+            KeyStore keystore = KeyStore.getInstance("JKS");
+            keystore.load(Loader.getResourceAsStream("keystore"), "changeit".toCharArray());
+            assertTrue(signature.checkSignatureValue((X509Certificate)keystore.getCertificate("sp")));
+
         } catch (Exception e) {
             LOG.error("During SAML 2.0 SP metadata parsing", e);
             fail(e.getMessage());


[5/5] syncope git commit: SYNCOPE-1195 - Remove copy of OpenSAMLUtil when WSS4J 2.1.11 is out

Posted by co...@apache.org.
SYNCOPE-1195 - Remove copy of OpenSAMLUtil when WSS4J 2.1.11 is out


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/6b3ace02
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/6b3ace02
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/6b3ace02

Branch: refs/heads/2_0_X
Commit: 6b3ace024498e4d86bff1e12c782e6c55c036511
Parents: c8748ba
Author: Colm O hEigeartaigh <co...@apache.org>
Authored: Fri Aug 11 13:39:21 2017 +0100
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Fri Aug 11 13:39:21 2017 +0100

----------------------------------------------------------------------
 .../syncope/core/logic/saml2/OpenSAMLUtil.java  | 141 +++++++++++++++++++
 .../core/logic/saml2/SAML2ReaderWriter.java     |   5 +-
 2 files changed, 143 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/6b3ace02/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/OpenSAMLUtil.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/OpenSAMLUtil.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/OpenSAMLUtil.java
new file mode 100644
index 0000000..ff197d4
--- /dev/null
+++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/OpenSAMLUtil.java
@@ -0,0 +1,141 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.syncope.core.logic.saml2;
+
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.opensaml.core.xml.XMLObject;
+import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
+import org.opensaml.core.xml.io.Marshaller;
+import org.opensaml.core.xml.io.MarshallerFactory;
+import org.opensaml.core.xml.io.MarshallingException;
+import org.opensaml.saml.common.SignableSAMLObject;
+import org.opensaml.xmlsec.signature.Signature;
+import org.opensaml.xmlsec.signature.support.SignatureException;
+import org.opensaml.xmlsec.signature.support.Signer;
+import org.opensaml.xmlsec.signature.support.SignerProvider;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+
+/**
+ * Class OpenSAMLUtil provides static helper methods for the OpenSaml library.
+ * TODO Remove once we pick up WSS4J 2.1.11 - See https://issues.apache.org/jira/browse/WSS-613
+ */
+final class OpenSAMLUtil {
+
+    private OpenSAMLUtil() {
+        // Complete
+    }
+
+    /**
+     * Convert a SAML Assertion from a XMLObject to a DOM Element
+     *
+     * @param xmlObject of type XMLObject
+     * @param doc  of type Document
+     * @param signObject whether to sign the XMLObject during marshalling
+     * @return Element
+     * @throws WSSecurityException
+     */
+    public static Element toDom(
+        final XMLObject xmlObject,
+        final Document doc,
+        final boolean signObject
+    ) throws WSSecurityException {
+        MarshallerFactory marshallerFactory = XMLObjectProviderRegistrySupport.getMarshallerFactory();
+        Marshaller marshaller = marshallerFactory.getMarshaller(xmlObject);
+        Element element = null;
+        DocumentFragment frag = doc == null ? null : doc.createDocumentFragment();
+        try {
+            if (frag != null) {
+                while (doc.getFirstChild() != null) {
+                    frag.appendChild(doc.removeChild(doc.getFirstChild()));
+                }
+            }
+            try {
+                if (doc == null) {
+                    element = marshaller.marshall(xmlObject);
+                } else {
+                    element = marshaller.marshall(xmlObject, doc);
+                }
+            } catch (MarshallingException ex) {
+                throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex, "empty",
+                                              new Object[] {"Error marshalling a SAML assertion"});
+            }
+
+            if (signObject) {
+                signXMLObject(xmlObject);
+            }
+        } finally {
+            if (frag != null) {
+                while (doc.getFirstChild() != null) {
+                    doc.removeChild(doc.getFirstChild());
+                }
+                doc.appendChild(frag);
+            }
+        }
+        return element;
+    }
+
+    private static void signXMLObject(final XMLObject xmlObject) throws WSSecurityException {
+        if (xmlObject instanceof org.opensaml.saml.saml1.core.Response) {
+            org.opensaml.saml.saml1.core.Response response =
+                    (org.opensaml.saml.saml1.core.Response) xmlObject;
+
+            // Sign any Assertions
+            if (response.getAssertions() != null) {
+                for (org.opensaml.saml.saml1.core.Assertion assertion : response.getAssertions()) {
+                    signObject(assertion.getSignature());
+                }
+            }
+
+            signObject(response.getSignature());
+        } else if (xmlObject instanceof org.opensaml.saml.saml2.core.Response) {
+            org.opensaml.saml.saml2.core.Response response =
+                    (org.opensaml.saml.saml2.core.Response) xmlObject;
+
+            // Sign any Assertions
+            if (response.getAssertions() != null) {
+                for (org.opensaml.saml.saml2.core.Assertion assertion : response.getAssertions()) {
+                    signObject(assertion.getSignature());
+                }
+            }
+
+            signObject(response.getSignature());
+        } else if (xmlObject instanceof SignableSAMLObject) {
+            signObject(((SignableSAMLObject) xmlObject).getSignature());
+        }
+    }
+
+    private static void signObject(final Signature signature) throws WSSecurityException {
+        if (signature != null) {
+            ClassLoader loader = Thread.currentThread().getContextClassLoader();
+            try {
+                Thread.currentThread().setContextClassLoader(SignerProvider.class.getClassLoader());
+                Signer.signObject(signature);
+            } catch (SignatureException ex) {
+                throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex, "empty",
+                                              new Object[] {"Error signing a SAML assertion"});
+            } finally {
+                Thread.currentThread().setContextClassLoader(loader);
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6b3ace02/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
index f530afb..9c1bcb2 100644
--- a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
+++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
@@ -49,7 +49,6 @@ import org.apache.syncope.common.lib.types.SAML2BindingType;
 import org.apache.syncope.core.logic.init.SAML2SPLoader;
 import org.apache.wss4j.common.crypto.Merlin;
 import org.apache.wss4j.common.ext.WSSecurityException;
-import org.apache.wss4j.common.saml.OpenSAMLUtil;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.saml.common.SignableSAMLObject;
 import org.opensaml.saml.saml2.core.RequestAbstractType;
@@ -134,7 +133,7 @@ public class SAML2ReaderWriter {
 
         // parse the provided SAML response
         Document responseDoc = StaxUtils.read(new InputStreamReader(tokenStream, StandardCharsets.UTF_8));
-        XMLObject responseObject = OpenSAMLUtil.fromDom(responseDoc.getDocumentElement());
+        XMLObject responseObject = org.apache.wss4j.common.saml.OpenSAMLUtil.fromDom(responseDoc.getDocumentElement());
 
         if (LOG.isDebugEnabled()) {
             try {
@@ -152,7 +151,7 @@ public class SAML2ReaderWriter {
     }
 
     public void sign(final SignableSAMLObject signableObject) throws SecurityException {
-        org.opensaml.xmlsec.signature.Signature signature = OpenSAMLUtil.buildSignature();
+        org.opensaml.xmlsec.signature.Signature signature = org.apache.wss4j.common.saml.OpenSAMLUtil.buildSignature();
         signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
         signature.setSignatureAlgorithm(sigAlgo);
         signature.setSigningCredential(loader.getCredential());


[3/5] syncope git commit: Take the valid SAML Assertion from the validator response instead.

Posted by co...@apache.org.
Take the valid SAML Assertion from the validator response instead.


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/fecfc6ff
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/fecfc6ff
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/fecfc6ff

Branch: refs/heads/2_0_X
Commit: fecfc6ff37e71b5eedf7f86be429205d9dd1715e
Parents: 1d8b6c6
Author: Colm O hEigeartaigh <co...@apache.org>
Authored: Fri Aug 11 12:51:22 2017 +0100
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Fri Aug 11 13:16:36 2017 +0100

----------------------------------------------------------------------
 .../apache/syncope/core/logic/SAML2SPLogic.java | 65 ++++++++++----------
 .../core/logic/saml2/SAML2ReaderWriter.java     |  8 ++-
 2 files changed, 39 insertions(+), 34 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/fecfc6ff/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
index 31ef8c4..03576ab 100644
--- a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
+++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
@@ -37,6 +37,7 @@ import org.apache.commons.lang3.tuple.Pair;
 import org.apache.commons.lang3.tuple.Triple;
 import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactConsumer;
 import org.apache.cxf.rs.security.jose.jws.JwsSignatureVerifier;
+import org.apache.cxf.rs.security.saml.sso.SSOValidatorResponse;
 import org.apache.syncope.common.lib.AbstractBaseBean;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.AttrTO;
@@ -371,8 +372,10 @@ public class SAML2SPLogic extends AbstractSAML2Logic<AbstractBaseBean> {
         if (idp.getConnObjectKeyItem() == null) {
             throw new IllegalArgumentException("No mapping provided for SAML 2.0 IdP '" + idp.getId() + "'");
         }
+
+        SSOValidatorResponse validatorResponse = null;
         try {
-            saml2rw.validate(
+            validatorResponse = saml2rw.validate(
                     samlResponse,
                     idp,
                     getAssertionConsumerURL(response.getSpEntityID(), response.getUrlContext()),
@@ -390,47 +393,45 @@ public class SAML2SPLogic extends AbstractSAML2Logic<AbstractBaseBean> {
         responseTO.setIdp(idp.getId());
         responseTO.setSloSupported(idp.getSLOLocation(idp.getBindingType()) != null);
 
-        NameID nameID = null;
+        Assertion assertion = validatorResponse.getOpensamlAssertion();
+        NameID nameID = assertion.getSubject().getNameID();
         String keyValue = null;
-        for (Assertion assertion : samlResponse.getAssertions()) {
-            nameID = assertion.getSubject().getNameID();
-            if (StringUtils.isNotBlank(nameID.getValue())
-                    && idp.getConnObjectKeyItem().getExtAttrName().equals("NameID")) {
+        if (StringUtils.isNotBlank(nameID.getValue())
+            && idp.getConnObjectKeyItem().getExtAttrName().equals("NameID")) {
 
-                keyValue = nameID.getValue();
-            }
+            keyValue = nameID.getValue();
+        }
 
-            if (assertion.getConditions().getNotOnOrAfter() != null) {
-                responseTO.setNotOnOrAfter(assertion.getConditions().getNotOnOrAfter().toDate());
-            }
-            for (AuthnStatement authnStmt : assertion.getAuthnStatements()) {
-                responseTO.setSessionIndex(authnStmt.getSessionIndex());
+        if (assertion.getConditions().getNotOnOrAfter() != null) {
+            responseTO.setNotOnOrAfter(assertion.getConditions().getNotOnOrAfter().toDate());
+        }
+        for (AuthnStatement authnStmt : assertion.getAuthnStatements()) {
+            responseTO.setSessionIndex(authnStmt.getSessionIndex());
 
-                responseTO.setAuthInstant(authnStmt.getAuthnInstant().toDate());
-                if (authnStmt.getSessionNotOnOrAfter() != null) {
-                    responseTO.setNotOnOrAfter(authnStmt.getSessionNotOnOrAfter().toDate());
-                }
+            responseTO.setAuthInstant(authnStmt.getAuthnInstant().toDate());
+            if (authnStmt.getSessionNotOnOrAfter() != null) {
+                responseTO.setNotOnOrAfter(authnStmt.getSessionNotOnOrAfter().toDate());
             }
+        }
 
-            for (AttributeStatement attrStmt : assertion.getAttributeStatements()) {
-                for (Attribute attr : attrStmt.getAttributes()) {
-                    if (!attr.getAttributeValues().isEmpty()) {
-                        String attrName = attr.getFriendlyName() == null ? attr.getName() : attr.getFriendlyName();
-                        if (attrName.equals(idp.getConnObjectKeyItem().getExtAttrName())
-                                && attr.getAttributeValues().get(0) instanceof XSString) {
+        for (AttributeStatement attrStmt : assertion.getAttributeStatements()) {
+            for (Attribute attr : attrStmt.getAttributes()) {
+                if (!attr.getAttributeValues().isEmpty()) {
+                    String attrName = attr.getFriendlyName() == null ? attr.getName() : attr.getFriendlyName();
+                    if (attrName.equals(idp.getConnObjectKeyItem().getExtAttrName())
+                        && attr.getAttributeValues().get(0) instanceof XSString) {
 
-                            keyValue = ((XSString) attr.getAttributeValues().get(0)).getValue();
-                        }
+                        keyValue = ((XSString) attr.getAttributeValues().get(0)).getValue();
+                    }
 
-                        AttrTO attrTO = new AttrTO();
-                        attrTO.setSchema(attrName);
-                        for (XMLObject value : attr.getAttributeValues()) {
-                            if (value.getDOM() != null) {
-                                attrTO.getValues().add(value.getDOM().getTextContent());
-                            }
+                    AttrTO attrTO = new AttrTO();
+                    attrTO.setSchema(attrName);
+                    for (XMLObject value : attr.getAttributeValues()) {
+                        if (value.getDOM() != null) {
+                            attrTO.getValues().add(value.getDOM().getTextContent());
                         }
-                        responseTO.getAttrs().add(attrTO);
                     }
+                    responseTO.getAttrs().add(attrTO);
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/fecfc6ff/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
index 22b0fd1..dba63cc 100644
--- a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
+++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
@@ -43,6 +43,7 @@ import javax.xml.transform.stream.StreamResult;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.cxf.rs.security.saml.DeflateEncoderDecoder;
 import org.apache.cxf.rs.security.saml.sso.SAMLProtocolResponseValidator;
+import org.apache.cxf.rs.security.saml.sso.SSOValidatorResponse;
 import org.apache.cxf.staxutils.StaxUtils;
 import org.apache.syncope.common.lib.SSOConstants;
 import org.apache.syncope.common.lib.types.SAML2BindingType;
@@ -202,7 +203,7 @@ public class SAML2ReaderWriter {
         return Base64.encodeBase64String(deflatedBytes);
     }
 
-    public void validate(
+    public SSOValidatorResponse validate(
             final Response samlResponse,
             final SAML2IdPEntity idp,
             final String assertionConsumerURL,
@@ -224,7 +225,8 @@ public class SAML2ReaderWriter {
         ssoResponseValidator.setIssuerIDP(idp.getId());
         ssoResponseValidator.setRequestId(requestId);
         ssoResponseValidator.setSpIdentifier(spEntityID);
-        ssoResponseValidator.validateSamlResponse(samlResponse, idp.getBindingType() == SAML2BindingType.POST);
+        SSOValidatorResponse validatorResponse =
+            ssoResponseValidator.validateSamlResponse(samlResponse, idp.getBindingType() == SAML2BindingType.POST);
 
         if (LOG.isDebugEnabled()) {
             try {
@@ -237,5 +239,7 @@ public class SAML2ReaderWriter {
                 LOG.error("Could not log the SAML response with decrypted assertions", e);
             }
         }
+
+        return validatorResponse;
     }
 }


[4/5] syncope git commit: Temporarily adding SSOValidatorResponse until we pick up CXF 3.1.13

Posted by co...@apache.org.
Temporarily adding SSOValidatorResponse until we pick up CXF 3.1.13


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/c8748ba1
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/c8748ba1
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/c8748ba1

Branch: refs/heads/2_0_X
Commit: c8748ba107bdda6ae4e8a3aec6dcf4cf9e25a3f6
Parents: fecfc6f
Author: Colm O hEigeartaigh <co...@apache.org>
Authored: Fri Aug 11 13:25:57 2017 +0100
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Fri Aug 11 13:35:24 2017 +0100

----------------------------------------------------------------------
 .../apache/syncope/core/logic/SAML2SPLogic.java |  3 +-
 .../core/logic/saml2/SAML2ReaderWriter.java     |  1 -
 .../logic/saml2/SAMLSSOResponseValidator.java   | 78 +++++++++---------
 .../core/logic/saml2/SSOValidatorResponse.java  | 84 ++++++++++++++++++++
 4 files changed, 125 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/c8748ba1/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
index 03576ab..0891f59 100644
--- a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
+++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
@@ -19,6 +19,8 @@
 package org.apache.syncope.core.logic;
 
 import org.apache.syncope.core.logic.saml2.SAML2UserManager;
+import org.apache.syncope.core.logic.saml2.SSOValidatorResponse;
+
 import com.fasterxml.uuid.Generators;
 import com.fasterxml.uuid.impl.RandomBasedGenerator;
 import java.io.OutputStream;
@@ -37,7 +39,6 @@ import org.apache.commons.lang3.tuple.Pair;
 import org.apache.commons.lang3.tuple.Triple;
 import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactConsumer;
 import org.apache.cxf.rs.security.jose.jws.JwsSignatureVerifier;
-import org.apache.cxf.rs.security.saml.sso.SSOValidatorResponse;
 import org.apache.syncope.common.lib.AbstractBaseBean;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.AttrTO;

http://git-wip-us.apache.org/repos/asf/syncope/blob/c8748ba1/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
index dba63cc..f530afb 100644
--- a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
+++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2ReaderWriter.java
@@ -43,7 +43,6 @@ import javax.xml.transform.stream.StreamResult;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.cxf.rs.security.saml.DeflateEncoderDecoder;
 import org.apache.cxf.rs.security.saml.sso.SAMLProtocolResponseValidator;
-import org.apache.cxf.rs.security.saml.sso.SSOValidatorResponse;
 import org.apache.cxf.staxutils.StaxUtils;
 import org.apache.syncope.common.lib.SSOConstants;
 import org.apache.syncope.common.lib.types.SAML2BindingType;

http://git-wip-us.apache.org/repos/asf/syncope/blob/c8748ba1/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAMLSSOResponseValidator.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAMLSSOResponseValidator.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAMLSSOResponseValidator.java
index a730140..a32ed09 100644
--- a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAMLSSOResponseValidator.java
+++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAMLSSOResponseValidator.java
@@ -25,7 +25,6 @@ import java.util.logging.Logger;
 import org.w3c.dom.Element;
 
 import org.apache.cxf.common.logging.LogUtils;
-import org.apache.cxf.rs.security.saml.sso.SSOValidatorResponse;
 import org.apache.cxf.rs.security.saml.sso.TokenReplayCache;
 import org.apache.wss4j.common.ext.WSSecurityException;
 import org.apache.wss4j.common.saml.builder.SAML2Constants;
@@ -39,9 +38,9 @@ import org.opensaml.saml.saml2.core.AuthnStatement;
  */
 //CHECKSTYLE:OFF
 public class SAMLSSOResponseValidator {
-    
+
     private static final Logger LOG = LogUtils.getL7dLogger(SAMLSSOResponseValidator.class);
-    
+
     private String issuerIDP;
     private String assertionConsumerURL;
     private String clientAddress;
@@ -51,7 +50,7 @@ public class SAMLSSOResponseValidator {
     private boolean enforceAssertionsSigned = true;
     private boolean enforceKnownIssuer = true;
     private TokenReplayCache<String> replayCache;
-    
+
     /**
      * Enforce that Assertions contained in the Response must be signed (if the Response itself is not
      * signed). The default is true.
@@ -59,14 +58,14 @@ public class SAMLSSOResponseValidator {
     public void setEnforceAssertionsSigned(boolean enforceAssertionsSigned) {
         this.enforceAssertionsSigned = enforceAssertionsSigned;
     }
-    
+
     /**
      * Enforce that the Issuer of the received Response/Assertion is known. The default is true.
      */
     public void setEnforceKnownIssuer(boolean enforceKnownIssuer) {
         this.enforceKnownIssuer = enforceKnownIssuer;
     }
-    
+
     /**
      * Validate a SAML 2 Protocol Response
      * @param samlResponse
@@ -86,7 +85,7 @@ public class SAMLSSOResponseValidator {
             LOG.fine("The Response must contain at least one Assertion");
             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
         }
-        
+
         // The Response must contain a Destination that matches the assertionConsumerURL if it is
         // signed
         String destination = samlResponse.getDestination();
@@ -95,12 +94,12 @@ public class SAMLSSOResponseValidator {
             LOG.fine("The Response must contain a destination that matches the assertion consumer URL");
             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
         }
-        
+
         if (enforceResponseSigned && !samlResponse.isSigned()) {
             LOG.fine("The Response must be signed!");
             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
         }
-        
+
         // Validate Assertions
         org.opensaml.saml.saml2.core.Assertion validAssertion = null;
         Date sessionNotOnOrAfter = null;
@@ -111,17 +110,17 @@ public class SAMLSSOResponseValidator {
                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
             }
             validateIssuer(assertion.getIssuer());
-            
+
             if (!samlResponse.isSigned() && enforceAssertionsSigned && assertion.getSignature() == null) {
                 LOG.fine("The enclosed assertions in the SAML Response must be signed");
                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
             }
-            
+
             // Check for AuthnStatements and validate the Subject accordingly
             if (assertion.getAuthnStatements() != null
                 && !assertion.getAuthnStatements().isEmpty()) {
                 org.opensaml.saml.saml2.core.Subject subject = assertion.getSubject();
-                org.opensaml.saml.saml2.core.SubjectConfirmation subjectConf = 
+                org.opensaml.saml.saml2.core.SubjectConfirmation subjectConf =
                     validateAuthenticationSubject(subject, assertion.getID(), postBinding);
                 if (subjectConf != null) {
                     validateAudienceRestrictionCondition(assertion.getConditions());
@@ -139,28 +138,29 @@ public class SAMLSSOResponseValidator {
                 }
             }
         }
-        
+
         if (validAssertion == null) {
             LOG.fine("The Response did not contain any Authentication Statement that matched "
                      + "the Subject Confirmation criteria");
             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
         }
-        
+
         SSOValidatorResponse validatorResponse = new SSOValidatorResponse();
         validatorResponse.setResponseId(samlResponse.getID());
         validatorResponse.setSessionNotOnOrAfter(sessionNotOnOrAfter);
+        validatorResponse.setOpensamlAssertion(validAssertion);
         if (samlResponse.getIssueInstant() != null) {
             validatorResponse.setCreated(samlResponse.getIssueInstant().toDate());
         }
-        
+
         Element assertionElement = validAssertion.getDOM();
         Element clonedAssertionElement = (Element)assertionElement.cloneNode(true);
         validatorResponse.setAssertionElement(clonedAssertionElement);
         validatorResponse.setAssertion(DOM2Writer.nodeToString(clonedAssertionElement));
-        
+
         return validatorResponse;
     }
-    
+
     /**
      * Validate the Issuer (if it exists)
      */
@@ -168,23 +168,23 @@ public class SAMLSSOResponseValidator {
         if (issuer == null) {
             return;
         }
-        
+
         // Issuer value must match (be contained in) Issuer IDP
         if (enforceKnownIssuer && !issuerIDP.startsWith(issuer.getValue())) {
-            LOG.fine("Issuer value: " + issuer.getValue() + " does not match issuer IDP: " 
+            LOG.fine("Issuer value: " + issuer.getValue() + " does not match issuer IDP: "
                 + issuerIDP);
             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
         }
-        
+
         // Format must be nameid-format-entity
         if (issuer.getFormat() != null
             && !SAML2Constants.NAMEID_FORMAT_ENTITY.equals(issuer.getFormat())) {
-            LOG.fine("Issuer format is not null and does not equal: " 
+            LOG.fine("Issuer format is not null and does not equal: "
                 + SAML2Constants.NAMEID_FORMAT_ENTITY);
             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
         }
     }
-    
+
     /**
      * Validate the Subject (of an Authentication Statement).
      */
@@ -194,20 +194,20 @@ public class SAMLSSOResponseValidator {
         if (subject.getSubjectConfirmations() == null) {
             return null;
         }
-        
+
         org.opensaml.saml.saml2.core.SubjectConfirmation validSubjectConf = null;
         // We need to find a Bearer Subject Confirmation method
-        for (org.opensaml.saml.saml2.core.SubjectConfirmation subjectConf 
+        for (org.opensaml.saml.saml2.core.SubjectConfirmation subjectConf
             : subject.getSubjectConfirmations()) {
             if (SAML2Constants.CONF_BEARER.equals(subjectConf.getMethod())) {
                 validateSubjectConfirmation(subjectConf.getSubjectConfirmationData(), id, postBinding);
                 validSubjectConf = subjectConf;
             }
         }
-        
+
         return validSubjectConf;
     }
-    
+
     /**
      * Validate a (Bearer) Subject Confirmation
      */
@@ -218,7 +218,7 @@ public class SAMLSSOResponseValidator {
             LOG.fine("Subject Confirmation Data of a Bearer Subject Confirmation is null");
             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
         }
-        
+
         // Recipient must match assertion consumer URL
         String recipient = subjectConfData.getRecipient();
         if (recipient == null || !recipient.equals(assertionConsumerURL)) {
@@ -226,14 +226,14 @@ public class SAMLSSOResponseValidator {
                 + assertionConsumerURL);
             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
         }
-        
+
         // We must have a NotOnOrAfter timestamp
         if (subjectConfData.getNotOnOrAfter() == null
             || subjectConfData.getNotOnOrAfter().isBeforeNow()) {
             LOG.fine("Subject Conf Data does not contain NotOnOrAfter or it has expired");
             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
         }
-        
+
         // Need to keep bearer assertion IDs based on NotOnOrAfter to detect replay attacks
         if (postBinding && replayCache != null) {
             if (replayCache.getId(id) == null) {
@@ -246,7 +246,7 @@ public class SAMLSSOResponseValidator {
                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
             }
         }
-        
+
         // Check address
         if (subjectConfData.getAddress() != null && clientAddress != null
             && !subjectConfData.getAddress().equals(clientAddress)) {
@@ -254,13 +254,13 @@ public class SAMLSSOResponseValidator {
                      + " client address " + clientAddress);
             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
         }
-        
+
         // It must not contain a NotBefore timestamp
         if (subjectConfData.getNotBefore() != null) {
             LOG.fine("The Subject Conf Data must not contain a NotBefore timestamp");
             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
         }
-        
+
         // InResponseTo must match the AuthnRequest request Id
         if (requestId != null && !requestId.equals(subjectConfData.getInResponseTo())) {
             LOG.fine("The InResponseTo String does match the original request id " + requestId);
@@ -269,9 +269,9 @@ public class SAMLSSOResponseValidator {
             LOG.fine("No InResponseTo String is allowed for the unsolicted case");
             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
         }
-        
+
     }
-    
+
     private void validateAudienceRestrictionCondition(
         org.opensaml.saml.saml2.core.Conditions conditions
     ) throws WSSecurityException {
@@ -281,13 +281,13 @@ public class SAMLSSOResponseValidator {
         }
         List<AudienceRestriction> audienceRestrs = conditions.getAudienceRestrictions();
         if (!matchSaml2AudienceRestriction(spIdentifier, audienceRestrs)) {
-            LOG.fine("Assertion does not contain unique subject provider identifier " 
+            LOG.fine("Assertion does not contain unique subject provider identifier "
                      + spIdentifier + " in the audience restriction conditions");
             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
         }
     }
-    
-    
+
+
     private boolean matchSaml2AudienceRestriction(
         String appliesTo, List<AudienceRestriction> audienceRestrictions
     ) {
@@ -352,7 +352,7 @@ public class SAMLSSOResponseValidator {
     public void setSpIdentifier(String spIdentifier) {
         this.spIdentifier = spIdentifier;
     }
-    
+
     public void setReplayCache(TokenReplayCache<String> replayCache) {
         this.replayCache = replayCache;
     }
@@ -367,5 +367,5 @@ public class SAMLSSOResponseValidator {
     public void setEnforceResponseSigned(boolean enforceResponseSigned) {
         this.enforceResponseSigned = enforceResponseSigned;
     }
-    
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/c8748ba1/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SSOValidatorResponse.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SSOValidatorResponse.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SSOValidatorResponse.java
new file mode 100644
index 0000000..5eadaef
--- /dev/null
+++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SSOValidatorResponse.java
@@ -0,0 +1,84 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.logic.saml2;
+
+import java.util.Date;
+
+import org.w3c.dom.Element;
+import org.opensaml.saml.saml2.core.Assertion;
+
+/**
+ * Some information that encapsulates a successful validation by the SAMLSSOResponseValidator
+ */
+public class SSOValidatorResponse {
+    private Date sessionNotOnOrAfter;
+    private Date created;
+    private String responseId;
+    private String assertion;
+    private Element assertionElement;
+    private Assertion opensamlAssertion;
+
+    public String getAssertion() {
+        return assertion;
+    }
+
+    public void setAssertion(final String assertion) {
+        this.assertion = assertion;
+    }
+
+    public Date getSessionNotOnOrAfter() {
+        return sessionNotOnOrAfter;
+    }
+
+    public void setSessionNotOnOrAfter(final Date sessionNotOnOrAfter) {
+        this.sessionNotOnOrAfter = sessionNotOnOrAfter;
+    }
+
+    public String getResponseId() {
+        return responseId;
+    }
+
+    public void setResponseId(final String responseId) {
+        this.responseId = responseId;
+    }
+
+    public Element getAssertionElement() {
+        return assertionElement;
+    }
+
+    public void setAssertionElement(final Element assertionElement) {
+        this.assertionElement = assertionElement;
+    }
+
+    public Date getCreated() {
+        return created;
+    }
+
+    public void setCreated(final Date created) {
+        this.created = created;
+    }
+
+    public Assertion getOpensamlAssertion() {
+        return opensamlAssertion;
+    }
+
+    public void setOpensamlAssertion(final Assertion opensamlAssertion) {
+        this.opensamlAssertion = opensamlAssertion;
+    }
+}


[2/5] syncope git commit: Dynamically generate a keypair for use in the SAML signing tests

Posted by co...@apache.org.
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/1d8b6c62
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/1d8b6c62
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/1d8b6c62

Branch: refs/heads/2_0_X
Commit: 1d8b6c62110564b57eb615b405346f1c978ee65e
Parents: 919584f
Author: Colm O hEigeartaigh <co...@apache.org>
Authored: Fri Aug 11 12:38:06 2017 +0100
Committer: Colm O hEigeartaigh <co...@apache.org>
Committed: Fri Aug 11 13:16:06 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/1d8b6c62/fit/core-reference/pom.xml
----------------------------------------------------------------------
diff --git a/fit/core-reference/pom.xml b/fit/core-reference/pom.xml
index de491a3..d28eb06 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/1d8b6c62/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 e8a5add..4ae8c8f 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 javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.xml.namespace.QName;
@@ -72,6 +83,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;
@@ -86,6 +104,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() {
@@ -98,13 +118,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);
@@ -124,7 +148,7 @@ public class SAML2ITCase extends AbstractITCase {
     }
 
     @AfterClass
-    public static void clearIdPs() {
+    public static void clearIdPs() throws Exception {
         if (!SAML2SPDetector.isSAML2SPAvailable()) {
             return;
         }
@@ -132,6 +156,9 @@ public class SAML2ITCase extends AbstractITCase {
         for (SAML2IdPTO idp : saml2IdPService.list()) {
             saml2IdPService.delete(idp.getKey());
         }
+
+        Files.delete(keystorePath);
+        Files.delete(truststorePath);
     }
 
     @Test
@@ -411,16 +438,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/1d8b6c62/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/1d8b6c62/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index e29b8a4..004a8b5 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.1</connid.soap.version>
     <connid.rest.version>1.0.1</connid.rest.version>