Как добавить заголовок в запрос SOAP?

17

Я пытаюсь вызвать веб-службу HTTPS SOAP через java-код:

    URL url = new URL("https://somehost:8181/services/"SomeService?wsdl");
    QName qname = new QName("http://services.somehost.com/", "SomeService");
    Service service = Service.create(url, qname);
    SomeService port = service.getPort(SomeService .class);
    port.doSomething();

Но получить исключение:

threw an unexpected exception: javax.xml.ws.soap.SOAPFaultException: Security Requirements not met - No Security header in message

Когда я проанализировал правильный образец запроса, я решил, что он должен содержать заголовок:

 <S:Header>
  <To xmlns="http://www.w3.org/2005/08/addressing">http://somehost:8181/services/SomeService</To>
  <Action xmlns="http://www.w3.org/2005/08/addressing">https://somehost:8181/services/"SomeService/doSomethingRequest</Action>
  <ReplyTo xmlns="http://www.w3.org/2005/08/addressing">
     <Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
  </ReplyTo>
  <MessageID xmlns="http://www.w3.org/2005/08/addressing">uuid:3428539e-d645-72ae-adc0-5423c1e68942</MessageID>
  <wsse:Security S:mustUnderstand="true">
     <wsu:Timestamp wsu:Id="_1" xmlns:ns14="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512" xmlns:ns13="http://schemas.xmlsoap.org/soap/envelope/">
        <wsu:Created>2013-01-15T16:36:30Z</wsu:Created>
        <wsu:Expires>2014-01-15T14:06:30Z</wsu:Expires>
     </wsu:Timestamp>
  </wsse:Security>

Итак, как добавить этот заголовок в мой запрос SOAP?

    
задан kostepanych 25.01.2013 в 14:40
источник

3 ответа

35

Я лично добавляю два класса: HeaderHandler и HeaderHandlerResolver:

import java.util.HashSet;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;


public class HeaderHandler implements SOAPHandler<SOAPMessageContext> {

public boolean handleMessage(SOAPMessageContext smc) {

    Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

    if (outboundProperty.booleanValue()) {

        SOAPMessage message = smc.getMessage();

        try {

            SOAPEnvelope envelope = smc.getMessage().getSOAPPart().getEnvelope();
            SOAPHeader header = envelope.addHeader();

            SOAPElement security =
                    header.addChildElement("Security", "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");



            SOAPElement usernameToken =
                    security.addChildElement("UsernameToken", "wsse");
            usernameToken.addAttribute(new QName("xmlns:wsu"), "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

            SOAPElement username =
                    usernameToken.addChildElement("Username", "wsse");
            username.addTextNode("test");

            SOAPElement password =
                    usernameToken.addChildElement("Password", "wsse");
            password.setAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
           password.addTextNode("test321");

            //Print out the outbound SOAP message to System.out
            message.writeTo(System.out);
            System.out.println("");

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

    } else {
        try {

            //This handler does nothing with the response from the Web Service so
            //we just print out the SOAP message.
            SOAPMessage message = smc.getMessage();
            message.writeTo(System.out);
            System.out.println("");

        } catch (Exception ex) {
            ex.printStackTrace();
        } 
    }


    return outboundProperty;

}

public Set getHeaders() {
    // The code below is added on order to invoke Spring secured WS.
    // Otherwise,
    // http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd
    // won't be recognised 
    final QName securityHeader = new QName(
            "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
            "Security", "wsse");

    final HashSet headers = new HashSet();
    headers.add(securityHeader);

    return headers;
}

public boolean handleFault(SOAPMessageContext context) {
    //throw new UnsupportedOperationException("Not supported yet.");
    return true;
}

public void close(MessageContext context) {
//throw new UnsupportedOperationException("Not supported yet.");
}
}

и

import java.util.ArrayList;
import java.util.List;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.HandlerResolver;
import javax.xml.ws.handler.PortInfo;


public class HeaderHandlerResolver implements HandlerResolver {

public List<Handler> getHandlerChain(PortInfo portInfo) {
  List<Handler> handlerChain = new ArrayList<Handler>();

  HeaderHandler hh = new HeaderHandler();

  handlerChain.add(hh);

  return handlerChain;
   }
}

В классе HeaderHandler вы можете добавить необходимые учетные данные. Чтобы окончательно использовать их:

HeaderHandlerResolver handlerResolver = new HeaderHandlerResolver();
service.setHandlerResolver(handlerResolver);
    
ответ дан Laabidi Raissi 25.01.2013 в 15:34
источник
5

Я выполнил шаги, упомянутые @LaabidiRaissi. Код работает отлично, но никогда не добавляет элемент безопасности под заголовком. Я подтвердил это, распечатав исходящее сообщение SOAP на System.out. После глубоких исследований я обнаружил, что SOAPMessage необходимо явно сохранить для отражения обновленного заголовка сообщения.

soapMessage.saveChanges();

Для получения дополнительной информации - Проверьте эту ссылку

    
ответ дан mobizen 18.06.2015 в 09:11
источник
0

Вы также можете использовать Apache wss4j, чтобы легко добавлять заголовок, а также шифровать пароль.

import org.apache.ws.security.WSConstants;
import org.apache.ws.security.message.WSSecHeader;
import org.apache.ws.security.message.WSSecUsernameToken;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import java.io.ByteArrayOutputStream;
import java.util.Set;

public class WSSecurityHeaderSOAPHandler implements SOAPHandler<SOAPMessageContext> {


    private final String usernameText;
    private final String passwordText;

    public WSSecurityHeaderSOAPHandler(String usernameText, String passwordText) {
        this.usernameText = usernameText;
        this.passwordText = passwordText;
    }

    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

        if (outboundProperty.booleanValue()) {

            try {
                SOAPMessage soapMessage = context.getMessage();
                soapMessage.removeAllAttachments();

                SOAPPart soappart = soapMessage.getSOAPPart();
                WSSecHeader wsSecHeader = new WSSecHeader();
                wsSecHeader.insertSecurityHeader(soappart);
                WSSecUsernameToken token = new WSSecUsernameToken();
                token.setPasswordType(WSConstants.PASSWORD_DIGEST);
                token.setUserInfo(usernameText, passwordText);
                token.build(soappart, wsSecHeader);

                soapMessage.saveChanges();
            } catch (Exception e) {
                throw new RuntimeException("Error on wsSecurityHandler: " + e.getMessage());
            }

        }

        return true;
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        return false;
    }

    @Override
    public void close(MessageContext context) {

    }

    @Override
    public Set<QName> getHeaders() {
        return null;
    }
}

И вам нужно обновить свой запрос следующим образом:

// This is the block that apply the Ws Security to the request
BindingProvider bindingProvider = (BindingProvider) portType;
List<Handler> handlerChain = new ArrayList<>();
handlerChain.add(new WSSecurityHeaderSOAPHandler("username", "password"));
bindingProvider.getBinding().setHandlerChain(handlerChain);

Зависимость Maven:

        <dependency>
            <groupId>org.apache.ws.security</groupId>
            <artifactId>wss4j</artifactId>
            <version>1.6.19</version>
        </dependency>
    
ответ дан Kamiel Ahmadpour 25.09.2017 в 12:10
источник