mustUnderstand attribute is added to SOAPEnvelope (element) before transmission 
e.g.
            env.addAttribute(Constants.URI_SOAP11_ENV, "mustUnderstand", "1");

here is the entire file:
/*
 * The Apache Software License, Version 1.1
 * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Axis" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apa...@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

package samples.security;

import org.apache.axis.Constants;
import org.apache.axis.Message;
import org.apache.axis.MessageContext;
import org.apache.axis.client.AxisClient;
import org.apache.axis.configuration.NullProvider;
import org.apache.axis.encoding.SerializationContext;
import org.apache.axis.encoding.SerializationContext;
import org.apache.axis.encoding.DeserializationContext;
import org.apache.axis.message.SOAPEnvelope;
import org.apache.axis.message.SOAPHeaderElement;
import org.apache.axis.utils.Mapping;
import org.apache.axis.utils.Messages;
import org.apache.axis.utils.XMLUtils;
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.signature.XMLSignature;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;

import java.io.FileInputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;


public class SignedSOAPEnvelope extends SOAPEnvelope {
    static String SOAPSECNS = 
"http://schemas.xmlsoap.org/soap/security/2000-12";;
    static String SOAPSECprefix = "SOAP-SEC";

    static String keystoreType = "JKS";
    static String keystoreFile = "keystore.jks";
    static String keystorePass = "xmlsecurity";
    static String privateKeyAlias = "test";
    static String privateKeyPass = "xmlsecurity";
    static String certificateAlias = "test";
    private MessageContext msgContext;

    static {
        org.apache.xml.security.Init.init();
    }

    public SignedSOAPEnvelope(MessageContext msgContext, SOAPEnvelope env, 
String baseURI, String keystoreFile) {
        this.msgContext = msgContext;
        init(env, baseURI, keystoreFile);
    }

    public SignedSOAPEnvelope(SOAPEnvelope env, String baseURI) {
        init(env, baseURI, keystoreFile);
    }

    private void init(SOAPEnvelope env, String baseURI, String keystoreFile) {
        try {
            System.out.println("Beginning Client signing...");
            env.addMapping(new Mapping(SOAPSECNS, SOAPSECprefix));
            env.addAttribute(Constants.URI_SOAP11_ENV, "actor", "some-uri");
            env.addAttribute(Constants.URI_SOAP11_ENV, "mustUnderstand", "1");

//create a Signature element
            SOAPHeaderElement header = 
                new SOAPHeaderElement(XMLUtils.StringToElement(SOAPSECNS,
                                                               "Signature",
                                                               ""));
//add the SOAPHeaderElement to SOAPEnvelope
            env.addHeader(header);

/get the Document
            Document doc = getSOAPEnvelopeAsDocument(env, msgContext);

//keystoreType is invariably JKS
            KeyStore ks = KeyStore.getInstance(keystoreType);
//get a handle on the keyStore file
            FileInputStream fis = new FileInputStream(keystoreFile);
//makesure keyStore.pass corresponds to public key password
            ks.load(fis, keystorePass.toCharArray());
//get the privateKey from keystore file
            PrivateKey privateKey = (PrivateKey) ks.getKey(privateKeyAlias,
                    privateKeyPass.toCharArray());
//get the first Header element
            Element soapHeaderElement = (Element) ((Element) 
doc.getFirstChild()).getElementsByTagNameNS("*", "Header").item(0);
//get the SignatureElement 
            Element soapSignatureElement = (Element) 
soapHeaderElement.getElementsByTagNameNS("*", "Signature").item(0);

//Id attribute creation
            Element body = 
(Element)doc.getElementsByTagNameNS("http://schemas.xmlsoap.org/soap/envelope/";,
 "Body").item(0);
//id will be 'Body'
            body.setAttribute("Id", "Body");

//Signture will use DSA algorithm
            XMLSignature sig = new XMLSignature(doc, baseURI,
                    XMLSignature.ALGO_ID_SIGNATURE_DSA);

//append XMLSignature's element to soapSignatureElement
            soapSignatureElement.appendChild(sig.getElement());
//add a Body to XMLSignature
            sig.addDocument("#Body");

//with the supplied alias get the X.509 cert
            X509Certificate cert =
                    (X509Certificate) ks.getCertificate(certificateAlias);

//add the cert to XMLSignature
            sig.addKeyInfo(cert);
//add the cert publicKey to XMLSignature
            sig.addKeyInfo(cert.getPublicKey());
//sign XMLSignature with privateKey
            sig.sign(privateKey);

//Canonicalise but keep the comments
            Canonicalizer c14n = 
Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS);
//canonicalize the document and deliver back canonicalMessage
            byte[] canonicalMessage = c14n.canonicalizeSubtree(doc);
//ingest the message into is InputStream
            InputSource is = new InputSource(new 
java.io.ByteArrayInputStream(canonicalMessage));
            DeserializationContext dser = null;
            if (msgContext == null) 
            {
//create new AxisClient
                AxisClient tmpEngine = new AxisClient(new NullProvider());
//create a MessageContext for new AxisClient
                msgContext = new MessageContext(tmpEngine);
            }
//desrialize msgContext into object dser
            dser = new DeserializationContext(is, msgContext,
                    Message.REQUEST, this);
//parse it
            dser.parse();
            System.out.println("Client signing complete.");
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.toString());
        }
    }

    private Document getSOAPEnvelopeAsDocument(SOAPEnvelope env, MessageContext 
msgContext)
            throws Exception {
        StringWriter writer = new StringWriter();
        SerializationContext serializeContext = new 
SerializationContext(writer, msgContext);
        env.output(serializeContext);
        writer.close();

        Reader reader = new StringReader(writer.getBuffer().toString());
        Document doc = XMLUtils.newDocument(new InputSource(reader));
        if (doc == null)
            throw new Exception(
                    Messages.getMessage("noDoc00", 
writer.getBuffer().toString()));
        return doc;
    }
}
/*
when the response is received by the client the responseMessage is assigned to 
msg
and the env is acquired by getSOAPEnvelope
you can then env.getAttribute("mustUnderstand");
*/
 
            Options opts = new Options(args);
            Service service = new Service();
            Call call = (Call) service.createCall();
            call.setTargetEndpointAddress(new java.net.URL(opts.getURL()));

            SOAPEnvelope env = new SOAPEnvelope();
            SOAPBodyElement sbe = new 
SOAPBodyElement(XMLUtils.StringToElement("http://localhost:8080/TestService";, 
"testMethod", ""));

            env.addBodyElement(sbe);

            Envelope env = new SignedSOAPEnvelope(env, "http://xml-security";);
//send to server
            call.invoke(env);

//get the MessageContext coming back
            org.apache.axis.MessageContext mc = call.getMessageContext();
            System.out.println("\n============= Response ==============");

//get the responseMessage
            Message msg = mc.getResponseMessage();
            if (msg == null)
            {
               System.out.println("the Response is null from TestService 
operation=testMethod");
                return;
            }
            SOAPEnvelope env = msg.getSOAPEnvelope();
            String mustUnderstand= env.getAttribute("mustUnderstand");          
  
...........

mustUnderstand attribute indicates the element MUST be processed
http://www.w3schools.com/soap/soap_header.asp

HTH
Martin Gainty 
______________________________________________ 
Verzicht und Vertraulichkeitanmerkung/Note de déni et de confidentialité
 Diese Nachricht ist vertraulich. Sollten Sie nicht der vorgesehene Empfaenger 
sein, so bitten wir hoeflich um eine Mitteilung. Jede unbefugte Weiterleitung 
oder Fertigung einer Kopie ist unzulaessig. Diese Nachricht dient lediglich dem 
Austausch von Informationen und entfaltet keine rechtliche Bindungswirkung. 
Aufgrund der leichten Manipulierbarkeit von E-Mails koennen wir keine Haftung 
fuer den Inhalt uebernehmen.
Ce message est confidentiel et peut être privilégié. Si vous n'êtes pas le 
destinataire prévu, nous te demandons avec bonté que pour satisfaire informez 
l'expéditeur. N'importe quelle diffusion non autorisée ou la copie de ceci est 
interdite. Ce message sert à l'information seulement et n'aura pas n'importe 
quel effet légalement obligatoire. Étant donné que les email peuvent facilement 
être sujets à la manipulation, nous ne pouvons accepter aucune responsabilité 
pour le contenu fourni.


From: mpettig...@ewise.com
To: axis-u...@ws.apache.org
Subject: Must Understand check failed for header 
http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd
 : Security
Date: Mon, 27 Jun 2011 14:57:44 -0600



Hello; Does anyone have a solution for this problem?   It seems to be a 
long-standing issue. Must Understand check failed for header 
http://.........secext-1.0.xsd : Security It occurs in the client when 
receiving a response from a service.  The “mustUnderstand” flag is set in the 
response. The client sends a UsernameToken which appears to be accepted by the 
server.  The server sends back a response which includes a Security header and 
Timestamp – and the “mustUnderstand” flag. I am unclear how the client is 
supposed to process the response with the security header.  I have tried 
writing a client-side handler for the Security header, but it never seems to 
engage.  The examples I have found seem to be incomplete in crucial details.  
-Mike Pettigrew                                     

Reply via email to