How to properly format a SOAP message envelope using a custom SOAPHandler
Asked Answered
S

3

5

I have a class that implements the SOAPHandler interface. The handleMessage is defined as:

public boolean handleMessage(SOAPMessageContext context) {

  SOAPMessage msg = context.getMessage();
  SOAPPart part = msg.getSOAPPart();
  SOAPEnvelope envelope = part.getEnvelope();

  // add namespaces
  SOAPElement envelope.addNamespaceDeclaration("xsd", "http://www.w3.org/2001/XMLSchema");
  envelope.addNamespaceDeclaration("xsi", "http://www.w3.org/2001/XMLSchema-      

  // add the header with additional elements
  Name qname = envelope.createName("Security", "sse", "http://example.com/security.xsd");
  element = envelope.addHeader().addChildElement(qname);

  qname = envelope.createName("mustUnderstand");
  element.addAttribute(qname, "1");

  qname = envelope.createName("UsernameToken", "sse", "http://example.com/user.xsd");
  element = envelope.getHeader().addHeaderElement(qname);
  element.addTextNode("user1");

  qname = envelope.createName("Password");
  element = envelope.getHeader().addHeaderElement(qname);
  element.addTextNode("1234");

}

} catch (Exception e) {
  e.printStackTrace();
}
  return true;
}

This generates the following message:

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <S:Header>
    <sse:Security xmlns:sse="http://example.com/security.xsd" mustUnderstand="1"/>
    <sse:UsernameToken xmlns:sse="http://example.com/user.xsd">user1</sse:UsernameToken>
  </S:Header>
  <S:Body>
    ....The rest of the transaction
  </S:Body>
</S:Envelope>

The problem is I need to generate a message with the following format:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Header>
      <sse:Security soapenv:mustUnderstand="1" xmlns:sse="http://example.com/security.xsd">
         <sse:UsernameToken wsu:Id="UsernameToken-9993341" xmlns:wsu="http://example.com/user.xsd">
            <sse:Username>user1</sse:Username>
            <sse:Password Type="http://example.com/password#PasswordText">1234</sse:Password>
         </sse:UsernameToken>
      </sse:Security>
   </soapenv:Header>
  <soapenv:Body>
    ....The rest of the transaction
  </soapenv:Body>
</soapenv:Envelope>

The "mustUnderstand" attribute doesn't have the soapenv prefix, the sse:Security tag is closed right away instead of having the other tags as children, and the UserName isn't properly formatted as

<sse:Username>user1</sse:Username>

. How can I format the message properly using the SOAPElement methods? The biggest thing I need to know is how to properly next the tags inside of the Security tag and how to have the username/password tags properly formatted.

I've tried different combinations of the addHeaderElement and addChildElement methods, but I can't get it formatted properly and the javadocs don't give enough detail about what they will generate.

Swedenborgian answered 28/7, 2009 at 23:46 Comment(3)
Was there a reason you had this question tagged "C#"?Gewirtz
There was not - I have been using C# for most of my projects, and put it down by default without even thinking about it. Thanks for the updated tags.Swedenborgian
how to call this handler in soap axis2...please provide the information....Cart
S
7

This is taken from my working handler. Hope it works for you.

public static final String WSSE_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
public static final String PASSWORD_TEXT_TYPE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";
public static final String WSSE_SECURITY_LNAME = "Security";
public static final String WSSE_NS_PREFIX = "wsse";

private String username;
private String password;
private boolean mustUnderstand = false;

public boolean handleMessage(SOAPMessageContext messageContext) {
    Object bOutbound = messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
    if (bOutbound == Boolean.TRUE) {
        try {
            if (username != null && username.length() != 0) {
                addSecurityHeader(messageContext);
                LOG.debug("Added security header");
            } else {
                LOG.debug("No username configured thus not adding a security header");
            }
        } catch (Exception e) {
            LOG.error("Exception in handleMessage", e);
            return false;
        }
    }
    return true;
}

private void addSecurityHeader(SOAPMessageContext messageContext) throws SOAPException {
    SOAPFactory sf = SOAPFactory.newInstance();
    SOAPHeader header = messageContext.getMessage().getSOAPPart().getEnvelope().getHeader();
    if (header == null) {
        header = messageContext.getMessage().getSOAPPart().getEnvelope().addHeader();
    }

    Name securityName = sf.createName(WSSE_SECURITY_LNAME, WSSE_NS_PREFIX, WSSE_NS);
    SOAPHeaderElement securityElem = header.addHeaderElement(securityName);
    securityElem.setMustUnderstand(mustUnderstand);

    Name usernameTokenName = sf.createName("UsernameToken", WSSE_NS_PREFIX, WSSE_NS);
    SOAPElement usernameTokenMsgElem = sf.createElement(usernameTokenName);

    Name usernameName = sf.createName("Username", WSSE_NS_PREFIX, WSSE_NS);
    SOAPElement usernameMsgElem = sf.createElement(usernameName);
    usernameMsgElem.addTextNode(username);
    usernameTokenMsgElem.addChildElement(usernameMsgElem);

    Name passwordName = sf.createName("Type", WSSE_NS_PREFIX, WSSE_NS);
    SOAPElement passwordMsgElem = sf.createElement("Password", WSSE_NS_PREFIX, WSSE_NS);

    passwordMsgElem.addAttribute(passwordName, PASSWORD_TEXT_TYPE);
    passwordMsgElem.addTextNode(password);
    usernameTokenMsgElem.addChildElement(passwordMsgElem);

    securityElem.addChildElement(usernameTokenMsgElem);
}
Sitzmark answered 7/12, 2010 at 16:32 Comment(0)
S
3

Just posting my solution if someone is still wondering --

Name name = soapenv.createName("Security", "sse", "URL");
SOAPHeaderElement security = soapenv.getHeader().addHeaderElement(name);
security.setMustUnderstand(true);
SOAPElement usernameToken = security.addChildElement("UsernameToken", "sse");
SOAPElement username = usernameToken.addChildElement("Username", "sse");
username.addTextNode("TestUser");
SOAPElement password = usernameToken.addChildElement("Password", "sse");
password.addTextNode("TestPassword");
Shikari answered 11/12, 2014 at 19:1 Comment(0)
M
-2

There's enough problems in this code that I'm thinking it's a troll, but heres a start:

The line :

element = envelope.addHeader().addChildElement(qname);

should read:

SOAPHeaderElement secHdrElement = envelope.addHeader().addHeaderElement(qname);

next, instead of:

qname = envelope.createName("mustUnderstand");
element.addAttribute(qname, "1");

probably:

secHdrElement.setMustUnderstand(true);

and

qname = envelope.createName("UsernameToken", "sse", "http://example.com/user.xsd");
element = envelope.getHeader().addHeaderElement(qname);
element.addTextNode("user1");

should be something like:

qname = envelope.createName("UsernameToken", "sse", "http://example.com/user.xsd");
element = secHdrElement.addHeaderElement(
          envelope.createName("UsernameToken", "sse", "http://example.com/user.xsd"));

and so on...

Monanthous answered 29/7, 2009 at 5:38 Comment(2)
This code isn't really different than what I had posted, and some of it won't even compile (like the setMustUnderstand). Can you explain how to add the Username and Password tags with the value inside the tags, not as an attribute?Swedenborgian
Tai - Regarding setMustUnderstand() - it's a method on SOAPHeaderElement (my example) but not on SOAPElement (your example), which is one of the differences in our code... Regarding creating proper DOM for the security header - in your code you first need to create a 'UserName' element as a child of 'UserNameToken', then you add a TextNode child to the UserName token. Likewise you will create a 'Password' element child of 'UserNameToken' and then add a text node to it. Hope this helps.Monanthous

© 2022 - 2024 — McMap. All rights reserved.