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