简体   繁体   English

Apache CXF策略异常(WS安全)-无法检测到安全配置

[英]Apache CXF Policy Exception (WS Security)- Security configuration could not be detected

Could really do with some help with this one as I've been banging my head against a brick wall for several days now. 我已经将头撞在砖墙上好几天了,对此确实可以提供一些帮助。

I've implemented a very simple JAX-WS service using Apache CXF, I'm trying to add WS-SecurityPolicies to encrypt and sign the message body however client side I'm getting the following exception: 我已经使用Apache CXF实现了一个非常简单的JAX-WS服务,我试图添加WS-SecurityPolicies来加密和签名消息正文,但是客户端却收到以下异常:

org.apache.cxf.ws.policy.PolicyException: Security configuration could not be detected. Potential cause: Make sure jaxws:client element with name attribute value matching endpoint port is defined as well as a security.signature.properties element within it.
    at org.apache.cxf.ws.security.wss4j.policyhandlers.AbstractCommonBindingHandler.unassertPolicy(AbstractCommonBindingHandler.java:92)
    at org.apache.cxf.ws.security.wss4j.policyhandlers.AbstractBindingBuilder.getSignatureBuilder(AbstractBindingBuilder.java:1797)
    at org.apache.cxf.ws.security.wss4j.policyhandlers.AsymmetricBindingHandler.doSignature(AsymmetricBindingHandler.java:693)
    at org.apache.cxf.ws.security.wss4j.policyhandlers.AsymmetricBindingHandler.doSignBeforeEncrypt(AsymmetricBindingHandler.java:171)
    at org.apache.cxf.ws.security.wss4j.policyhandlers.AsymmetricBindingHandler.handleBinding(AsymmetricBindingHandler.java:110)
    at org.apache.cxf.ws.security.wss4j.PolicyBasedWSS4JOutInterceptor$PolicyBasedWSS4JOutInterceptorInternal.handleMessageInternal(PolicyBasedWSS4JOutInterceptor.java:190)
    at org.apache.cxf.ws.security.wss4j.PolicyBasedWSS4JOutInterceptor$PolicyBasedWSS4JOutInterceptorInternal.handleMessage(PolicyBasedWSS4JOutInterceptor.java:109)
    at org.apache.cxf.ws.security.wss4j.PolicyBasedWSS4JOutInterceptor$PolicyBasedWSS4JOutInterceptorInternal.handleMessage(PolicyBasedWSS4JOutInterceptor.java:96)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
    at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:514)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:423)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:324)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:277)
    at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:139)

This is my applicationContext.xml client side: 这是我的applicationContext.xml客户端:

<bean id="passwordCallback"
        class="com.example.payment.engine.soap.service.ClientPasswordCallback"></bean>

<jaxws:client
    name="{http://service.soap.engine.payment.example.com/}HelloWorldImplService"
    createdFromAPI="true" id="helloClient"
    serviceClass="com.example.payment.engine.soap.service.HelloWorld"
    address="http://localhost:8080/payment-engine/api/soap/hello">
    <jaxws:properties>
        <entry key="ws-security.callback-handler" value-ref="passwordCallback" />
        <entry key="ws-security.encryption.properties" value="crypto.properties" />
        <entry key="ws-security.signature.properties" value="crypto.properties" />
        <entry key="ws-security.encryption.username" value="server" />
    </jaxws:properties>
</jaxws:client>

This is the client crypto.properties 这是客户端crypto.properties

org.apache.ws.security.crypto.merlin.keystore.file=client-keystore.jks
org.apache.ws.security.crypto.merlin.keystore.password=client-pass
org.apache.ws.security.crypto.merlin.keystore.private.password=key-pass
org.apache.ws.security.crypto.merlin.keystore.alias=client

And finally this is the WSDL: 最后是WSDL:

<wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:tns="http://service.soap.engine.payment.example.com/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:ns1="http://schemas.xmlsoap.org/soap/http" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"
    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" name="HelloWorldImplService"
    targetNamespace="http://service.soap.engine.payment.example.com/">
    <wsdl:types>
        <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://service.soap.engine.payment.example.com/"
            elementFormDefault="unqualified" targetNamespace="http://service.soap.engine.payment.example.com/" version="1.0">
            <xs:element name="sayHello" type="tns:sayHello" />
            <xs:element name="sayHelloResponse" type="tns:sayHelloResponse" />
            <xs:complexType name="sayHello">
                <xs:sequence />
            </xs:complexType>
            <xs:complexType name="sayHelloResponse">
                <xs:sequence>
                    <xs:element minOccurs="0" name="return" type="xs:string" />
                </xs:sequence>
            </xs:complexType>
        </xs:schema>
    </wsdl:types>
    <wsdl:message name="sayHelloResponse">
        <wsdl:part element="tns:sayHelloResponse" name="parameters"></wsdl:part>
    </wsdl:message>
    <wsdl:message name="sayHello">
        <wsdl:part element="tns:sayHello" name="parameters"></wsdl:part>
    </wsdl:message>
    <wsdl:portType name="HelloWorld">
        <wsdl:operation name="sayHello">
            <wsdl:input message="tns:sayHello" name="sayHello"></wsdl:input>
            <wsdl:output message="tns:sayHelloResponse" name="sayHelloResponse"></wsdl:output>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="HelloWorldImplServiceSoapBinding" type="tns:HelloWorld">
    <wsp:PolicyReference URI="#HelloWorldBindingPolicy"/>
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
        <wsdl:operation name="sayHello">
            <soap:operation soapAction="" style="document" />
            <wsdl:input name="sayHello">
                <wsp:PolicyReference URI="#HelloWorldInputBindingPolicy" />
                <soap:body use="literal" />
            </wsdl:input>
            <wsdl:output name="sayHelloResponse">
                <wsp:PolicyReference URI="#HelloWorldOutputBindingPolicy" />
                <soap:body use="literal" />
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name="HelloWorldImplService">
        <wsdl:port binding="tns:HelloWorldImplServiceSoapBinding" name="HelloWorldImplPort">
            <soap:address location="http://localhost:8080/payment-engine/api/soap/hello" />
        </wsdl:port>
    </wsdl:service>
    <wsp:Policy wsu:Id="HelloWorldBindingPolicy">
        <wsp:ExactlyOne>
            <wsp:All>
                <sp:AsymmetricBinding>
                    <wsp:Policy>
                        <sp:InitiatorToken>
                            <wsp:Policy>
                                <sp:X509Token sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
                                    <wsp:Policy>
                                        <sp:WssX509V3Token11 />
                                    </wsp:Policy>
                                </sp:X509Token>
                            </wsp:Policy>
                        </sp:InitiatorToken>
                        <sp:RecipientToken>
                            <wsp:Policy>
                                <sp:X509Token sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/Never">
                                    <wsp:Policy>
                                        <sp:WssX509V3Token11 />
                                        <sp:RequireIssuerSerialReference />
                                    </wsp:Policy>
                                </sp:X509Token>
                            </wsp:Policy>
                        </sp:RecipientToken>
                        <sp:Layout>
                            <wsp:Policy>
                                <sp:Strict />
                            </wsp:Policy>
                        </sp:Layout>
                        <sp:IncludeTimestamp />
                        <sp:OnlySignEntireHeadersAndBody />
                        <sp:AlgorithmSuite>
                            <wsp:Policy>
                                <sp:Basic128 />
                            </wsp:Policy>
                        </sp:AlgorithmSuite>
                        <sp:EncryptSignature />
                    </wsp:Policy>
                </sp:AsymmetricBinding>
                <sp:Wss11>
                    <wsp:Policy>
                        <sp:MustSupportRefIssuerSerial />
                    </wsp:Policy>
                </sp:Wss11>
            </wsp:All>
        </wsp:ExactlyOne>
    </wsp:Policy>
    <wsp:Policy wsu:Id="HelloWorldInputBindingPolicy">
        <wsp:ExactlyOne>
            <wsp:All>
                <sp:EncryptedParts>
                    <sp:Body />
                </sp:EncryptedParts>
                <sp:SignedParts>
                    <sp:Body />
                </sp:SignedParts>
            </wsp:All>
        </wsp:ExactlyOne>
    </wsp:Policy>
    <wsp:Policy wsu:Id="HelloWorldOutputBindingPolicy">
        <wsp:ExactlyOne>
            <wsp:All>
                <sp:EncryptedParts>
                    <sp:Body />
                </sp:EncryptedParts>
                <sp:SignedParts>
                    <sp:Body />
                </sp:SignedParts>
            </wsp:All>
        </wsp:ExactlyOne>
    </wsp:Policy>
</wsdl:definitions>

Any help would be really appreciated! 任何帮助将非常感激!

I spent a few days solving this and additional issues with Apache CXF 3.1.4. 我花了几天的时间解决Apache CXF 3.1.4的这一问题和其他问题。 Fact is, the Error messages in CXF seldom provide the true clue about what to fix. 事实是,CXF中的错误消息很少能提供有关修复内容的真实线索。 The one at stake is quite typical: it tells about a name not found but does not provide the actual value that is looked up, and second, that was not the issue in my context. 危在旦夕的事情很典型:它讲述了一个找不到的名字,但没有提供要查找的实际值,其次,在我看来,这并不是问题所在。

I was starting from an XML/Spring-based CXF bus/policy configuration working in test and prod for over a year, and like: 我从一个基于XML / Spring的CXF总线/策略配置开始,从事了超过一年的测试和生产工作,例如:

SpringBusFactory bf = new SpringBusFactory();
URL busFile = MyClient.class.getResource("/wssec_policy.xml");
Bus bus = bf.createBus(busFile);
BusFactory.setDefaultBus(bus);

where the wssec_policy.xml contained the jaxws:client definition as follows: wssec_policy.xml包含jaxws:client定义,如下所示:

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:cxf="http://cxf.apache.org/core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="...etc...">
<bean id="logOutbound" class="MyLoggingOutInterceptor"/>
<bean id="logInbound" class="MyLoggingInInterceptor"/>
<cxf:bus>
    <cxf:outInterceptors><ref bean="logOutbound"/></cxf:outInterceptors>
    <cxf:inInterceptors><ref bean="dumpMessageInterceptor"/><ref bean="logInbound"/></cxf:inInterceptors>
    <cxf:features><cxf:logging/></cxf:features>
</cxf:bus>
<jaxws:client name="{http://some.domain/webservices}servicioSoap" createdFromAPI="true">
        <jaxws:properties>
            <entry key="security.encryption.properties" value="etc/Client_Encrypt.properties"/>
            <entry key="security.signature.properties" value="etc/Client_Sign.properties"/>
        </jaxws:properties>
    </jaxws:client>
</beans>

and where encryption and signature.properties contain WSS4J properties . 以及加密和signature.properties包含WSS4J属性的地方

My challenge was just to get this working with CXF 3.1.4, BouncyCastle 1.52, Spring 4.2.4, on JRE 8; 我的挑战只是要在JRE 8上与CXF 3.1.4,BouncyCastle 1.52,Spring 4.2.4一起工作。 which did not, banging first on the error you cite. 并没有,首先敲打您引用的错误。

I assembled the code in a POJO client and started drilling down in CXF source code to find the true cause, and discovered that the default bus setup as above (which did work previously) no longer supplied the jaxws:client meta-data to WSS4J layers. 我在POJO客户端中汇编了代码,并开始深入研究CXF源代码以找到真正的原因,并发现上述默认总线设置(之前确实有效)不再向WSS4J层提供jaxws:client元数据。 No data, hence the error. 没有数据,因此出现错误。 Apache CXF supplies three ways of configuring your WS-* stack (Explicit Interceptors, policy-based with XML, and policy-based via Java API). Apache CXF提供了三种配置WS- *堆栈的方式(显式拦截器,基于XML的策略和基于Java API的策略)。 To solve your issue, I switched to policy-based config via the java API as follows: 为了解决您的问题,我通过java API切换到基于策略的配置,如下所示:

serviceGDS = new WSDL2Java_generated_Service();
portGDS = serviceGDS.getServiceGdsSoap();
Map<String, Object> ctx = ((javax.xml.ws.BindingProvider)portGDS).getRequestContext();
Properties encProps = new Properties();
encProps.load(new FileInputStream("etc/Client_Encrypt.properties"));
ctx.put("security.encryption.properties", encProps);
Properties signProps = new Properties();
signProps.load(new FileInputStream("etc/Client_Sign.properties"));
ctx.put("security.signature.properties", signProps);
// setting the props below once helped solving the error at stake
ctx.put("security.signature.username","test_keypair");
ctx.put("security.encryption.username","gds_test_cert");

The last two properties were once needed to progress in debugging, solving wrong key length errors due to missing key alias!!! 最后两个属性曾经需要进行调试,以解决由于缺少密钥别名而导致的错误的密钥长度错误! But at the very end, I noted that it worked back without them! 但最后,我指出如果没有他们,它可以奏效! (they actually duplicate keystore alias in the Client_Encrypt and Client_Sign properties). (它们实际上在Client_Encrypt和Client_Sign属性中重复了密钥库别名)。

I then solved no certificate found for encryption errors by suppressing "org.apache.ws.security.crypto.merlin.keystore.provider=BC" from Client_Encrypt and Client_Sign properties (yet worked in the past version). 然后,我通过抑制Client_Encrypt和Client_Sign属性中的“ org.apache.ws.security.crypto.merlin.keystore.provider = BC”解决了未发现的加密错误证书 (至今仍在过去的版本中工作)。

I solved missing certificate errors by switching from pkcs12 keystore type to jks . 我通过将pkcs12密钥库类型切换为jks来解决了丢失的证书错误。 I discovered that keystore.load() does not fetch all the contained certificates... with the same p12 keystore I get varying outcome according to the context in which it is called... buggy indeed. 我发现keystore.load()不会获取所有包含的证书...使用相同的p12密钥库,根据调用上下文的不同,我得到的结果也有所不同。

I solved AsymmetricBinding is not supported by observing that the re-deployment in a live server (JBoss EAP7 in my case) never worked, but when the deployed app starts along with the server (hence after server reboot), it works. 我通过观察实时服务器(在我的情况下为JBoss EAP7)中的重新部署从未奏效,从而解决了不支持AsymmetricBinding的问题,但是当已部署的应用与服务器一起启动时(因此在服务器重启后),它可以正常工作。 I strongly suspect class loader issues. 我强烈怀疑类加载器问题。

Let me add that I once switched back to JRE 7 (where legacy runs OK) and the errors were significantly different (I suspect policy config files in the JRE). 让我补充一下,我曾经切换回JRE 7(旧版运行正常),并且错误明显不同(我怀疑JRE中的策略配置文件)。

Another major difficulty is that all errors, be it client side exceptions on handling the request or even the response, as well as server side faults, are all wrapped by CXF as soap faults with terse error messages making it very difficult to understand what's really happening. 另一个主要的困难是,所有错误(无论是处理请求乃至响应的客户端异常,还是服务器端错误)都由CXF封装为肥皂错误,并带有简洁的错误消息,这使得很难理解实际发生的情况。 The only way left that allowed me to progress was assembling needed client code in a POJO and debugging it with help of CXF and WSS4J source code libraries( Eclipse/Maven fetches the source code for you while you use the debugger and drill down... efficient!) 让我前进的唯一途径是在POJO中组装所需的客户端代码,并借助CXF和WSS4J源代码库对其进行调试(当您使用调试器并向下钻取时,Eclipse / Maven会为您获取源代码。高效!)

Managed to get this half working by using the following 通过使用以下内容设法使这一半工作

    HelloWorldImplService service = new HelloWorldImplService();
    HelloWorld port = service.getHelloWorldImplPort();

    Map<String, Object> ctx = ((BindingProvider) port).getRequestContext();
    ctx.put("ws-security.callback-handler", "com.example.payment.engine.soap.service.ClientPasswordCallback");
    ctx.put("ws-security.encryption.properties", "config/crypto.properties");
    ctx.put("ws-security.signature.properties", "config/crypto.properties");
    ctx.put("ws-security.encryption.username", "server");

    System.out.println(port.sayHello());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM