我正在尝试为以下网站开发Web服务客户端:https://se-face-webservice.redsara.es/facturasspp2?wsdl 使用WS-Security 1.0 X.509令牌配置文件实现安全性
我已经尝试了三种方法:
1)仅包含Java 1.8和Wsdl2Java中包含的库。 (JAX-WS?) 经过大量熨烫后,我能够包含证书并发送请求,但是服务器响应“签名无效”自定义错误。
2)Axis2,在使用Eclipse 2019-09向导后,我发现它对我当前的项目造成了太多混乱:许多新的jar和新文件夹。当此Web服务仅涉及系统项目的1%时,实在太多了。
3)Axis(不建议使用)我使用了Eclipse 2019-09向导:首先,我发现了几个缺少的类,看起来该向导并未添加所有jar。 我下载了wss4j-1.5.8和xmlsec-1.4.4解决了这个问题(无法确定这些版本是否在1.4轴上工作良好,但错误消失了)。 在找出如何包括实现基本处理程序的证书之后,我从服务器获得了成功的响应(我正在将其打印到控制台),但是在解析时得到了:
faultCode: {http://schemas.xmlsoap.org/soap/envelope/}MustUnderstand
faultSubcode:
faultString: Did not understand "MustUnderstand" header(s):{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security
在方法#1中,我在SOAPFaultException "MustUnderstand headers (oasis-200401-wss-wssecurity-secext-1.0.xsd) are not understood"中的第一个响应中解决了类似或相同的错误 但是我不知道如何在轴生成的代码中应用它。
在stackoverflow上有很多关于此轴错误的文章,但大多数是关于在请求中禁用此选项的。看来,在这种情况下,我认为服务器使用MustUnderstand ='1'。 无论如何,我的要求在wsse中没有包含MustUnderstand,因此我尝试了
_call.setProperty(org.apache.axis.client.Call.CHECK_MUST_UNDERSTAND, Boolean.TRUE)
但是没有用。我发现在请求中包括Mustunderstand =“ 1”的唯一方法是在BasicHandler中进行编码:
WSSecHeader wsSecHeader;
wsSecHeader.setMustUnderstand(true);
...
但出现相同的错误。
当前,我正在尝试找到一种方法,以某种方式绕过此MustUnderstand检查,在解析响应之前对其进行拦截和转换。在处理程序invoke方法中,您可以实现以下拦截:
public void invoke(MessageContext msgContext) throws AxisFault {
try {
//request, include signing with certificate in the header
((SOAPPart) msgContext.getRequestMessage().getSOAPPart()).setCurrentMessage(this.createBinarySecurityToken(msgContext),
SOAPPart.FORM_SOAPENVELOPE);
//response
if(msgContext.getResponseMessage() != null) {
String transf = msgContext.getResponseMessage().getSOAPPartAsString();
//
transf = transf.replace("mustUnderstand=\"1\"" , "");
msgContext.setResponseMessage(new Message(transf ));
}
//Print xml to console
if(msgContext.getResponseMessage() != null && msgContext.getResponseMessage().getSOAPPart() != null) {
System.out.println("\n -- RESPONSE -- \n" + msgContext.getResponseMessage().getSOAPPartAsString());
} else {
if(msgContext.getRequestMessage() != null && msgContext.getRequestMessage().getSOAPPartAsString() != null) {
System.out.println("\n -- REQUEST -- \n" + msgContext.getRequestMessage().getSOAPPartAsString());
}
}
} catch (Exception e) {
System.err.println(e.getMessage());
System.exit(-1);
}
}
您可以看到,我天真地认为从xml中删除mustUnderstand部分是可行的,但是我得到了“ SimpleDeserializer遇到子元素,这在我们试图反序列化的过程中是不希望的”。
我也尝试了一些发现的事情,但没有成功:
SOAPHeader header = msgContext.getResponseMessage().getSOAPHeader();
if( header != null )
{
Iterator<?> blocks = header.examineAllHeaderElements();
while( blocks.hasNext() )
{
SOAPHeaderElement block = (SOAPHeaderElement)blocks.next();
block.setMustUnderstand(false);
}
}
必须有一种方法来忽略此标头检查,因为响应中的正文显示了预期的信息,就在那。
我找到了一个解决方法,但是它很脏。如果我先用方法#3发出请求,然后用方法#1发出请求,那么毫无疑问#1现在可以正常工作。我得到的是正确的响应,而不是服务器用“签名无效”响应,它使用生成的类进行了解析。后续仅使用#1的电话可以正常工作。
这不是永久性的,当我第二天尝试#1返回错误,但是再次执行变通方法/连接调用可解决此问题。我已经连续三天看到这种行为,我听不懂,但这可能是一个临时解决方案。
同时,我还将比较1和3的SOAP请求,以检查标头中的差异。