Как правильно отформатировать конверт сообщения SOAP с помощью пользовательского SOAPHandler

У меня есть класс, который реализует интерфейс SOAPHandler. HandleMessage определяется как:

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;
}

Это генерирует следующее сообщение:

<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>

Проблема в том, что мне нужно сгенерировать сообщение в следующем формате:

<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>

Атрибут "mustUnderstand" не имеет префикса soapenv, тэг sse: Security закрывается сразу вместо того, чтобы другие тэги были дочерними, а имя пользователя неправильно форматировалось как

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

, Как правильно отформатировать сообщение, используя методы SOAPElement? Самая важная вещь, которую мне нужно знать, - это как правильно размещать теги внутри тега Security и как правильно форматировать теги username / password.

Я пробовал разные комбинации методов addHeaderElement и addChildElement, но я не могу правильно отформатировать его, и javadocs не дают достаточно подробной информации о том, что они будут генерировать.

3 ответа

Это взято из моего рабочего обработчика. Надеюсь, это работает для вас.

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);
}

Просто разместите мое решение, если кому-то все еще интересно -

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");

В этом коде достаточно проблем, и я думаю, что это тролль, но вот начало:

Линия:

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

должен прочесть:

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

далее вместо:

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

наверное:

secHdrElement.setMustUnderstand(true);

а также

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

должно быть что-то вроде:

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

и так далее...

Другие вопросы по тегам