cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cohei...@apache.org
Subject [2/2] cxf-fediz git commit: [FEDIZ-113] - Added support for Metadata in the idp for federating to remote Idps
Date Thu, 28 May 2015 15:22:34 GMT
[FEDIZ-113] - Added support for Metadata in the idp for federating to remote Idps


Project: http://git-wip-us.apache.org/repos/asf/cxf-fediz/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf-fediz/commit/5f1bc25e
Tree: http://git-wip-us.apache.org/repos/asf/cxf-fediz/tree/5f1bc25e
Diff: http://git-wip-us.apache.org/repos/asf/cxf-fediz/diff/5f1bc25e

Branch: refs/heads/master
Commit: 5f1bc25ed67669758a20f50544d93effd2dde7b5
Parents: f852083
Author: Colm O hEigeartaigh <coheigea@apache.org>
Authored: Thu May 28 16:22:02 2015 +0100
Committer: Colm O hEigeartaigh <coheigea@apache.org>
Committed: Thu May 28 16:22:02 2015 +0100

----------------------------------------------------------------------
 .../cxf/fediz/service/idp/MetadataServlet.java  |   5 +-
 .../idp/metadata/ServiceMetadataWriter.java     | 232 +++++++++++++++++++
 .../fediz/integrationtests/AbstractTests.java   |  31 +++
 3 files changed, 267 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5f1bc25e/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/MetadataServlet.java
----------------------------------------------------------------------
diff --git a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/MetadataServlet.java
b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/MetadataServlet.java
index a458f56..039d26f 100644
--- a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/MetadataServlet.java
+++ b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/MetadataServlet.java
@@ -32,6 +32,7 @@ import org.w3c.dom.Document;
 import org.apache.cxf.fediz.service.idp.domain.Idp;
 import org.apache.cxf.fediz.service.idp.domain.TrustedIdp;
 import org.apache.cxf.fediz.service.idp.metadata.IdpMetadataWriter;
+import org.apache.cxf.fediz.service.idp.metadata.ServiceMetadataWriter;
 import org.apache.cxf.fediz.service.idp.service.ConfigService;
 import org.apache.wss4j.common.util.DOM2Writer;
 import org.slf4j.Logger;
@@ -73,7 +74,9 @@ public class MetadataServlet extends HttpServlet {
                     LOG.error("No TrustedIdp found for desired realm: " + serviceRealm);
                     response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                 }
-                // TODO
+                ServiceMetadataWriter mw = new ServiceMetadataWriter();
+                Document metadata = mw.getMetaData(idpConfig, trustedIdp);
+                out.write(DOM2Writer.nodeToString(metadata));
             } else {
                 // Otherwise return the Metadata for the Idp
                 LOG.debug(idpConfig.toString());

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5f1bc25e/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/metadata/ServiceMetadataWriter.java
----------------------------------------------------------------------
diff --git a/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/metadata/ServiceMetadataWriter.java
b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/metadata/ServiceMetadataWriter.java
new file mode 100644
index 0000000..a732511
--- /dev/null
+++ b/services/idp/src/main/java/org/apache/cxf/fediz/service/idp/metadata/ServiceMetadataWriter.java
@@ -0,0 +1,232 @@
+/**
+ * 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.cxf.fediz.service.idp.metadata;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.security.cert.X509Certificate;
+import java.util.Map;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.w3c.dom.Document;
+
+import org.apache.cxf.fediz.core.exception.ProcessingException;
+import org.apache.cxf.fediz.core.util.CertsUtils;
+import org.apache.cxf.fediz.core.util.SignatureUtils;
+import org.apache.cxf.fediz.service.idp.domain.Idp;
+import org.apache.cxf.fediz.service.idp.domain.TrustedIdp;
+import org.apache.cxf.fediz.service.idp.protocols.TrustedIdpSAMLProtocolHandler;
+import org.apache.wss4j.common.crypto.Crypto;
+import org.apache.xml.security.stax.impl.util.IDGenerator;
+import org.apache.xml.security.utils.Base64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.cxf.fediz.core.FedizConstants.SAML2_METADATA_NS;
+import static org.apache.cxf.fediz.core.FedizConstants.SCHEMA_INSTANCE_NS;
+import static org.apache.cxf.fediz.core.FedizConstants.WS_ADDRESSING_NS;
+import static org.apache.cxf.fediz.core.FedizConstants.WS_FEDERATION_NS;
+
+public class ServiceMetadataWriter {
+    
+    private static final Logger LOG = LoggerFactory.getLogger(ServiceMetadataWriter.class);
+    
+    private static final XMLOutputFactory XML_OUTPUT_FACTORY = XMLOutputFactory.newInstance();
+    private static final DocumentBuilderFactory DOC_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
+    
+    static {
+        DOC_BUILDER_FACTORY.setNamespaceAware(true);
+    }
+
+    //CHECKSTYLE:OFF
+    public Document getMetaData(Idp config, TrustedIdp serviceConfig) throws ProcessingException
{
+
+        try {
+            Crypto crypto = CertsUtils.createCrypto(config.getCertificate());
+            
+            ByteArrayOutputStream bout = new ByteArrayOutputStream(4096);
+            Writer streamWriter = new OutputStreamWriter(bout, "UTF-8");
+            XMLStreamWriter writer = XML_OUTPUT_FACTORY.createXMLStreamWriter(streamWriter);
+
+            writer.writeStartDocument("UTF-8", "1.0");
+
+            String referenceID = IDGenerator.generateID("_");
+            writer.writeStartElement("md", "EntityDescriptor", SAML2_METADATA_NS);
+            writer.writeAttribute("ID", referenceID);
+            
+            String serviceURL = config.getIdpUrl().toString();
+            writer.writeAttribute("entityID", serviceURL);
+            
+            writer.writeNamespace("md", SAML2_METADATA_NS);
+            writer.writeNamespace("fed", WS_FEDERATION_NS);
+            writer.writeNamespace("wsa", WS_ADDRESSING_NS);
+            writer.writeNamespace("auth", WS_FEDERATION_NS);
+            writer.writeNamespace("xsi", SCHEMA_INSTANCE_NS);
+
+            if ("http://docs.oasis-open.org/wsfed/federation/200706".equals(serviceConfig.getProtocol()))
{
+                writeFederationMetadata(writer, serviceConfig, serviceURL);
+            } else if ("urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser".equals(serviceConfig.getProtocol()))
{
+                writeSAMLMetadata(writer, serviceConfig, serviceURL, crypto);
+            }
+            
+            writer.writeEndElement(); // EntityDescriptor
+
+            writer.writeEndDocument();
+            
+            streamWriter.flush();
+            bout.flush();
+            //
+
+            if (LOG.isDebugEnabled()) {
+                String out = new String(bout.toByteArray());
+                LOG.debug("***************** unsigned ****************");
+                LOG.debug(out);
+                LOG.debug("***************** unsigned ****************");
+            }
+
+            InputStream is = new ByteArrayInputStream(bout.toByteArray());
+            
+            Document result = SignatureUtils.signMetaInfo(crypto, null, config.getCertificatePassword(),
is, referenceID);
+            if (result != null) {
+                return result;
+            } else {
+                throw new RuntimeException("Failed to sign the metadata document: result=null");
+            }
+        } catch (ProcessingException e) {
+            throw e;
+        } catch (Exception e) {
+            LOG.error("Error creating service metadata information ", e);
+            throw new ProcessingException("Error creating service metadata information: "
+ e.getMessage());
+        }
+
+    }
+
+    private void writeFederationMetadata(
+        XMLStreamWriter writer, 
+        TrustedIdp config,
+        String serviceURL
+    ) throws XMLStreamException {
+
+        writer.writeStartElement("md", "RoleDescriptor", WS_FEDERATION_NS);
+        writer.writeAttribute(SCHEMA_INSTANCE_NS, "type", "fed:ApplicationServiceType");
+        writer.writeAttribute("protocolSupportEnumeration", WS_FEDERATION_NS);
+
+        writer.writeStartElement("fed", "ApplicationServiceEndpoint", WS_FEDERATION_NS);
+        writer.writeStartElement("wsa", "EndpointReference", WS_ADDRESSING_NS);
+
+        writer.writeStartElement("wsa", "Address", WS_ADDRESSING_NS);
+        writer.writeCharacters(serviceURL);
+        
+        writer.writeEndElement(); // Address
+        writer.writeEndElement(); // EndpointReference
+        writer.writeEndElement(); // ApplicationServiceEndpoint
+
+        // create target scope element
+        writer.writeStartElement("fed", "TargetScope", WS_FEDERATION_NS);
+        writer.writeEndElement(); // TargetScope
+
+        // create sign in endpoint section
+
+        writer.writeStartElement("fed", "PassiveRequestorEndpoint", WS_FEDERATION_NS);
+        writer.writeStartElement("wsa", "EndpointReference", WS_ADDRESSING_NS);
+        writer.writeStartElement("wsa", "Address", WS_ADDRESSING_NS);
+
+        writer.writeCharacters(serviceURL);
+
+        // writer.writeCharacters("http://host:port/url Issuer from config");
+        writer.writeEndElement(); // Address
+        writer.writeEndElement(); // EndpointReference
+
+        writer.writeEndElement(); // PassiveRequestorEndpoint
+        writer.writeEndElement(); // RoleDescriptor
+    }
+    
+    private void writeSAMLMetadata(
+        XMLStreamWriter writer, 
+        TrustedIdp config,
+        String serviceURL,
+        Crypto crypto
+    ) throws Exception {
+        
+        writer.writeStartElement("md", "SPSSODescriptor", SAML2_METADATA_NS);
+        boolean signRequest = 
+            isPropertyConfigured(config, TrustedIdpSAMLProtocolHandler.SIGN_REQUEST, true);
+        writer.writeAttribute("AuthnRequestsSigned", Boolean.toString(signRequest));
+        writer.writeAttribute("WantAssertionsSigned", "true");
+        writer.writeAttribute("protocolSupportEnumeration", "urn:oasis:names:tc:SAML:2.0:protocol");
+        
+        writer.writeStartElement("md", "AssertionConsumerService", SAML2_METADATA_NS);
+        writer.writeAttribute("Location", serviceURL);
+        writer.writeAttribute("index", "0");
+        writer.writeAttribute("isDefault", "true");
+        writer.writeAttribute("Binding", "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST");
+        writer.writeEndElement(); // AssertionConsumerService
+        
+        if (signRequest) {
+            writer.writeStartElement("md", "KeyDescriptor", SAML2_METADATA_NS);
+            writer.writeAttribute("use", "signing");
+            
+            writer.writeStartElement("ds", "KeyInfo", "http://www.w3.org/2000/09/xmldsig#");
+            writer.writeNamespace("ds", "http://www.w3.org/2000/09/xmldsig#");
+            writer.writeStartElement("ds", "X509Data", "http://www.w3.org/2000/09/xmldsig#");
+            writer.writeStartElement("ds", "X509Certificate", "http://www.w3.org/2000/09/xmldsig#");
+
+            // Write the Base-64 encoded certificate
+            
+            String keyAlias = crypto.getDefaultX509Identifier();
+            X509Certificate cert = CertsUtils.getX509Certificate(crypto, keyAlias);
+            
+            if (cert == null) {
+                throw new ProcessingException(
+                    "No signing certs were found to insert into the metadata using name:
" 
+                        + keyAlias);
+            }
+            byte data[] = cert.getEncoded();
+            String encodedCertificate = Base64.encode(data);
+            writer.writeCharacters(encodedCertificate);
+            
+            writer.writeEndElement(); // X509Certificate
+            writer.writeEndElement(); // X509Data
+            writer.writeEndElement(); // KeyInfo
+            writer.writeEndElement(); // KeyDescriptor
+        }
+        
+        writer.writeEndElement(); // SPSSODescriptor
+    }
+    
+    // Is a property configured. Defaults to "true" if not
+    private boolean isPropertyConfigured(TrustedIdp trustedIdp, String property, boolean
defaultValue) {
+        Map<String, String> parameters = trustedIdp.getParameters();
+        
+        if (parameters != null && parameters.containsKey(property)) {
+            return Boolean.parseBoolean(parameters.get(property));
+        }
+        
+        return defaultValue;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/5f1bc25e/systests/tests/src/test/java/org/apache/cxf/fediz/integrationtests/AbstractTests.java
----------------------------------------------------------------------
diff --git a/systests/tests/src/test/java/org/apache/cxf/fediz/integrationtests/AbstractTests.java
b/systests/tests/src/test/java/org/apache/cxf/fediz/integrationtests/AbstractTests.java
index 8ba7288..7f3c05a 100644
--- a/systests/tests/src/test/java/org/apache/cxf/fediz/integrationtests/AbstractTests.java
+++ b/systests/tests/src/test/java/org/apache/cxf/fediz/integrationtests/AbstractTests.java
@@ -371,6 +371,37 @@ public abstract class AbstractTests {
     }
     
     @Test
+    public void testIdPServiceMetadata() throws Exception {
+        String url = "https://localhost:" + getIdpHttpsPort() 
+            + "/fediz-idp/metadata/urn:org:apache:cxf:fediz:idp:realm-B";
+
+        final WebClient webClient = new WebClient();
+        webClient.getOptions().setUseInsecureSSL(true);
+        webClient.getOptions().setSSLClientCertificate(
+            this.getClass().getClassLoader().getResource("client.jks"), "storepass", "jks");
+
+        final XmlPage rpPage = webClient.getPage(url);
+        final String xmlContent = rpPage.asXml();
+        Assert.assertTrue(xmlContent.startsWith("<md:EntityDescriptor"));
+        
+        // Now validate the Signature
+        Document doc = rpPage.getXmlDocument();
+        
+        doc.getDocumentElement().setIdAttributeNS(null, "ID", true);
+        
+        Node signatureNode = 
+            DOMUtils.getChild(doc.getDocumentElement(), "Signature");
+        Assert.assertNotNull(signatureNode);
+        
+        XMLSignature signature = new XMLSignature((Element)signatureNode, "");
+        KeyInfo ki = signature.getKeyInfo();
+        Assert.assertNotNull(ki);
+        Assert.assertNotNull(ki.getX509Certificate());
+
+        Assert.assertTrue(signature.checkSignatureValue(ki.getX509Certificate()));
+    }
+    
+    @Test
     public void testRPLogout() throws Exception {
 
         String url = "https://localhost:" + getRpHttpsPort() + "/fedizhelloworld/secure/fedservlet";


Mime
View raw message