J'essaie d'obtenir des informations d'un service Web utilisant le type PasswordText WSS. Tout d'abord, je l'ai testé avec soapUI et j'ai réussi à obtenir des données. Ensuite, j'ai implémenté l'authentification sur Java en écrivant SecurityHandler:
public final class SecurityHandler implements SOAPHandler<SOAPMessageContext> {
...
@Override
public boolean handleMessage(SOAPMessageContext messageContext) {
boolean outInd = (Boolean) messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outInd) {
try {
WSSecUsernameToken builder = new WSSecUsernameToken();
builder.setPasswordType(WSConstants.PASSWORD_TEXT);
builder.setUserInfo(_username, _password);
builder.addNonce();
builder.addCreated();
Document doc = messageContext.getMessage().getSOAPPart().getEnvelope().getOwnerDocument();
WSSecHeader secHeader = new WSSecHeader();
secHeader.insertSecurityHeader(doc);
builder.build(doc, secHeader);
} catch (Exception e) {
LOGGER.error("Unable to handle SOAP message", e);
return false;
}
}
return true;
}
...
}
J'ai vérifié l'objet doc avec XMLUtils.PrettyDocumentToString(doc)
et j'ai vu qu'il ressemblait au XML envoyé par soupUI. Toutes les informations d'authentification (nom d'utilisateur, mot de passe, heure de création) étaient sur place, mustUnderstand attribut de la variable Security
était vrai.
Alors j'ai fait face à l'erreur:
javax.xml.ws.soap.SOAPFaultException: en-têtes MustUnderstand: [{ http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd } Sécurité] ne sont pas compris
J'ai trouvé des conseils pour supprimer l'attribut mustUnderstand de la balise Security
, mais cela n'aide pas. Avez-vous des idées?
P.S.
Le point de terminaison du service Web est sur HTTPS.
Partie politique de WSDL:
<wsp:Policy wsu:Id="BasicHttpBinding_RelateService_policy">
<wsp:ExactlyOne>
<wsp:All>
<sp:TransportBinding>
<wsp:Policy>
<sp:TransportToken>
<wsp:Policy>
<sp:HttpsToken RequireClientCertificate="false"/>
</wsp:Policy>
</sp:TransportToken>
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:Basic256/>
</wsp:Policy>
</sp:AlgorithmSuite>
<sp:Layout>
<wsp:Policy>
<sp:Lax/>
</wsp:Policy>
</sp:Layout>
<sp:IncludeTimestamp/>
</wsp:Policy>
</sp:TransportBinding>
<sp:SignedSupportingTokens>
<wsp:Policy>
<sp:UsernameToken
sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:WssUsernameToken10/>
</wsp:Policy>
</sp:UsernameToken>
</wsp:Policy>
</sp:SignedSupportingTokens>
<sp:Wss10>
<wsp:Policy/>
</sp:Wss10>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
soapUI demande:
<soapenv:Envelope xmlns:ns="http://api.example.com/RelateService/1.0"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand="1"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-37"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>username</wsse:Username>
<wsse:Password
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">
password
</wsse:Password>
<wsse:Nonce
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
li/0YK2wxrmrHL7Cg+etdQ==
</wsse:Nonce>
<wsu:Created>2012-02-21T08:59:10.262Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<ns:RetrieveCustomerByEmail>
<ns:email>[email protected]</ns:email>
<ns:firstName/>
<ns:lastName/>
</ns:RetrieveCustomerByEmail>
</soapenv:Body>
</soapenv:Envelope>
Ma demande:
<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
S:mustUnderstand="1">
<wsse:UsernameToken wsu:Id="UsernameToken-1">
<wsse:Username>username</wsse:Username>
<wsse:Password
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">
password
</wsse:Password>
<wsse:Nonce
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
+jeleKO9zr0/wLjAIYcmSg==
</wsse:Nonce>
<wsu:Created>2012-02-21T09:42:03.760Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</S:Header>
<S:Body>
<ns5:RetrieveCustomerByEmail xmlns="http://schemas.Microsoft.com/2003/10/Serialization/Arrays"
xmlns:ns2="http://schemas.datacontract.org/2004/07/XXX.Service"
xmlns:ns3="http://schemas.datacontract.org/2004/07/XXX.Service.Relate.Contract"
xmlns:ns4="http://schemas.datacontract.org/2004/07/XXX.Service.Dto"
xmlns:ns5="http://api.example.com/RelateService/1.0"
xmlns:ns6="http://schemas.Microsoft.com/2003/10/Serialization/">
<ns5:email>[email protected]</ns5:email>
<ns5:firstName/>
<ns5:lastName/>
</ns5:RetrieveCustomerByEmail>
</S:Body>
</S:Envelope>
J'ai trouvé la solution. Les dépendances suivantes étaient nécessaires:
<dependency>
<groupId>org.Apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>org.Apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>2.2.3</version>
</dependency>
Bon article sur ce sujet et quelques pièges de cxf: http://www.logicsector.com/Java/how-to-create-a-wsdl-first-soap-client-in-Java-with-cxf-and -maven/
Vous pouvez obtenir cette erreur lorsque le service ne gère pas les en-têtes. Le service doit implémenter un SOAPHandler avec un getHeaders () qui résoudrait les en-têtes. Pour le défaut mentionné ci-dessus, la mise en œuvre correcte serait la suivante
@Override
public Set<QName> getHeaders() {
QName securityHeader = new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
"Security");
HashSet<QName> headers = new HashSet<QName>();
headers.add(securityHeader);
return headers;
}
Il est également possible de l'obtenir lorsque le service n'est pas sécurisé, mais que le client tente d'utiliser une configuration de sécurité (éventuellement en utilisant une configuration de sécurité XWSS). contient la politique de sécurité attendue (ajoutez? wsdl à son URL de noeud final)
Voici ce qui a fonctionné pour moi. En gros, c’est une application de l’idée exprimée par @Joseph Rajeev Motha (bien que je l’aie trouvée ailleurs, ici: https://dwuysan.wordpress.com/2012/04/02/jax-ws-wsimport-and-the -error-mustunderstand-headers-not-includes/# comment-215 ), mais sa réponse ne fournit pas de passe-partout, et sans cela, la réponse est assez mystérieuse.
Veuillez noter que cette séquence s'applique au cas autonome (où vous publiez vous-même une Endpoint
).
Créez une SOAPHandler
qui "comprendra" l'en-tête:
public class WSSESecurityUnderstandPretender implements SOAPHandler<SOAPMessageContext> {
@Override
public Set<QName> getHeaders() {
final QName securityHeader = new QName(
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
"Security",
"wsse");
final Set<QName> headers = new HashSet<>();
headers.add(securityHeader);
// notify the runtime that this is handled
return headers;
}
@Override
public boolean handleMessage(SOAPMessageContext context) {
// we must return true, or else the runtime will return
// wrong wrapper element name (like makeTransfer instead of
// makeTransferResponse)
return true;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
// we must return true, or else the runtime will return
// wrong wrapper element name (like makeTransfer instead of
// makeTransferResponse)
return true;
}
@Override
public void close(MessageContext context) {
}
}
Créez un fichier handler-chain.xml
et placez-le sur classpath:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<javaee:handler-chains
xmlns:javaee="http://Java.Sun.com/xml/ns/javaee"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<javaee:handler-chain>
<javaee:handler>
<javaee:handler-class>com.mypackage.WSSESecurityUnderstandPretender</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</javaee:handler-chains>
Annotez votre classe d'implémentation (classe annotée avec @WebService
) avec une référence au fichier de chaîne du gestionnaire:
@HandlerChain(file = "handler-chain.xml")
Publiez votre terminal:
Endpoint endpoint = Endpoint.publish(url, impl);
handleMessage()
et handleFault()
définis par le gestionnaire doivent renvoyer true
. Sinon, vous obtiendrez des erreurs étranges telles que 'Elément de wrapper inattendu' car un nom d'élément de wrapper différent sera utilisé.