【问题标题】:SOAPFaultException "MustUnderstand headers (oasis-200401-wss-wssecurity-secext-1.0.xsd) are not understood"SOAPFaultException“必须理解标头(oasis-200401-wss-wssecurity-secext-1.0.xsd)不被理解”
【发布时间】:2020-06-17 22:08:50
【问题描述】:

我尝试从使用 PasswordText WSS 类型的 Web 服务获取信息。首先,我使用soapUI对其进行了测试,并成功获取了数据。然后我在Java上实现了认证,写了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) 检查了 doc 对象,发现它看起来像 soupUI 发送的 XML - 所有身份验证信息(登录名、密码、nonce 和创建时间)都在适当的位置,mustUnderstand 属性Security 标签为真。

然后我遇到了错误:

javax.xml.ws.soap.SOAPFaultException: MustUnderstand headers:[{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security] 不被理解

我找到了从 Security 标记中删除 mustUnderstand 属性的建议,但这没有帮助。你有什么想法吗?

附言

Web 服务端点在 HTTPS 上。

来自 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 请求:

<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>xxx@example.com</ns:email>
            <ns:firstName/>
            <ns:lastName/>
        </ns:RetrieveCustomerByEmail>
    </soapenv:Body>
</soapenv:Envelope>

我的要求:

<?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>xxx@example.com</ns5:email>
            <ns5:firstName/>
            <ns5:lastName/>
        </ns5:RetrieveCustomerByEmail>
    </S:Body>
</S:Envelope>

【问题讨论】:

标签: java webservice-client wss4j


【解决方案1】:

当服务不处理标头时,您可能会收到此错误。该服务需要使用可以解析标头的 getHeaders() 来实现 SOAPHandler。 对于上述故障,正确的实现如下

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

当服务实际上不安全时也有可能得到这个,但是客户端正在尝试使用安全配置(可能使用 XWSS 安全配置) 为此,只需从浏览器检查发布的 wsdl 并确保它包含预期的安全策略(将 ?wsdl 附加到其端点 URL)

【讨论】:

  • 这绝对是有帮助的!
  • 注意:getHeaders() 仅在容器(在我的情况下为 Tomcat)启动时调用一次。但是处理每个请求/响应时调用的其余处理程序方法(handleMessage 和 close())(在错误时调用handleFault())。
  • 能否请您在这里指导我:stackoverflow.com/questions/60260277/…
  • @Joseph - 它不适合我。此处发布的问题:stackoverflow.com/questions/60260277/…
  • 使用Spring Boot SOAP项目时在哪里配置这个类?
【解决方案2】:

我找到了解决方案。需要以下依赖项:

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

关于这个主题的好文章和 cxf 的一些陷阱:http://www.logicsector.com/java/how-to-create-a-wsdl-first-soap-client-in-java-with-cxf-and-maven/

【讨论】:

  • 我试过这个并得到以下异常:Servlet /test threw load() exception java.lang.ClassCastException: test.TestServiceListener cannot be cast to javax.servlet.Servlet
  • 不明白原因和解决办法。复制粘贴,它的工作原理。爱它。 ;)
【解决方案3】:

这对我有用。基本上,这是对@Joseph Rajeev Motha 提出的想法的应用(虽然我在其他地方找到了它,在这里:https://dwuysan.wordpress.com/2012/04/02/jax-ws-wsimport-and-the-error-mustunderstand-headers-not-understood/#comment-215),但他的回答没有提供样板文件,没有它,答案很神秘。

请注意,此顺序适用于独立案例(您自己发布Endpoint)。

步骤 1

创建一个“理解”标题的SOAPHandler

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) {
    }
}

第二步

创建一个handler-chain.xml 文件并将其放在类路径中:

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

第三步

使用对处理程序链文件的引用来注释您的实现类(使用@WebService 注释的类):

@HandlerChain(file = "handler-chain.xml")

第四步

发布您的端点:

Endpoint endpoint = Endpoint.publish(url, impl);

重要提示

处理程序定义的handleMessage()handleFault() 必须返回true。否则,您将收到奇怪的错误,例如“意外的包装元素”,因为将使用不同的包装元素名称。

【讨论】:

  • 你救了我,尤其是返回标题的代码!谢谢你罗曼:)
  • @Roman - 请您在这里指导我:stackoverflow.com/questions/60260277/…
  • @Roman - 此解决方案不适用于 Spring Boot v2.2.2.RELEASE & SOAP 项目
【解决方案4】:

如果您在使用 Java 11 的项目中遇到此问题,请尝试使用 Apache CXF 3.3.x 版本。
下面来自Apache CXF FAQ的回答:

CXF 可以在 JDK/Java 9+ (10, 11) 上运行吗?
是的。 CXF 将在下一个 3.3.x 版本中支持 Java 9-11。

【讨论】:

    猜你喜欢
    • 2016-06-21
    • 2014-07-24
    • 2020-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多