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

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

The newest version!
/*
 * Copyright (c) 1997, 2022 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Distribution License v. 1.0, which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

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 jakarta.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 jakarta.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) {

        //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 {
                return someTime < _notOnOrAfter.getTime();
            }
        } else if (_notOnOrAfter == null ) {
            return someTime >= _notBefore.getTime();
        } else return (someTime >= _notBefore.getTime()) &&
                (someTime < _notOnOrAfter.getTime());
    }

    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));
            return xmlSignature.validate(validationContext);
        } 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.FALSE;
        DSigResolver(Map map,Element elem){
            this.elem = elem;
            this.map = map;
            init();
        }

        void init(){
            try{
                _nodeSetClass = Class.forName(optNSClassName);
                _constructor = _nodeSetClass.getConstructor(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){

            }
        }
        @Override
        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);
                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(){
                        @Override
                        public Iterator iterator(){
                            return nodeSet.iterator();
                        }
                    };
                }

            }

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

        @SuppressWarnings({"fallthrough"})
        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 = rootNode.getAttributes();
                        for (int i=0;i