<commit_before>/*
* Copyright  2003-2004 The Apache Software Foundation.
*
*  Licensed 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.ws.security.handler;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.security.SOAPConstants;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.WSEncryptionPart;
import org.apache.ws.security.WSPasswordCallback;
import org.apache.ws.security.WSSecurityEngine;
import org.apache.ws.security.WSSecurityEngineResult;
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.components.crypto.Crypto;
import org.apache.ws.security.components.crypto.CryptoFactory;
import org.apache.ws.security.message.WSAddTimestamp;
import org.apache.ws.security.message.WSEncryptBody;
import org.apache.ws.security.message.WSSAddSAMLToken;
import org.apache.ws.security.message.WSSAddUsernameToken;
import org.apache.ws.security.message.WSSignEnvelope;
import org.apache.ws.security.message.token.Timestamp;
import org.apache.ws.security.saml.SAMLIssuer;
import org.apache.ws.security.saml.SAMLIssuerFactory;
import org.apache.ws.security.util.StringUtil;
import org.apache.ws.security.util.WSSecurityUtil;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.utils.XMLUtils;
import org.opensaml.SAMLAssertion;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.rpc.Call;
import javax.xml.rpc.JAXRPCException;
import javax.xml.rpc.handler.Handler;
import javax.xml.rpc.handler.HandlerInfo;
import javax.xml.rpc.handler.MessageContext;
import javax.xml.rpc.handler.soap.SOAPMessageContext;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.TimeZone;
import java.util.Vector;

/**
 * Merged and converted the the axis handlers WSDoAllReceiver and WSDoAllSender
 * into a single JAX-RPC Handler. All the axis dependencies are removed.
 *
 * @author <NAME> (<EMAIL>).
 */
public class WSS4JHandler implements Handler {
    private HandlerInfo handlerInfo;
    static Log log = LogFactory.getLog(WSS4JHandler.class.getName());
    static final WSSecurityEngine secEngine = new WSSecurityEngine();

    private boolean doDebug = true;
    private static Hashtable cryptos = new Hashtable(5);
    private SOAPMessageContext msgContext = null;

    Crypto sigCrypto = null;
    String sigPropFile = null;

    Crypto decCrypto = null;
    String decPropFile = null;

    protected int timeToLive = 300;
    private boolean noSerialization = false;
    private SOAPConstants soapConstants = null;

    String actor = null;
    String username = null;
    String pwType = null;
    String[] utElements = null;

    int sigKeyId = 0;
    String sigAlgorithm = null;
    Vector signatureParts = new Vector();

    Crypto encCrypto = null;
    int encKeyId = 0;
    String encSymmAlgo = null;
    String encKeyTransport = null;
    String encUser = null;
    Vector encryptParts = new Vector();
    X509Certificate encCert = null;

    static final String DEPLOYMENT = "deployment";
    static final String CLIENT_DEPLOYMENT = "client";
    static final String SERVER_DEPLOYMENT = "server";

    /**
     * Initializes the instance of the handler.
     */
    public void init(HandlerInfo hi) {
        handlerInfo = hi;
    }

    /**
     * Destroys the Handler instance.
     */
    public void destroy() {
    }

    public QName[] getHeaders() {
        return handlerInfo.getHeaders();
    }

    private void initialize() {
        signatureParts.removeAllElements();
        encryptParts.removeAllElements();
    }

    public boolean handleRequest(MessageContext mc) {
        return processMessage(mc, true);
    }

    public boolean handleResponse(MessageContext mc) {
        return processMessage(mc, false);
    }

    /**
     * Switch for transfering control to doReceiver and doSender
     */
    public boolean processMessage(MessageContext mc, boolean messageType) {
        String deployment = null;
        if ((deployment = (String) handlerInfo.getHandlerConfig().get(DEPLOYMENT)) == null) {
            deployment = (String) msgContext.getProperty(DEPLOYMENT);
        }

        if (deployment == null) {
            throw new JAXRPCException("WSS4JHandler.processMessage: No deployment defined");
        }

        // call doSender if we are -
        // (handling request and client-side deployment) or (handling response and server-side deployment).
        // call doReceiver if we are -
        // (handling request and server-side deployment) or (handling response and client-side deployment).
        if (deployment.equals(CLIENT_DEPLOYMENT) ^ messageType) {
            return doReceiver(mc);
        } else {
            return doSender(mc);
        }
    }

    /**
     * Handles incoming web service requests and outgoing responses
     */
    public boolean doSender(MessageContext mc) {
        msgContext = (SOAPMessageContext) mc;

        initialize();
        noSerialization = false;
        /*
        * Get the action first.
        */
        Vector actions = new Vector();
        String action = null;
        if ((action = (String) handlerInfo.getHandlerConfig().get(WSHandlerConstants.ACTION)) == null) {
            action = (String) msgContext.getProperty(WSHandlerConstants.ACTION);
        }
        if (action == null) {
            throw new JAXRPCException("WSS4JHandler: No action defined");
        }
        int doAction = decodeAction(action, actions);
        if (doAction == WSConstants.NO_SECURITY) {
            return true;
        }

        boolean mu = decodeMustUnderstand();

        if ((actor = (String) handlerInfo.getHandlerConfig().get(WSHandlerConstants.ACTOR)) == null) {
            actor = (String) msgContext.getProperty(WSHandlerConstants.ACTOR);
        }
        /*
        * For every action we need a username, so get this now. The username
        * defined in the deployment descriptor takes precedence.
        */
        username = (String) handlerInfo.getHandlerConfig().get(WSHandlerConstants.USER);
        if (username == null || username.equals("")) {
            username = (String) msgContext.getProperty(WSHandlerConstants.USER);
            msgContext.setProperty(WSHandlerConstants.USER, null);
        }
        /*
        * Now we perform some set-up for UsernameToken and Signature
        * functions. No need to do it for encryption only. Check if username
        * is available and then get a passowrd.
        */
        if ((doAction & (WSConstants.SIGN | WSConstants.UT | WSConstants.UT_SIGN)) != 0) {
            /*
            * We need a username - if none throw an JAXRPCException. For encryption
            * there is a specific parameter to get a username.
            */
            if (username == null || username.equals("")) {
                throw new JAXRPCException("WSS4JHandler: Empty username for specified action");
            }
        }
        if (doDebug) {
            log.debug("Action: " + doAction);
            log.debug("Actor: " + actor + ", mu: " + mu);
        }
        /*
        * Now get the SOAP part from the request message and convert it into a
        * Document.
        *
        * This forces Axis to serialize the SOAP request into FORM_STRING.
        * This string is converted into a document.
        *
        * During the FORM_STRING serialization Axis performs multi-ref of
        * complex data types (if requested), generates and inserts references
        * for attachements and so on. The resulting Document MUST be the
        * complete and final SOAP request as Axis would send it over the wire.
        * Therefore this must shall be the last (or only) handler in a chain.
        *
        * Now we can perform our security operations on this request.
        */
        Document doc = null;
        SOAPMessage message = msgContext.getMessage();

        /*
        * If the message context property conatins a document then this is a
        * chained handler.
        */
        SOAPPart sPart = message.getSOAPPart();
        if ((doc = (Document) msgContext.getProperty(WSHandlerConstants.SND_SECURITY))
                == null) {
            try {
                doc = messageToDocument(message);
            } catch (Exception e) {
                throw new JAXRPCException("WSS4JHandler: cannot get SOAP envlope from message" + e);
            }
        }
        soapConstants =
                WSSecurityUtil.getSOAPConstants(doc.getDocumentElement());
        /*
        * Here we have action, username, password, and actor, mustUnderstand.
        * Now get the action specific parameters.
        */
        if ((doAction & WSConstants.UT) == WSConstants.UT) {
            decodeUTParameter();
        }
        /*
        * Here we have action, username, password, and actor, mustUnderstand.
        * Now get the action specific parameters.
        */
        if ((doAction & WSConstants.UT_SIGN) == WSConstants.UT_SIGN) {
            decodeUTParameter();
            decodeSignatureParameter();
        }
        /*
        * Get and check the Signature specific parameters first because they
        * may be used for encryption too.
        */
        if ((doAction & WSConstants.SIGN) == WSConstants.SIGN) {
            decodeSignatureParameter();
        }
        /*
        * If we need to handle signed SAML token then we need may of the
        * Signature parameters. The handle procedure loads the signature
        * crypto file on demand, thus don't do it here.
        */
        if ((doAction & WSConstants.ST_SIGNED) == WSConstants.ST_SIGNED) {
            decodeSignatureParameter();
        }
        /*
        * Set and check the encryption specific parameters, if necessary take
        * over signature parameters username and crypto instance.
        */
        if ((doAction & WSConstants.ENCR) == WSConstants.ENCR) {
            encCrypto = loadEncryptionCrypto();
            decodeEncryptionParameter();
        }
        /*
        * Here we have all necessary information to perform the requested
        * action(s).
        */
        for (int i = 0; i < actions.size(); i++) {

            int actionToDo = ((Integer) actions.get(i)).intValue();
            if (doDebug) {
                log.debug("Performing Action: " + actionToDo);
            }

            switch (actionToDo) {
                case WSConstants.UT:
                    performUTAction(actionToDo, mu, doc);
                    break;

                case WSConstants.ENCR:
                    performENCRAction(mu, actionToDo, doc);
                    break;

                case WSConstants.SIGN:
                    performSIGNAction(actionToDo, mu, doc);
                    break;

                case WSConstants.ST_SIGNED:
                    performST_SIGNAction(actionToDo, mu, doc);
                    break;

                case WSConstants.ST_UNSIGNED:
                    performSTAction(mu, doc);
                    break;

                case WSConstants.TS:
                    performTSAction(mu, doc);
                    break;

                case WSConstants.UT_SIGN:
                    performUT_SIGNAction(actionToDo, mu, doc);
                    break;

                case WSConstants.NO_SERIALIZE:
                    noSerialization = true;
                    break;
            }
        }

        /*
        * If required convert the resulting document into a message first. The
        * outputDOM() method performs the necessary c14n call. After that we
        * extract it as a string for further processing.
        *
        * Set the resulting byte array as the new SOAP message.
        *
        * If noSerialization is false, this handler shall be the last (or only)
        * one in a handler chain. If noSerialization is true, just set the
        * processed Document in the transfer property. The next Axis WSS4J
        * handler takes it and performs additional security processing steps.
        *
        */
        if (noSerialization) {
            msgContext.setProperty(WSHandlerConstants.SND_SECURITY, doc);
        } else {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            // documentToStream(doc, os);
			XMLUtils.outputDOM(doc, os, true);

            try {
                sPart.setContent(new StreamSource(new ByteArrayInputStream(os.toByteArray())));
            } catch (SOAPException se) {
                throw new JAXRPCException("Couldn't set content on SOAPPart" + se.getMessage());
            }
            if (doDebug) {
                String osStr = null;
                try {
                    osStr = os.toString("UTF-8");
                } catch (UnsupportedEncodingException e) {
                    osStr = os.toString();
                }
                log.debug("Send request:");
                log.debug(osStr);
            }
            msgContext.setProperty(WSHandlerConstants.SND_SECURITY, null);
        }
        if (doDebug) {
            log.debug("WSS4JHandler: exit invoke()");
        }
        return true;
    }

/*<commit_msg>Enable debug dynamically, insert/re-arrange some debug statements to catch the problem of testcase failure. Seems to be an Axis problem.<commit_after>/*
* Copyright  2003-2004 The Apache Software Foundation.
*
*  Licensed 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.ws.security.handler;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.security.SOAPConstants;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.WSEncryptionPart;
import org.apache.ws.security.WSPasswordCallback;
import org.apache.ws.security.WSSecurityEngine;
import org.apache.ws.security.WSSecurityEngineResult;
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.components.crypto.Crypto;
import org.apache.ws.security.components.crypto.CryptoFactory;
import org.apache.ws.security.message.WSAddTimestamp;
import org.apache.ws.security.message.WSEncryptBody;
import org.apache.ws.security.message.WSSAddSAMLToken;
import org.apache.ws.security.message.WSSAddUsernameToken;
import org.apache.ws.security.message.WSSignEnvelope;
import org.apache.ws.security.message.token.Timestamp;
import org.apache.ws.security.saml.SAMLIssuer;
import org.apache.ws.security.saml.SAMLIssuerFactory;
import org.apache.ws.security.util.StringUtil;
import org.apache.ws.security.util.WSSecurityUtil;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.utils.XMLUtils;
import org.opensaml.SAMLAssertion;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.rpc.Call;
import javax.xml.rpc.JAXRPCException;
import javax.xml.rpc.handler.Handler;
import javax.xml.rpc.handler.HandlerInfo;
import javax.xml.rpc.handler.MessageContext;
import javax.xml.rpc.handler.soap.SOAPMessageContext;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.TimeZone;
import java.util.Vector;

/**
 * Merged and converted the the axis handlers WSDoAllReceiver and WSDoAllSender
 * into a single JAX-RPC Handler. All the axis dependencies are removed.
 *
 * @author <NAME> (<EMAIL>).
 */
public class WSS4JHandler implements Handler {
    private HandlerInfo handlerInfo;
    static Log log = LogFactory.getLog(WSS4JHandler.class.getName());
    static final WSSecurityEngine secEngine = new WSSecurityEngine();

    private boolean doDebug = false;
    private static Hashtable cryptos = new Hashtable(5);
    private SOAPMessageContext msgContext = null;

    Crypto sigCrypto = null;
    String sigPropFile = null;

    Crypto decCrypto = null;
    String decPropFile = null;

    protected int timeToLive = 300;
    private boolean noSerialization = false;
    private SOAPConstants soapConstants = null;

    String actor = null;
    String username = null;
    String pwType = null;
    String[] utElements = null;

    int sigKeyId = 0;
    String sigAlgorithm = null;
    Vector signatureParts = new Vector();

    Crypto encCrypto = null;
    int encKeyId = 0;
    String encSymmAlgo = null;
    String encKeyTransport = null;
    String encUser = null;
    Vector encryptParts = new Vector();
    X509Certificate encCert = null;

    static final String DEPLOYMENT = "deployment";
    static final String CLIENT_DEPLOYMENT = "client";
    static final String SERVER_DEPLOYMENT = "server";

    /**
     * Initializes the instance of the handler.
     */
    public void init(HandlerInfo hi) {
        handlerInfo = hi;
    }

    /**
     * Destroys the Handler instance.
     */
    public void destroy() {
    }

    public QName[] getHeaders() {
        return handlerInfo.getHeaders();
    }

    private void initialize() {
        signatureParts.removeAllElements();
        encryptParts.removeAllElements();
    }

    public boolean handleRequest(MessageContext mc) {
        return processMessage(mc, true);
    }

    public boolean handleResponse(MessageContext mc) {
        return processMessage(mc, false);
    }

    /**
     * Switch for transfering control to doReceiver and doSender
     */
    public boolean processMessage(MessageContext mc, boolean messageType) {
        doDebug = log.isDebugEnabled();
        String deployment = null;
        if ((deployment = (String) handlerInfo.getHandlerConfig().get(DEPLOYMENT)) == null) {
            deployment = (String) msgContext.getProperty(DEPLOYMENT);
        }

        if (deployment == null) {
            throw new JAXRPCException("WSS4JHandler.processMessage: No deployment defined");
        }

        // call doSender if we are -
        // (handling request and client-side deployment) or (handling response and server-side deployment).
        // call doReceiver if we are -
        // (handling request and server-side deployment) or (handling response and client-side deployment).
        if (deployment.equals(CLIENT_DEPLOYMENT) ^ messageType) {
            return doReceiver(mc);
        } else {
            return doSender(mc);
        }
    }

    /**
     * Handles incoming web service requests and outgoing responses
     */
    public boolean doSender(MessageContext mc) {
        msgContext = (SOAPMessageContext) mc;

        initialize();
        noSerialization = false;
        /*
        * Get the action first.
        */
        Vector actions = new Vector();
        String action = null;
        if ((action = (String) handlerInfo.getHandlerConfig().get(WSHandlerConstants.ACTION)) == null) {
            action = (String) msgContext.getProperty(WSHandlerConstants.ACTION);
        }
        if (action == null) {
            throw new JAXRPCException("WSS4JHandler: No action defined");
        }
        int doAction = decodeAction(action, actions);
        if (doAction == WSConstants.NO_SECURITY) {
            return true;
        }

        boolean mu = decodeMustUnderstand();

        if ((actor = (String) handlerInfo.getHandlerConfig().get(WSHandlerConstants.ACTOR)) == null) {
            actor = (String) msgContext.getProperty(WSHandlerConstants.ACTOR);
        }
        /*
        * For every action we need a username, so get this now. The username
        * defined in the deployment descriptor takes precedence.
        */
        username = (String) handlerInfo.getHandlerConfig().get(WSHandlerConstants.USER);
        if (username == null || username.equals("")) {
            username = (String) msgContext.getProperty(WSHandlerConstants.USER);
            msgContext.setProperty(WSHandlerConstants.USER, null);
        }
        /*
        * Now we perform some set-up for UsernameToken and Signature
        * functions. No need to do it for encryption only. Check if username
        * is available and then get a passowrd.
        */
        if ((doAction & (WSConstants.SIGN | WSConstants.UT | WSConstants.UT_SIGN)) != 0) {
            /*
            * We need a username - if none throw an JAXRPCException. For encryption
            * there is a specific parameter to get a username.
            */
            if (username == null || username.equals("")) {
                throw new JAXRPCException("WSS4JHandler: Empty username for specified action");
            }
        }
        if (doDebug) {
            log.debug("Action: " + doAction);
            log.debug("Actor: " + actor + ", mu: " + mu);
        }
        /*
        * Now get the SOAP part from the request message and convert it into a
        * Document.
        *
        * This forces Axis to serialize the SOAP request into FORM_STRING.
        * This string is converted into a document.
        *
        * During the FORM_STRING serialization Axis performs multi-ref of
        * complex data types (if requested), generates and inserts references
        * for attachements and so on. The resulting Document MUST be the
        * complete and final SOAP request as Axis would send it over the wire.
        * Therefore this must shall be the last (or only) handler in a chain.
        *
        * Now we can perform our security operations on this request.
        */
        Document doc = null;
        SOAPMessage message = msgContext.getMessage();
        Boolean propFormOptimization = (Boolean)msgContext.getProperty("axis.form.optimization");
        log.debug("Form optimzation: " + propFormOptimization);
        /*
        * If the message context property conatins a document then this is a
        * chained handler.
        */
        SOAPPart sPart = message.getSOAPPart();
        if ((doc = (Document) msgContext.getProperty(WSHandlerConstants.SND_SECURITY))
                == null) {
            try {
                doc = messageToDocument(message);
            } catch (Exception e) {
                throw new JAXRPCException("WSS4JHandler: cannot get SOAP envlope from message" + e);
            }
        }
        if (doDebug) {
            log.debug("WSS4JHandler: orginal SOAP request: ");
            log.debug(org.apache.axis.utils.XMLUtils
                    .PrettyDocumentToString(doc));
        }
        
        soapConstants =
                WSSecurityUtil.getSOAPConstants(doc.getDocumentElement());
        /*
        * Here we have action, username, password, and actor, mustUnderstand.
        * Now get the action specific parameters.
        */
        if ((doAction & WSConstants.UT) == WSConstants.UT) {
            decodeUTParameter();
        }
        /*
        * Here we have action, username, password, and actor, mustUnderstand.
        * Now get the action specific parameters.
        */
        if ((doAction & WSConstants.UT_SIGN) == WSConstants.UT_SIGN) {
            decodeUTParameter();
            decodeSignatureParameter();
        }
        /*
        * Get and check the Signature specific parameters first because they
        * may be used for encryption too.
        */
        if ((doAction & WSConstants.SIGN) == WSConstants.SIGN) {
            decodeSignatureParameter();
        }
        /*
        * If we need to handle signed SAML token then we need may of the
        * Signature parameters. The handle procedure loads the signature
        * crypto file on demand, thus don't do it here.
        */
        if ((doAction & WSConstants.ST_SIGNED) == WSConstants.ST_SIGNED) {
            decodeSignatureParameter();
        }
        /*
        * Set and check the encryption specific parameters, if necessary take
        * over signature parameters username and crypto instance.
        */
        if ((doAction & WSConstants.ENCR) == WSConstants.ENCR) {
            encCrypto = loadEncryptionCrypto();
            decodeEncryptionParameter();
        }
        /*
        * Here we have all necessary information to perform the requested
        * action(s).
        */
        for (int i = 0; i < actions.size(); i++) {

            int actionToDo = ((Integer) actions.get(i)).intValue();
            if (doDebug) {
                log.debug("Performing Action: " + actionToDo);
            }

            switch (actionToDo) {
                case WSConstants.UT:
                    performUTAction(actionToDo, mu, doc);
                    break;

                case WSConstants.ENCR:
                    performENCRAction(mu, actionToDo, doc);
                    break;

                case WSConstants.SIGN:
                    performSIGNAction(actionToDo, mu, doc);
                    break;

                case WSConstants.ST_SIGNED:
                    performST_SIGNAction(actionToDo, mu, doc);
                    break;

                case WSConstants.ST_UNSIGNED:
                    performSTAction(mu, doc);
                    break;

                case WSConstants.TS:
                    performTSAction(mu, doc);
                    break;

                case WSConstants.UT_SIGN:
                    performUT_SIGNAction(actionToDo, mu, doc);
                    break;

                case WSConstants.NO_SERIALIZE:
                    noSerialization = true;
                    break;
            }
        }

        /*
        * If required convert the resulting document into a message first. The
        * outputDOM() method performs the necessary c14n call. After that we
        * extract it as a string for further processing.
        *
        * Set the resulting byte array as the new SOAP message.
        *
        * If noSerialization is false, this handler shall be the last (or only)
        * one in a handler chain. If noSerialization is true, just set the
        * processed Document in the transfer property. The next Axis WSS4J
        * handler takes it and performs additional security processing steps.
        *
        */
        if (noSerialization) {
            msgContext.setProperty(WSHandlerConstants.SND_SECURITY, doc);
        } else {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            // documentToStream(doc, os);
			XMLUtils.outputDOM(doc, os, true);
            if (doDebug) {
                String osStr = null;
                try {
                    osStr = os.toString("UTF-8");
                } catch (UnsupportedEncodingException e) {
                    osStr = os.toString();
                }
                log.debug("Send request:");
                log.debug(osStr);
            }

            try {
                sPart.setContent(new StreamSource(new ByteArrayInputStream(os.toByteArray())));
            } catch (SOAPException se) {
                throw new JAXRPCException("Couldn't set content on SOAPPart" + se.getMessage());
            }
            msgContext.setProperty(WSHandlerConstants.SND_SECURITY, null);
        }
        if (doDebug) {
            log.debug("WSS4JHandler: exit invoke()");
        }
        return true;
    }

/*
{'fraction_non_alphanumeric': 0.0884659205147108, 'fraction_numerical': 0.0026472756517659673, 'mean_word_length': 2.3280918924947027, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 44}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3103183', 'n_tokens_mistral': 8037, 'n_tokens_neox': 7836, 'n_words': 2259}