<commit_before>/*
 * Copyright 2004,2005 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.rampart;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.rampart.policy.RampartPolicyData;
import org.apache.rampart.util.RampartUtil;
import org.apache.ws.secpolicy.Constants;
import org.apache.ws.secpolicy.model.HttpsToken;
import org.apache.ws.secpolicy.model.IssuedToken;
import org.apache.ws.secpolicy.model.SignedEncryptedParts;
import org.apache.ws.secpolicy.model.SupportingToken;
import org.apache.ws.secpolicy.model.Token;
import org.apache.ws.secpolicy.model.UsernameToken;
import org.apache.ws.secpolicy.model.X509Token;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.WSEncryptionPart;
import org.apache.ws.security.WSSecurityEngineResult;
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.message.token.Timestamp;
import org.apache.ws.security.util.WSSecurityUtil;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import java.math.BigInteger;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;

public class PolicyBasedResultsValidator {
    
    private static Log log = LogFactory.getLog(PolicyBasedResultsValidator.class);
    
    public void validate(ValidatorData data, Vector results) 
    throws RampartException {
        
        RampartMessageData rmd = data.getRampartMessageData();
        
        RampartPolicyData rpd = rmd.getPolicyData();
        
        //If there's Security policy present and no results 
        //then we should throw an error
        if(rpd != null && results == null) {
            throw new RampartException("noSecurityResults");
        }
        
        //Check presence of timestamp
        WSSecurityEngineResult tsResult = null;
        if(rpd.isIncludeTimestamp()) {
            tsResult = 
                WSSecurityUtil.fetchActionResult(results, WSConstants.TS);
            if(tsResult == null) {
                throw new RampartException("timestampMissing");
            }
            
        }
        
        //sig/encr
        Vector encryptedParts = RampartUtil.getEncryptedParts(rmd);
        if(rpd.isSignatureProtection() && isSignatureRequired(rmd)) {
            encryptedParts.add(new WSEncryptionPart(WSConstants.SIG_LN, 
                    WSConstants.SIG_NS, "Element"));
        }
        
        Vector signatureParts = RampartUtil.getSignedParts(rmd);

        //Timestamp is not included in sig parts
        if(rpd.isIncludeTimestamp() && !rpd.isTransportBinding()) {
            signatureParts.add(new WSEncryptionPart("timestamp"));
        }
        
        if(!rmd.isInitiator()) {
                        
            //Just an indicator for EndorsingSupportingToken signature
            SupportingToken endSupportingToken = rpd.getEndorsingSupportingTokens();
            if(endSupportingToken !=  null) {
                SignedEncryptedParts endSignedParts = endSupportingToken.getSignedParts();
                if((endSignedParts != null && 
                        (endSignedParts.isBody() || 
                                endSignedParts.getHeaders().size() > 0)) ||
                                rpd.isIncludeTimestamp()) {
                    signatureParts.add(
                            new WSEncryptionPart("EndorsingSupportingTokens"));
                }
            }
            //Just an indicator for SignedEndorsingSupportingToken signature
            SupportingToken sgndEndSupportingToken = rpd.getSignedEndorsingSupportingTokens();
            if(sgndEndSupportingToken != null) {
                SignedEncryptedParts sgndEndSignedParts = sgndEndSupportingToken.getSignedParts();
                if((sgndEndSignedParts != null && 
                        (sgndEndSignedParts.isBody() || 
                                sgndEndSignedParts.getHeaders().size() > 0)) || 
                                rpd.isIncludeTimestamp()) {
                    signatureParts.add(
                            new WSEncryptionPart("SignedEndorsingSupportingTokens"));
                }
            }
        }
        
        validateEncrSig(data,encryptedParts, signatureParts, results);
        
        if(!rpd.isTransportBinding()) {
            validateProtectionOrder(data, results);
        }  
        
        if(rpd.isTransportBinding() && !rmd.isInitiator()){
            if (rpd.getTransportToken() instanceof HttpsToken) {
                String incomingTransport = rmd.getMsgContext().getIncomingTransportName();
                if(!incomingTransport.equals(org.apache.axis2.Constants.TRANSPORT_HTTPS)){
                    throw new RampartException("invalidTransport", 
                            new String[]{incomingTransport});
                }
            }
        }
        
        validateEncryptedParts(data, encryptedParts, results);

        validateSignedPartsHeaders(data, signatureParts, results);

        //Supporting tokens
        if(!rmd.isInitiator()) {
            validateSupportingTokens(data, results);
        }
        
        /*
         * Now we can check the certificate used to sign the message. In the
         * following implementation the certificate is only trusted if either it
         * itself or the certificate of the issuer is installed in the keystore.
         * 
         * Note: the method verifyTrust(X509Certificate) allows custom
         * implementations with other validation algorithms for subclasses.
         */

        // Extract the signature action result from the action vector
        WSSecurityEngineResult actionResult = WSSecurityUtil.fetchActionResult(
                results, WSConstants.SIGN);

        if (actionResult != null) {
            X509Certificate returnCert = (X509Certificate) actionResult
                    .get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);

            if (returnCert != null) {
                if (!verifyTrust(returnCert, rmd)) {
                    throw new RampartException ("trustVerificationError");
                }
            }
        }
        
        /*
         * Perform further checks on the timestamp that was transmitted in the
         * header. 
         * In the following implementation the timestamp is valid if :
         * Timestamp->Created < 'now' < Timestamp->Expires (Last test already handled by WSS4J)
         * 
         * Note: the method verifyTimestamp(Timestamp) allows custom
         * implementations with other validation algorithms for subclasses.
         */

        // Extract the timestamp action result from the action vector
        actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.TS);

        if (actionResult != null) {
            Timestamp timestamp = (Timestamp) actionResult
                    .get(WSSecurityEngineResult.TAG_TIMESTAMP);

            if (timestamp != null) {
                if (!verifyTimestamp(timestamp, rmd)) {
                    throw new RampartException("cannotValidateTimestamp");
                }
            }
        }
    }
    
    /**
     * @param encryptedParts
     * @param signatureParts
     */
    private void validateEncrSig(ValidatorData data,Vector encryptedParts, Vector signatureParts, Vector results) 
    throws RampartException {
        ArrayList actions = getSigEncrActions(results);
        boolean sig = false; 
        boolean encr = false;
        for (Iterator iter = actions.iterator(); iter.hasNext();) {
            Integer act = (Integer) iter.next();
            if(act.intValue() == WSConstants.SIGN) {
                sig = true;
            } else if(act.intValue() == WSConstants.ENCR) {
                encr = true;
            }
        }
        
        RampartPolicyData rpd = data.getRampartMessageData().getPolicyData();
        
        SupportingToken sgndSupTokens = rpd.getSignedSupportingTokens();
        SupportingToken sgndEndorSupTokens = rpd.getSignedEndorsingSupportingTokens();
        
        if(sig && signatureParts.size() == 0 
                && sgndSupTokens.getTokens().size() == 0
                 && sgndEndorSupTokens.getTokens().size() == 0) {
            
            //Unexpected signature
            throw new RampartException("unexprectedSignature");
        } else if(!sig && signatureParts.size() > 0) {
            
            //required signature missing
            throw new RampartException("signatureMissing");
        }
        
        if(encr && encryptedParts.size() == 0) {
            
            //Check whether its just an encrypted key
            ArrayList list = this.getResults(results, WSConstants.ENCR);
            boolean encrDataFound = false;
            for (Iterator iter = list.iterator(); iter.hasNext();) {
                WSSecurityEngineResult result = (WSSecurityEngineResult) iter.next();
                ArrayList dataRefURIs = (ArrayList)result.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
                if ( dataRefURIs != null && dataRefURIs.size() != 0) {
                    encrDataFound = true;
                }
            }
            //TODO check whether the encrptedDataFound is an UsernameToken
            if(encrDataFound && !isUsernameTokenPresent(data)) {
                //Unexpected encryption
                throw new RampartException("unexprectedEncryptedPart");
            }
        } else if(!encr && encryptedParts.size() > 0) {
            
            //required signature missing
            throw new RampartException("encryptionMissing");
        }
    }

    /**
     * @param data
     * @param results
     */
    private void validateSupportingTokens(ValidatorData data, Vector results) 
    throws RampartException {
        
        //Check for UsernameToken
        RampartPolicyData rpd = data.getRampartMessageData().getPolicyData();
        SupportingToken suppTok = rpd.getSupportingTokens();
        handleSupportingTokens(results, suppTok);
        SupportingToken signedSuppToken = rpd.getSignedSupportingTokens();
        handleSupportingTokens(results, signedSuppToken);
        SupportingToken signedEndSuppToken = rpd.getSignedEndorsingSupportingTokens();
        handleSupportingTokens(results, signedEndSuppToken);
        SupportingToken endSuppToken = rpd.getEndorsingSupportingTokens();
        handleSupportingTokens(results, endSuppToken);
    }

    /**
     * @param results
     * @param suppTok
     * @throws RampartException
     */
    private void handleSupportingTokens(Vector results, SupportingToken suppTok) throws RampartException {
        
        if(suppTok == null) {
            return;
        }
        
        ArrayList tokens = suppTok.getTokens();
        for (Iterator iter = tokens.iterator(); iter.hasNext();) {
            Token token = (Token) iter.next();
            if(token instanceof UsernameToken) {
                //Check presence of a UsernameToken
                WSSecurityEngineResult utResult = WSSecurityUtil.fetchActionResult(results, WSConstants.UT);
                if(utResult == null) {
                    throw new RampartException("usernameTokenMissing");
                }
                
            } else if ( token instanceof IssuedToken ) {
                //TODO is is enough to check for ST_UNSIGNED results ??
                WSSecurityEngineResult samlResult = WSSecurityUtil.fetchActionResult(results, WSConstants.ST_UNSIGNED);
                if(samlResult == null) {
                    throw new RampartException("samlTokenMissing");
                }
            } else if ( token instanceof X509Token) {
                WSSecurityEngineResult x509Result = WSSecurityUtil.fetchActionResult(results, WSConstants.BST);
                if(x509Result == null) {
                    throw new RampartException("binaryTokenMissing");
                }
            }
        }
    }
    
    
    

    /**
     * @param data
     * @param results
     */
    private void validateProtectionOrder(ValidatorData data, Vector results) 
    throws RampartException {
        
        String protectionOrder = data.getRampartMessageData().getPolicyData().getProtectionOrder();
        ArrayList sigEncrActions = this.getSigEncrActions(results);
        
        if(sigEncrActions.size() < 2) {
            //There are no results to COMPARE
            return;
        }
        
        boolean sigNotPresent = true; 
        boolean encrNotPresent = true;
        
        for (Iterator iter = sigEncrActions.iterator(); iter.hasNext();) {
            Integer act = (Integer) iter.next();
            if(act.intValue() == WSConstants.SIGN) {
                sigNotPresent = false;
            } else if(act.intValue() == WSConstants.ENCR) {
                encrNotPresent = false;
            }
        }
        
        // Only one action is present, so there is no order to check
        if ( sigNotPresent || encrNotPresent ) {
            return;
        }
        
        
        boolean done = false;
        if(Constants.SIGN_BEFORE_ENCRYPTING.equals(protectionOrder)) {
                        
            boolean sigFound = false;
            for (Iterator iter = sigEncrActions.iterator(); 
                iter.hasNext() || !done;) {
                Integer act = (Integer) iter.next();
                if(act.intValue() == WSConstants.ENCR && ! sigFound ) {
                    // We found ENCR and SIGN has not been found - break and fail
                    break;
                }
                if(act.intValue() == WSConstants.SIGN) {
                    sigFound = true;<commit_msg>rampart-policy related changes to support WS Security Policy 1.2<commit_after>/*
 * Copyright 2004,2005 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.rampart;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.rampart.policy.RampartPolicyData;
import org.apache.rampart.util.RampartUtil;
import org.apache.ws.secpolicy.SPConstants;
import org.apache.ws.secpolicy.model.HttpsToken;
import org.apache.ws.secpolicy.model.IssuedToken;
import org.apache.ws.secpolicy.model.SignedEncryptedParts;
import org.apache.ws.secpolicy.model.SupportingToken;
import org.apache.ws.secpolicy.model.Token;
import org.apache.ws.secpolicy.model.UsernameToken;
import org.apache.ws.secpolicy.model.X509Token;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.WSEncryptionPart;
import org.apache.ws.security.WSSecurityEngineResult;
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.message.token.Timestamp;
import org.apache.ws.security.util.WSSecurityUtil;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import java.math.BigInteger;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;

public class PolicyBasedResultsValidator {
    
    private static Log log = LogFactory.getLog(PolicyBasedResultsValidator.class);
    
    public void validate(ValidatorData data, Vector results) 
    throws RampartException {
        
        RampartMessageData rmd = data.getRampartMessageData();
        
        RampartPolicyData rpd = rmd.getPolicyData();
        
        //If there's Security policy present and no results 
        //then we should throw an error
        if(rpd != null && results == null) {
            throw new RampartException("noSecurityResults");
        }
        
        //Check presence of timestamp
        WSSecurityEngineResult tsResult = null;
        if(rpd.isIncludeTimestamp()) {
            tsResult = 
                WSSecurityUtil.fetchActionResult(results, WSConstants.TS);
            if(tsResult == null) {
                throw new RampartException("timestampMissing");
            }
            
        }
        
        //sig/encr
        Vector encryptedParts = RampartUtil.getEncryptedParts(rmd);
        if(rpd.isSignatureProtection() && isSignatureRequired(rmd)) {
            encryptedParts.add(new WSEncryptionPart(WSConstants.SIG_LN, 
                    WSConstants.SIG_NS, "Element"));
        }
        
        Vector signatureParts = RampartUtil.getSignedParts(rmd);

        //Timestamp is not included in sig parts
        if(rpd.isIncludeTimestamp() && !rpd.isTransportBinding()) {
            signatureParts.add(new WSEncryptionPart("timestamp"));
        }
        
        if(!rmd.isInitiator()) {
                        
            //Just an indicator for EndorsingSupportingToken signature
            SupportingToken endSupportingToken = rpd.getEndorsingSupportingTokens();
            if(endSupportingToken !=  null) {
                SignedEncryptedParts endSignedParts = endSupportingToken.getSignedParts();
                if((endSignedParts != null && 
                        (endSignedParts.isBody() || 
                                endSignedParts.getHeaders().size() > 0)) ||
                                rpd.isIncludeTimestamp()) {
                    signatureParts.add(
                            new WSEncryptionPart("EndorsingSupportingTokens"));
                }
            }
            //Just an indicator for SignedEndorsingSupportingToken signature
            SupportingToken sgndEndSupportingToken = rpd.getSignedEndorsingSupportingTokens();
            if(sgndEndSupportingToken != null) {
                SignedEncryptedParts sgndEndSignedParts = sgndEndSupportingToken.getSignedParts();
                if((sgndEndSignedParts != null && 
                        (sgndEndSignedParts.isBody() || 
                                sgndEndSignedParts.getHeaders().size() > 0)) || 
                                rpd.isIncludeTimestamp()) {
                    signatureParts.add(
                            new WSEncryptionPart("SignedEndorsingSupportingTokens"));
                }
            }
        }
        
        validateEncrSig(data,encryptedParts, signatureParts, results);
        
        if(!rpd.isTransportBinding()) {
            validateProtectionOrder(data, results);
        }  
        
        if(rpd.isTransportBinding() && !rmd.isInitiator()){
            if (rpd.getTransportToken() instanceof HttpsToken) {
                String incomingTransport = rmd.getMsgContext().getIncomingTransportName();
                if(!incomingTransport.equals(org.apache.axis2.Constants.TRANSPORT_HTTPS)){
                    throw new RampartException("invalidTransport", 
                            new String[]{incomingTransport});
                }
            }
        }
        
        validateEncryptedParts(data, encryptedParts, results);

        validateSignedPartsHeaders(data, signatureParts, results);

        //Supporting tokens
        if(!rmd.isInitiator()) {
            validateSupportingTokens(data, results);
        }
        
        /*
         * Now we can check the certificate used to sign the message. In the
         * following implementation the certificate is only trusted if either it
         * itself or the certificate of the issuer is installed in the keystore.
         * 
         * Note: the method verifyTrust(X509Certificate) allows custom
         * implementations with other validation algorithms for subclasses.
         */

        // Extract the signature action result from the action vector
        WSSecurityEngineResult actionResult = WSSecurityUtil.fetchActionResult(
                results, WSConstants.SIGN);

        if (actionResult != null) {
            X509Certificate returnCert = (X509Certificate) actionResult
                    .get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);

            if (returnCert != null) {
                if (!verifyTrust(returnCert, rmd)) {
                    throw new RampartException ("trustVerificationError");
                }
            }
        }
        
        /*
         * Perform further checks on the timestamp that was transmitted in the
         * header. 
         * In the following implementation the timestamp is valid if :
         * Timestamp->Created < 'now' < Timestamp->Expires (Last test already handled by WSS4J)
         * 
         * Note: the method verifyTimestamp(Timestamp) allows custom
         * implementations with other validation algorithms for subclasses.
         */

        // Extract the timestamp action result from the action vector
        actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.TS);

        if (actionResult != null) {
            Timestamp timestamp = (Timestamp) actionResult
                    .get(WSSecurityEngineResult.TAG_TIMESTAMP);

            if (timestamp != null) {
                if (!verifyTimestamp(timestamp, rmd)) {
                    throw new RampartException("cannotValidateTimestamp");
                }
            }
        }
    }
    
    /**
     * @param encryptedParts
     * @param signatureParts
     */
    private void validateEncrSig(ValidatorData data,Vector encryptedParts, Vector signatureParts, Vector results) 
    throws RampartException {
        ArrayList actions = getSigEncrActions(results);
        boolean sig = false; 
        boolean encr = false;
        for (Iterator iter = actions.iterator(); iter.hasNext();) {
            Integer act = (Integer) iter.next();
            if(act.intValue() == WSConstants.SIGN) {
                sig = true;
            } else if(act.intValue() == WSConstants.ENCR) {
                encr = true;
            }
        }
        
        RampartPolicyData rpd = data.getRampartMessageData().getPolicyData();
        
        SupportingToken sgndSupTokens = rpd.getSignedSupportingTokens();
        SupportingToken sgndEndorSupTokens = rpd.getSignedEndorsingSupportingTokens();
        
        if(sig && signatureParts.size() == 0 
                && sgndSupTokens.getTokens().size() == 0
                 && sgndEndorSupTokens.getTokens().size() == 0) {
            
            //Unexpected signature
            throw new RampartException("unexprectedSignature");
        } else if(!sig && signatureParts.size() > 0) {
            
            //required signature missing
            throw new RampartException("signatureMissing");
        }
        
        if(encr && encryptedParts.size() == 0) {
            
            //Check whether its just an encrypted key
            ArrayList list = this.getResults(results, WSConstants.ENCR);
            boolean encrDataFound = false;
            for (Iterator iter = list.iterator(); iter.hasNext();) {
                WSSecurityEngineResult result = (WSSecurityEngineResult) iter.next();
                ArrayList dataRefURIs = (ArrayList)result.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
                if ( dataRefURIs != null && dataRefURIs.size() != 0) {
                    encrDataFound = true;
                }
            }
            //TODO check whether the encrptedDataFound is an UsernameToken
            if(encrDataFound && !isUsernameTokenPresent(data)) {
                //Unexpected encryption
                throw new RampartException("unexprectedEncryptedPart");
            }
        } else if(!encr && encryptedParts.size() > 0) {
            
            //required signature missing
            throw new RampartException("encryptionMissing");
        }
    }

    /**
     * @param data
     * @param results
     */
    private void validateSupportingTokens(ValidatorData data, Vector results) 
    throws RampartException {
        
        //Check for UsernameToken
        RampartPolicyData rpd = data.getRampartMessageData().getPolicyData();
        SupportingToken suppTok = rpd.getSupportingTokens();
        handleSupportingTokens(results, suppTok);
        SupportingToken signedSuppToken = rpd.getSignedSupportingTokens();
        handleSupportingTokens(results, signedSuppToken);
        SupportingToken signedEndSuppToken = rpd.getSignedEndorsingSupportingTokens();
        handleSupportingTokens(results, signedEndSuppToken);
        SupportingToken endSuppToken = rpd.getEndorsingSupportingTokens();
        handleSupportingTokens(results, endSuppToken);
    }

    /**
     * @param results
     * @param suppTok
     * @throws RampartException
     */
    private void handleSupportingTokens(Vector results, SupportingToken suppTok) throws RampartException {
        
        if(suppTok == null) {
            return;
        }
        
        ArrayList tokens = suppTok.getTokens();
        for (Iterator iter = tokens.iterator(); iter.hasNext();) {
            Token token = (Token) iter.next();
            if(token instanceof UsernameToken) {
                //Check presence of a UsernameToken
                WSSecurityEngineResult utResult = WSSecurityUtil.fetchActionResult(results, WSConstants.UT);
                if(utResult == null) {
                    throw new RampartException("usernameTokenMissing");
                }
                
            } else if ( token instanceof IssuedToken ) {
                //TODO is is enough to check for ST_UNSIGNED results ??
                WSSecurityEngineResult samlResult = WSSecurityUtil.fetchActionResult(results, WSConstants.ST_UNSIGNED);
                if(samlResult == null) {
                    throw new RampartException("samlTokenMissing");
                }
            } else if ( token instanceof X509Token) {
                WSSecurityEngineResult x509Result = WSSecurityUtil.fetchActionResult(results, WSConstants.BST);
                if(x509Result == null) {
                    throw new RampartException("binaryTokenMissing");
                }
            }
        }
    }
    
    
    

    /**
     * @param data
     * @param results
     */
    private void validateProtectionOrder(ValidatorData data, Vector results) 
    throws RampartException {
        
        String protectionOrder = data.getRampartMessageData().getPolicyData().getProtectionOrder();
        ArrayList sigEncrActions = this.getSigEncrActions(results);
        
        if(sigEncrActions.size() < 2) {
            //There are no results to COMPARE
            return;
        }
        
        boolean sigNotPresent = true; 
        boolean encrNotPresent = true;
        
        for (Iterator iter = sigEncrActions.iterator(); iter.hasNext();) {
            Integer act = (Integer) iter.next();
            if(act.intValue() == WSConstants.SIGN) {
                sigNotPresent = false;
            } else if(act.intValue() == WSConstants.ENCR) {
                encrNotPresent = false;
            }
        }
        
        // Only one action is present, so there is no order to check
        if ( sigNotPresent || encrNotPresent ) {
            return;
        }
        
        
        boolean done = false;
        if(SPConstants.SIGN_BEFORE_ENCRYPTING.equals(protectionOrder)) {
                        
            boolean sigFound = false;
            for (Iterator iter = sigEncrActions.iterator(); 
                iter.hasNext() || !done;) {
                Integer act = (Integer) iter.next();
                if(act.intValue() == WSConstants.ENCR && ! sigFound ) {
                    // We found ENCR and SIGN has not been found - break and fail
                    break;
                }
                if(act.intValue() == WSConstants.SIGN) {
                    sigFound = true;
{'fraction_non_alphanumeric': 0.08596509635225405, 'fraction_numerical': 0.003777148253068933, 'mean_word_length': 2.020386606105419, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, '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': '3232667', 'n_tokens_mistral': 7509, 'n_tokens_neox': 7125, 'n_words': 1635}