package gov.va.med.cds.ws.saml.interceptor.client;

import java.io.StringReader;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.cxf.binding.soap.SoapHeader;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.apache.wss4j.dom.WSConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;

import gov.va.med.cds.saml.SamlAssertionThreadLocal;

/**
 * Class is used by soap clients to create a SAML Token - add a security header
 * retrieve an exiting Assertion and add it to the Security Header before sending request message to service
 * 
 * @author DNS   TALBOM
 *
 */
public class ClientSoapHeaderOutInterceptor extends AbstractSoapInterceptor{

	public ClientSoapHeaderOutInterceptor() {
		super(Phase.PRE_PROTOCOL);	
	}
	public ClientSoapHeaderOutInterceptor(String phase) {
		super(phase);
	}

	public void handleMessage(SoapMessage message) throws Fault {
		
		boolean create = true;
		if(SamlAssertionThreadLocal.get() == null){
			create = false;
		}
		addAssertionToSecurityHeaderHeader(message, create);		
	}
	
	protected Header addAssertionToSecurityHeaderHeader(SoapMessage message, boolean create) {
        for (Header h : message.getHeaders()) {
            QName n = h.getName();
            if (n.getLocalPart().equals("Security")
                && (n.getNamespaceURI().equals(WSConstants.WSSE_NS) 
                    || n.getNamespaceURI().equals(WSConstants.WSSE11_NS))) {
                return h;
            }
        }
        if (!create) {
            return null;
        }
        //create security header
        Document doc = DOMUtils.createDocument();
        Element el = doc.createElementNS(WSConstants.WSSE_NS, "wsse:Security");
        el.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:wsse", WSConstants.WSSE_NS);
        //add assertion to security header
        el.appendChild(doc.importNode(getAssertionChild(), true));
        SoapHeader sh = new SoapHeader(new QName(WSConstants.WSSE_NS, "Security"), el);
        sh.setMustUnderstand(true);
        message.getHeaders().add(sh);
        return sh;
    }
	
	protected Node getAssertionChild() {
		Node assertionNode = null;
		String assertion = SamlAssertionThreadLocal.get();
		if(assertion != null){
			try{
				
				DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
				factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);//fortify-fix scan insistence
				DocumentBuilder builder;
				
				builder = factory.newDocumentBuilder();
				Document doc = builder.parse(new InputSource( new StringReader(assertion)));//line of code fortify had issues with- fix above addresses this issue
				assertionNode = doc.getDocumentElement();
			}
			catch(Exception e){
				e.printStackTrace();
			}
		}
		return assertionNode;
	}
	
}
