JAX-WS - adding SOAP Headers

j'essaie de créer un client autonome pour consommer certains services web. Je dois ajouter mon nom d'utilisateur et mot de passe à L'en-tête SOAP. J'ai essayé d'ajouter les informations d'identification comme suit:

OTSWebSvcsService service = new OTSWebSvcsService();
OTSWebSvcs port = service.getOTSWebSvcs();

BindingProvider prov = (BindingProvider)port;
prov.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "myusername");
prov.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "mypassword");

...

Lorsque j'appelle une méthode sur le service que j'ai l'exception suivante:

com.ibm.wsspi.wssecurity.SoapSecurityException: WSEC5048E: One of "SOAP Header" elements required.

Qu'est-ce que je fais de mal? Comment ajouter ces propriétés à L'en-tête SOAP?

édité: j'utilisais JAX-WS 2.1 inclus dans JDK6. J'utilise maintenant JAX-WS 2.2. Je reçois maintenant la exception suivante:

com.ibm.wsspi.wssecurity.SoapSecurityException: WSEC5509E: A security token whose type is [http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken] is required.

comment créer ce token?

29
demandé sur Pascal Thivent 2010-02-24 03:57:22

8 réponses

pas sûr à 100% car la question manque quelques détails mais si vous utilisez JAX-WS RI, alors jetez un oeil à ajouter des en-têtes SOAP lors de l'envoi de requêtes:

la façon portable de faire ceci est que vous créez un SOAPHandler et le désordre avec SAAJ, mais le RI fournit une meilleure façon de le faire.

lorsque vous créez un mandataire ou une expédition objet, ils mettent en œuvre BindingProvider interface. Lorsque vous utilisez le JAX-WS RI, vous pouvez downcast à WSBindingProvider qui définit une quelques méthodes fournies uniquement par le JAX-WS RI.

Cette interface vous permet de définir un nombre arbitraire de l'en-Tête de l'objet, chacune représentant une tête de savon. Vous pouvez la mettre en œuvre sur votre propre si vous vous le voulez, mais vous en utiliseriez probablement un les méthodes d'usine définies sur Headers classe pour en créer un.

import com.sun.xml.ws.developer.WSBindingProvider;

HelloPort port = helloService.getHelloPort();  // or something like that...
WSBindingProvider bp = (WSBindingProvider)port;

bp.setOutboundHeader(
  // simple string value as a header, like <simpleHeader>stringValue</simpleHeader>
  Headers.create(new QName("simpleHeader"),"stringValue"),
  // create a header from JAXB object
  Headers.create(jaxbContext,myJaxbObject)
);

mettez à jour votre code en conséquence et réessayez. Et si vous n'utilisez pas JAX-WS RI, veuillez mettre à jour votre question et fournir plus d'informations de contexte.

mise à Jour: il semble que le service web que vous voulez appeler est sécurisé avec WS-Security/UsernameTokens. C'est un peu différent de votre question initiale. Quoi qu'il en soit, pour configurer votre client pour envoyer des noms d'utilisateurs et des mots de passe, je suggère de vérifier le Grand post mise en œuvre du profil D'utilisateur de WS-Security Usernametook pour les services web métropolitains (passer à l'étape 4). Utiliser NetBeans pour cette étape pourrait faciliter les choses beaucoup.

26
répondu Pascal Thivent 2018-03-13 09:30:15

Désolé pour mon mauvais anglais. Les données peuvent être transférées dans l'en-tête SOAP (JaxWS) en utilisant @WebParam (header = true) comme ceci:

@WebMethod(operationName = "SendRequest", action = "http://abcd.ru/")
@Oneway
public void sendRequest(
    @WebParam(name = "Message", targetNamespace = "http://abcd.ru/", partName = "Message")
    Data message,
    @WebParam(name = "ServiceHeader", targetNamespace = "http://abcd.ru/", header = true, partName = "ServiceHeader")
    Header serviceHeader);

Si Vous voulez générer du client avec des en-Têtes SOAP, besoin d'utiliser -XadditionalHeaders comme ça:

wsimport -keep -Xnocompile -XadditionalHeaders -Xdebug http://12.34.56.78:8080/TestHeaders/somewsdl?wsdl -d /home/evgeny/DEVELOPMENT/JAVA/gen

Si vous n'avez pas besoin @Oneway service web, vous pouvez utiliser le Titulaire de ce genre:

@WebMethod(operationName = "SendRequest", action = "http://abcd.ru/")
public void sendRequest(
    @WebParam(name = "Message", targetNamespace = "http://abcd.ru/", partName = "Message")
    Data message,
    @WebParam(name = "ServiceHeader", targetNamespace = "http://abcd.ru/", header = true, partName = "ServiceHeader")
    Holder<Header> serviceHeader);
26
répondu Evgeny 2012-12-09 10:42:15
    <dependency>
        <groupId>com.sun.xml.ws</groupId>
        <artifactId>jaxws-rt</artifactId>
        <version>{currentversion}/version>
    </dependency>

cela vous fournit la classe com.sun.xml.ws.developer.WSBindingProvider.

https://mvnrepository.com/artifact/com.sun.xml.ws/jaxws-rt

7
répondu cristianoms 2016-08-01 18:50:14

utilisez maven et le plugin jaxws-maven-plugin. cela générera un client de service web. Assurez-vous que vous êtes réglage de l' xadditionalHeaders pour vrai. Cela générera des méthodes avec des entrées d'en-tête.

2
répondu Eduardo Dennis 2016-03-11 18:46:59

j'ajoute cette réponse parce qu'aucun des autres n'a travaillé pour moi.

j'ai dû ajouter un En-Tête Handler Proxy:

import java.util.Set;
import java.util.TreeSet;

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

public class SOAPHeaderHandler implements SOAPHandler<SOAPMessageContext> {

    private final String authenticatedToken;

    public SOAPHeaderHandler(String authenticatedToken) {
        this.authenticatedToken = authenticatedToken;
    }

    public boolean handleMessage(SOAPMessageContext context) {
        Boolean outboundProperty =
                (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (outboundProperty.booleanValue()) {
            try {
                SOAPEnvelope envelope = context.getMessage().getSOAPPart().getEnvelope();
                SOAPFactory factory = SOAPFactory.newInstance();
                String prefix = "urn";
                String uri = "urn:xxxx";
                SOAPElement securityElem =
                        factory.createElement("Element", prefix, uri);
                SOAPElement tokenElem =
                        factory.createElement("Element2", prefix, uri);
                tokenElem.addTextNode(authenticatedToken);
                securityElem.addChildElement(tokenElem);
                SOAPHeader header = envelope.addHeader();
                header.addChildElement(securityElem);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            // inbound
        }
        return true;
    }

    public Set<QName> getHeaders() {
        return new TreeSet();
    }

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

    public void close(MessageContext context) {
        //
    }
}

Dans le proxy, je viens d'ajouter le Gestionnaire:

BindingProvider bp =(BindingProvider)basicHttpBindingAuthentication;
bp.getBinding().getHandlerChain().add(new SOAPHeaderHandler(authenticatedToken));
bp.getBinding().getHandlerChain().add(new SOAPLoggingHandler());
1
répondu edubriguenti 2016-04-25 17:54:40

Vous pouvez ajouter le nom d'utilisateur et le mot de passe à L'en-tête SOAP

BindingProvider prov = (BindingProvider)port;
prov.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
                "your end point"));
Map<String, List<String>> headers = new HashMap<String, List<String>>();
prov.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "myusername");
prov.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "mypassword");
prov.getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, headers);
1
répondu MahmoudPrime 2017-06-22 11:15:57

jaxws-rt-2.2.10-ources.jar!\com\sun\xml\ws\transport\http\client\HttpTransportPipe.java:

public Packet process(Packet request) {
        Map<String, List<String>> userHeaders = (Map<String, List<String>>) request.invocationProperties.get(MessageContext.HTTP_REQUEST_HEADERS);
        if (userHeaders != null) {
            reqHeaders.putAll(userHeaders);

Donc, Map<String, List<String>> à partir de requestContext avec la touche MessageContext.HTTP_REQUEST_HEADERS sera copié sur des en-têtes de savon. Exemple authentification de L'Application avec JAX-WS via des en-têtes

BindingProvider.USERNAME_PROPERTY et BindingProvider.PASSWORD_PROPERTY les clés sont traitées de manière spéciale dans HttpTransportPipe.addBasicAuth(), ajout d'une autorisation de base standard Authorization en-tête.

Voir aussi Message d'Contexte JAX-WS

0
répondu GKislin 2017-02-04 16:40:08

j'ai du mal avec toutes les réponses ici, en commençant par la solution de Pascal, qui devient de plus en plus difficile avec le compilateur Java ne se liant pas à rt.jar par défaut plus (et l'utilisation de classes internes le rend spécifique à cette implémentation d'exécution).

La réponse de edubriguenti m'a amené à proximité. La façon dont le handler est connecté dans le dernier morceau de code n'a pas fonctionné pour moi, bien que - il n'a jamais été appelé.

j'ai fini par utiliser un variation de sa classe de handler, mais il l'a relié dans le javax.xml.ws.Service exemple comme ceci:

Service service = Service.create(url, qname); service.setHandlerResolver( portInfo -> Collections.singletonList(new SOAPHeaderHandler(handlerArgs)) );

0
répondu Peter Becker 2018-10-04 03:27:22