All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.xml.wss.saml.util.SAMLUtil Maven / Gradle / Ivy

There is a newer version: 4.0.4
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://oss.oracle.com/licenses/CDDL+GPL-1.1
 * or LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.sun.xml.wss.saml.util;


import com.sun.xml.stream.buffer.MutableXMLStreamBuffer;
import com.sun.xml.stream.buffer.stax.StreamWriterBufferCreator;
import com.sun.xml.wss.WSITXMLFactory;
import com.sun.xml.wss.impl.SecurableSoapMessage;
import com.sun.xml.wss.logging.LogDomainConstants;
import com.sun.xml.wss.XWSSecurityException;
import com.sun.xml.wss.impl.MessageConstants;
import com.sun.xml.wss.impl.dsig.WSSPolicyConsumerImpl;
import com.sun.xml.wss.logging.saml.LogStringsMessages;
import java.text.ParseException;
import java.util.Date;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.bind.Marshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.dom.DOMResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.bind.JAXBContext;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import com.sun.xml.wss.util.DateUtils;
import java.lang.reflect.Constructor;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.xml.crypto.Data;
import javax.xml.crypto.NodeSetData;
import javax.xml.crypto.URIDereferencer;
import javax.xml.crypto.URIReference;
import javax.xml.crypto.URIReferenceException;
import javax.xml.crypto.XMLCryptoContext;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import org.w3c.dom.NamedNodeMap;

public class SAMLUtil {
    private static Logger logger = Logger.getLogger(LogDomainConstants.SAML_API_DOMAIN,
            LogDomainConstants.SAML_API_DOMAIN_BUNDLE);      
    
    public static Element locateSamlAssertion(String assertionId,Document soapDocument)
    throws XWSSecurityException {
        
        //System.out.println("\n\n--------SOAP DOCUMENT : " + soapDocument + "--------\n\n");
        
        NodeList nodeList = null;
        
//        try {
          nodeList = soapDocument.getElementsByTagNameNS(MessageConstants.SAML_v1_0_NS, MessageConstants.SAML_ASSERTION_LNAME);
          if((nodeList.item(0)) == null ){
              nodeList = soapDocument.getElementsByTagNameNS(MessageConstants.SAML_v2_0_NS,
                    MessageConstants.SAML_ASSERTION_LNAME);
          }
        
        int nodeListLength = nodeList.getLength();
        if (nodeListLength == 0) {
                logger.log(Level.SEVERE,LogStringsMessages.WSS_001_SAML_ASSERTION_NOT_FOUND(assertionId));
            throw SecurableSoapMessage.newSOAPFaultException(
                    MessageConstants.WSSE_SECURITY_TOKEN_UNAVAILABLE,
                    "Referenced Security Token could not be retrieved",
                    null);
            //throw new XWSSecurityException(
            //"No SAML Assertion found with  AssertionID:" + assertionId );
        }
        
        for (int i=0; i 0) {
            conditionsElement = nl.item(0);
        } else {
            //no conditions stmt
            logger.log(Level.INFO, "No Conditions Element found in SAML Assertion");
            return true;
        }
        Element elt = (Element)conditionsElement;
        String eltName = elt.getLocalName();
        if (eltName == null)  {
            throw new XWSSecurityException("Internal Error: LocalName of Conditions Element found Null") ;
        }
        if (!(eltName.equals("Conditions")))  {
            throw new XWSSecurityException("Internal Error: LocalName of Conditions Element found to be :" + eltName) ;
        }
        
        String dt = elt.getAttribute("NotBefore");
        if ((dt != null) && (!dt.equals("")))  {
            try {
                _notBefore = DateUtils.stringToDate(dt);
            } catch (ParseException pe) {
               throw new XWSSecurityException(pe);
            }
                                                                                                                                                             
        }
        dt = elt.getAttribute("NotOnOrAfter");
        if ((dt != null) && (!dt.equals("")))  {
            try {
                _notOnOrAfter = DateUtils.stringToDate(
                            elt.getAttribute("NotOnOrAfter"));
            } catch (ParseException pe) {
               throw new XWSSecurityException(pe);
            }
        }
        
        long someTime = System.currentTimeMillis();
        
        if (_notBefore == null ) {
            if (_notOnOrAfter == null) {
                return true;
            } else {
                if (someTime < _notOnOrAfter.getTime()) {
                    return true;
                }
            }
        } else if (_notOnOrAfter == null ) {
            if (someTime >= _notBefore.getTime()) {
                return true;
            }
        } else if ((someTime >= _notBefore.getTime()) &&
            (someTime < _notOnOrAfter.getTime()))
        {
            return true;
        }
        return false;
    }

    public static boolean verifySignature(Element samlAssertion, PublicKey pubKey)throws XWSSecurityException {
        try {
            Map map = new HashMap();
            String id = samlAssertion.getAttribute("ID");
            if (id == null || id.length() < 1){
                id = samlAssertion.getAttribute("AssertionID");
            }
            map.put(id, samlAssertion);
            NodeList nl = samlAssertion.getElementsByTagNameNS(MessageConstants.DSIG_NS, "Signature");

            //verify the signature inside the SAML assertion
            if (nl.getLength() == 0) {
                throw new XWSSecurityException("Unsigned SAML Assertion encountered while verifying the SAML signature");
            }
            Element signElement = (Element) nl.item(0);
            DOMValidateContext validationContext = new DOMValidateContext(pubKey, signElement);
            XMLSignatureFactory signatureFactory = WSSPolicyConsumerImpl.getInstance().getSignatureFactory();

            // unmarshal the XMLSignature
            XMLSignature xmlSignature = signatureFactory.unmarshalXMLSignature(validationContext);
            validationContext.setURIDereferencer(new DSigResolver(map, samlAssertion));
            boolean coreValidity = xmlSignature.validate(validationContext);
            return coreValidity;
        } catch (Exception ex) {
            throw new XWSSecurityException(ex);
        }
    }

    private static class DSigResolver implements URIDereferencer{
        //TODO : Convert DSigResolver to singleton class.
        Element elem = null;
        Map map = null;
        Class _nodeSetClass = null;
        String optNSClassName = "org.apache.jcp.xml.dsig.internal.dom.DOMSubTreeData";
        Constructor _constructor = null;
        Boolean  _false = Boolean.valueOf(false);
        DSigResolver(Map map,Element elem){
            this.elem = elem;
            this.map = map;
            init();
        }

        void init(){
            try{
                _nodeSetClass = Class.forName(optNSClassName);
                _constructor = _nodeSetClass.getConstructor(new Class [] {org.w3c.dom.Node.class,boolean.class});
            }catch(LinkageError le){
                // logger.log (Level.FINE,"Not able load JSR 105 RI specific NodeSetData class ",le);
            }catch(ClassNotFoundException cne){
                // logger.log (Level.FINE,"Not able load JSR 105 RI specific NodeSetData class ",cne);
            }catch(NoSuchMethodException ne){

            }
        }
        public Data dereference(URIReference uriRef, XMLCryptoContext context) throws URIReferenceException {
            try{
                String uri = null;
                uri = uriRef.getURI();
                return dereferenceURI(uri,context);
            }catch(Exception ex){
                // log here
                throw new URIReferenceException(ex);
            }
        }
        Data dereferenceURI(String uri, XMLCryptoContext context) throws URIReferenceException{
            if(uri.charAt(0) == '#'){
                uri =  uri.substring(1,uri.length());
                Element el = elem.getOwnerDocument().getElementById(uri);
                if(el == null){
                    el = (Element)map.get(uri);
                }

                if(_constructor != null){
                    try{
                        return (Data)_constructor.newInstance(new Object[] {el,_false});
                    }catch(Exception ex){
                        // TODO: igonore this ?
                        ex.printStackTrace();
                    }
                }else{
                    final HashSet nodeSet = new HashSet();
                    toNodeSet(el,nodeSet);
                    return new NodeSetData(){
                        public Iterator iterator(){
                            return nodeSet.iterator();
                        }
                    };
                }

            }

            return null;
            //throw new URIReferenceException("Resource "+uri+" was not found");
        }

        void toNodeSet(final Node rootNode,final Set result){
            switch (rootNode.getNodeType()) {
                case Node.ELEMENT_NODE:
                    result.add(rootNode);
                    Element el=(Element)rootNode;
                    if (el.hasAttributes()) {
                        NamedNodeMap nl = ((Element)rootNode).getAttributes();
                        for (int i=0;i