2013-01-25 30 views
17

cerco di richiamare servizio web HTTPS SOAP tramite codice Java:Come aggiungere un'intestazione alla richiesta SOAP?

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

Ma ottenere un'eccezione:

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

Quando ho analizzato Campione corretta ho deciso che deve contenere intestazione:

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

Quindi, come aggiungere questa intestazione alla mia richiesta SOAP?

risposta

35

io personalmente aggiungere due classi: HeaderHandler e 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."); 
} 
} 

E

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

Nella classe HeaderHandler, è possibile aggiungere credenziali necessarie. Per utilizzarli, infine:

HeaderHandlerResolver handlerResolver = new HeaderHandlerResolver(); 
service.setHandlerResolver(handlerResolver); 
+0

Questo era esattamente quello che stavo cercando. Grazie per il tuo esauriente esempio. –

+0

siete i benvenuti –

+0

grazie mille. hai salvato tutto il mio futuro giorno! –

5

Ho seguito i passi menzionati da @LaabidiRaissi. Il codice funziona bene ma non aggiunge mai l'elemento di sicurezza sotto l'intestazione. L'ho confermato stampando il messaggio SOAP in uscita a System.out. Dopo una ricerca approfondita, ho trovato che il messaggio SOAP deve essere salvato in modo esplicito per riflettere l'intestazione del messaggio aggiornato.

soapMessage.saveChanges(); 

Per ulteriori riferimento - Check this link

+0

Il codice della risposta di @ Laabidi ha funzionato per me con Java 7 e tomcat 7. Dopo l'aggiornamento a Java 8 e tomcat 8, soapMessage.saveChanges() è necessario. – Hok

1

È inoltre possibile utilizzare Apache wss4j di aggiungere facilmente l'intestazione e anche di criptare la password.

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

ed è necessario aggiornare la vostra richiesta in questo modo:

// 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 Dipendenza:

 <dependency> 
      <groupId>org.apache.ws.security</groupId> 
      <artifactId>wss4j</artifactId> 
      <version>1.6.19</version> 
     </dependency> 
Problemi correlati