example - ws-security java
SOAPFaultException "Los encabezados MustUnderstand(oasis-200401-wss-wssecurity-secext-1.0.xsd) no se entienden" (3)
Intento obtener información de un servicio web que usa el tipo de contraseña de texto WSS. En primer lugar, lo probé con soapUI y obtuve datos con éxito. Luego implementé la autenticación en Java, escribiendo 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;
}
...
}
XMLUtils.PrettyDocumentToString(doc)
objeto doc con XMLUtils.PrettyDocumentToString(doc)
y vi que se parece al XML enviado por soupUI: toda la información de autenticación (inicio de sesión, contraseña, hora y hora de creación) estaba vigente, el atributo mustUnderstand de Security
etiqueta de Security
era verdadero.
Entonces me enfrenté con el error:
javax.xml.ws.soap.SOAPFaultException: MustUnderstand headers: [{ http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd } Security] son no se entiende
Encontré consejos para eliminar el atributo mustUnderstand de Security
etiqueta de Security
, pero no ayuda. ¿Tienes alguna idea?
PD
El punto final del servicio web está en HTTPS .
Parte de la política 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>
solicitud de soapUI:
<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>
Mi petición:
<?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>
Encontré la solución. Se requirieron las siguientes dependencias:
<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>
Buen artículo sobre este tema y algunos escollos de cxf: http://www.logicsector.com/java/how-to-create-a-wsdl-first-soap-client-in-java-with-cxf-and-maven/
Esto es lo que funcionó para mí. Básicamente, es una aplicación de la idea pronunciada por @Joseph Rajeev Motha (aunque la encontré en otro lugar, aquí: https://dwuysan.wordpress.com/2012/04/02/jax-ws-wsimport-and-the-error-mustunderstand-headers-not-understood/#comment-215 ), pero su respuesta no proporciona repetitivo, y sin ella, la respuesta es bastante misteriosa.
Tenga en cuenta que esta secuencia se aplica al caso independiente (donde usted mismo publica un Endpoint
).
Paso 1
Cree un SOAPHandler
que "entienda" el encabezado:
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) {
}
}
Paso 2
Cree un archivo handler-chain.xml
y póngalo en 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>
Paso 3
Anote su clase de implementación (clase que se anota con @WebService
) con una referencia al archivo de cadena de manejador:
@HandlerChain(file = "handler-chain.xml")
Etapa 4
Publique su punto final:
Endpoint endpoint = Endpoint.publish(url, impl);
Una nota importante
handleMessage()
y handleFault()
definidos por el controlador deben devolver true
. De lo contrario, obtendrá errores extraños como "Elemento de envoltorio inesperado" porque se usará un nombre de elemento de envoltorio diferente.
Podría obtener este error cuando el servicio no maneje los encabezados. El servicio debe implementar un SOAPHandler con un getHeaders () que resolvería los encabezados. Para la falla arriba mencionada la implementación correcta sería la siguiente
@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;
}
También es posible obtener esto cuando el servicio en realidad no es seguro, pero el cliente está intentando usar la configuración de seguridad (posiblemente utilizando una configuración de seguridad XWSS). Para esto, simplemente verifique el wsdl publicado desde un navegador y asegúrese de que contenga la información esperada. política de seguridad (agregue wsdl a su URL de punto final)