Package org.apache.cxf.fediz.core.metadata

Source Code of org.apache.cxf.fediz.core.metadata.MetadataWriter

/**
* 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.core.metadata;



import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;

import org.apache.cxf.fediz.core.config.Claim;
import org.apache.cxf.fediz.core.config.FederationContext;
import org.apache.cxf.fediz.core.config.FederationProtocol;
import org.apache.cxf.fediz.core.config.KeyManager;
import org.apache.cxf.fediz.core.config.Protocol;
import org.apache.cxf.fediz.core.exception.ProcessingException;
import org.apache.cxf.fediz.core.util.DOMUtils;

import org.apache.ws.security.components.crypto.CryptoType;
import org.apache.ws.security.util.UUIDGenerator;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.apache.cxf.fediz.core.FederationConstants.SAML2_METADATA_NS;
import static org.apache.cxf.fediz.core.FederationConstants.SCHEMA_INSTANCE_NS;
import static org.apache.cxf.fediz.core.FederationConstants.WS_ADDRESSING_NS;
import static org.apache.cxf.fediz.core.FederationConstants.WS_FEDERATION_NS;

public class MetadataWriter {
   
    private static final Logger LOG = LoggerFactory.getLogger(MetadataWriter.class);

    //CHECKSTYLE:OFF
    public Document getMetaData(FederationContext config) throws ProcessingException {

        try {
            XMLOutputFactory factory = XMLOutputFactory.newInstance();

            ByteArrayOutputStream bout = new ByteArrayOutputStream(4096);
            Writer streamWriter = new OutputStreamWriter(bout);
            XMLStreamWriter writer = factory.createXMLStreamWriter(streamWriter);

            Protocol protocol = config.getProtocol();

            writer.writeStartDocument();

            String referenceID = "_" + UUIDGenerator.getUUID();
            writer.writeStartElement("", "EntityDescriptor", SAML2_METADATA_NS);
            writer.writeAttribute("ID", referenceID);
           
            String audience = "_someID";
            String serviceURL = null;
            if (protocol instanceof FederationProtocol) {
                serviceURL = ((FederationProtocol)protocol).getApplicationServiceURL();
                List<String> audienceList = config.getAudienceUris();
                if (audienceList != null && audienceList.size() > 0 && !"".equals(audienceList.get(0))) {
                    audience = audienceList.get(0);
                }
            }
            if (serviceURL == null) {
                serviceURL = audience;
            }
           
            writer.writeAttribute("entityID", serviceURL);

            writer.writeNamespace("fed", WS_FEDERATION_NS);
            writer.writeNamespace("wsa", WS_ADDRESSING_NS);
            writer.writeNamespace("auth", WS_FEDERATION_NS);
            writer.writeNamespace("xsi", SCHEMA_INSTANCE_NS);

            writer.writeStartElement("fed", "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.writeStartElement("wsa", "EndpointReference", WS_ADDRESSING_NS);
            writer.writeStartElement("wsa", "Address", WS_ADDRESSING_NS);

            if (protocol instanceof FederationProtocol) {
                FederationProtocol fedprotocol = (FederationProtocol)protocol;
                String realm = fedprotocol.getRealm();
                if (!(realm == null || "".equals(realm))) {
                    writer.writeCharacters(realm);
                }
            }
            // writer.writeCharacters("http://host:port/url from config");
            writer.writeEndElement(); // Address
            writer.writeEndElement(); // EndpointReference
            writer.writeEndElement(); // TargetScope

            // TODO loop over Context config and populate claims from there instead the dummy code below

            if (protocol instanceof FederationProtocol) {
                FederationProtocol fedprotocol = (FederationProtocol)protocol;
                List<Claim> claims = fedprotocol.getClaimTypesRequested();
                if (claims != null && claims.size() > 0) {

                    // create ClaimsType section
                    writer.writeStartElement("fed", "ClaimTypesRequested", WS_FEDERATION_NS);
                    for (Claim claim : claims) {

                        writer.writeStartElement("auth", "ClaimType", WS_FEDERATION_NS);
                        writer.writeAttribute("Uri", claim.getType());
                        if (claim.isOptional()) {
                            writer.writeAttribute("Optional", "true");
                        } else {
                            writer.writeAttribute("Optional", "false");
                        }

                        writer.writeEndElement(); // ClaimType

                    }
                    writer.writeEndElement(); // ClaimsTypeRequested
                }
            }
            // 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);

            if (protocol instanceof FederationProtocol) {
                FederationProtocol fedprotocol = (FederationProtocol)protocol;
                Object issuer = fedprotocol.getIssuer();
                if (issuer instanceof String && !"".equals(issuer)) {
                    writer.writeCharacters((String)issuer);
                }
            }

            // writer.writeCharacters("http://host:port/url Issuer from config");
            writer.writeEndElement(); // Address
            writer.writeEndElement(); // EndpointReference

            writer.writeEndElement(); // PassiveRequestorEndpoint
            writer.writeEndElement(); // RoleDescriptor
            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());
           
            boolean hasSigningKey = false;
            try {
                if (config.getSigningKey().getCrypto() != null) {
                    hasSigningKey = true;
                }
            } catch (Exception ex) {
                LOG.info("No signingKey element found in config: " + ex.getMessage());
            }
            if (hasSigningKey) {
                ByteArrayOutputStream result = signMetaInfo(config, is, referenceID);
                if (result != null) {
                    is = new ByteArrayInputStream(result.toByteArray());
                } else {
                    throw new ProcessingException("Failed to sign the metadata document: result=null");
                }
            }
            return DOMUtils.readXml(is);
        } 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 ByteArrayOutputStream signMetaInfo(FederationContext config, InputStream metaInfo, String referenceID) throws Exception {
        KeyManager keyManager = config.getSigningKey();
        String keyAlias = keyManager.getKeyAlias();
        String keypass  = keyManager.getKeyPassword()
       
        // Create a DOM XMLSignatureFactory that will be used to
        // generate the enveloped signature.
        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

        // Create a Reference to the enveloped document (in this case,
        // you are signing the whole document, so a URI of "" signifies
        // that, and also specify the SHA1 digest algorithm and
        // the ENVELOPED Transform.
        Reference ref = fac.newReference("#" + referenceID, fac.newDigestMethod(DigestMethod.SHA1, null), Collections
            .singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec)null)), null, null);

        // Create the SignedInfo.
        SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE,
                                                                        (C14NMethodParameterSpec)null), fac
            .newSignatureMethod(SignatureMethod.RSA_SHA1, null), Collections.singletonList(ref));

        // step 2
        // Load the KeyStore and get the signing key and certificate.

        // in case we did not specify the key alias, we assume there is only one key in the keystore ,
        // we use this key's alias as default.
        if (keyAlias == null || "".equals(keyAlias)) {
            //keyAlias = getDefaultX509Identifier(ks);
            keyAlias = keyManager.getCrypto().getDefaultX509Identifier();
        }
       
        PrivateKey keyEntry = keyManager.getCrypto().getPrivateKey(keyAlias, keypass);
        CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
        cryptoType.setAlias(keyAlias);
        X509Certificate[] issuerCerts = keyManager.getCrypto().getX509Certificates(cryptoType);
        if (issuerCerts == null || issuerCerts.length == 0) {
            throw new ProcessingException(
                    "No issuer certs were found to sign the metadata using issuer name: "
                            + keyAlias);
        }
        X509Certificate cert = issuerCerts[0];
       
        // Create the KeyInfo containing the X509Data.
        KeyInfoFactory kif = fac.getKeyInfoFactory();
        List<Object> x509Content = new ArrayList<Object>();
        x509Content.add(cert.getSubjectX500Principal().getName());
        x509Content.add(cert);
        X509Data xd = kif.newX509Data(x509Content);
        KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));

        // step3
        // Instantiate the document to be signed.
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        Document doc = dbf.newDocumentBuilder().parse(metaInfo);

        // Create a DOMSignContext and specify the RSA PrivateKey and
        // location of the resulting XMLSignature's parent element.
        //DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), doc.getDocumentElement());
        DOMSignContext dsc = new DOMSignContext(keyEntry, doc.getDocumentElement());
        dsc.setIdAttributeNS(doc.getDocumentElement(), null, "ID");
        dsc.setNextSibling(doc.getDocumentElement().getFirstChild());

        // Create the XMLSignature, but don't sign it yet.
        XMLSignature signature = fac.newXMLSignature(si, ki);

        // Marshal, generate, and sign the enveloped signature.
        signature.sign(dsc);

        // step 4
        // Output the resulting document.

        ByteArrayOutputStream os = new ByteArrayOutputStream(8192);
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer trans = tf.newTransformer();
        trans.transform(new DOMSource(doc), new StreamResult(os));
        os.flush();
        return os;
    }

}
TOP

Related Classes of org.apache.cxf.fediz.core.metadata.MetadataWriter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.