问题 Apache CXF - 无法满足任何策略选择


我正在尝试创建第三方WS的客户端。我的应用程序在JBoss AS 6上运行(带有Apache CXF 2.3.1堆栈)。我通过wsconsume(wsdl2java)生成了客户端代码。当我尝试连接到WS时出现异常:

No assertion builder for type http://schemas.microsoft.com/ws/06/2004/policy/http}BasicAuthentication registered. 
Exception in thread "main" org.apache.cxf.ws.policy.PolicyException: None of the policy alternatives can be satisfied.

WSDL的Auth部分看起来像:

<wsp:Policy wsu:Id="abc_ssl_policy">
    <wsp:ExactlyOne>
        <wsp:All>
            <http:BasicAuthentication
                xmlns:http="http://schemas.microsoft.com/ws/06/2004/policy/http" />
            <sp:TransportBinding
                xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
                <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:Strict />
                        </wsp:Policy>
                    </sp:Layout>
                </wsp:Policy>
            </sp:TransportBinding>
        </wsp:All>
    </wsp:ExactlyOne>
</wsp:Policy>

客户代码:

@WebServiceClient(name = "Abc", 
              wsdlLocation = "https://hiddendomain.com/abc/abc.svc?wsdl",
              targetNamespace = "http://tempuri.org/")                  
public class Abc extends Service {

public final static URL WSDL_LOCATION;

public final static QName SERVICE = new QName("http://tempuri.org/", "Abc");
public final static QName AbcSsl = new QName("http://tempuri.org/", "abc_ssl");
static {

    Authenticator.setDefault(new Authenticator() {
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication("user", "pas".toCharArray());
        }

    });

    URL url = null;
    try {
        url = new URL("https://hiddendomain.com/abc/abc.svc?wsdl");

    } catch (MalformedURLException e) {
        java.util.logging.Logger.getLogger(DistrInfo.class.getName())
            .log(java.util.logging.Level.INFO, 
                 "Can not initialize the default wsdl from {0}", "...");
    }
    WSDL_LOCATION = url;
}

在我尝试使用Conduit时抛出异常:

    Client client = ClientProxy.getClient(port);
    HTTPConduit con = (HTTPConduit) client.getConduit(); <- exception

我怀疑这是因为非标准的MS政策,我需要适当的Intercerptor来处理这个政策,但是有人可以告诉我一个怎么做的方法吗?

我甚至不,我应该把我的HTTPS凭据放到auth(我不能得到管道)


1641
2017-08-22 11:52


起源



答案:


我使用此代码时问题消失了:

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;

...

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();

//factory.getInInterceptors().add(new LoggingInInterceptor());
//factory.getOutInterceptors().add(new LoggingOutInterceptor());

factory.setServiceClass(IAbc.class);
factory.setAddress("https://hiddendomain.com/abc/abc.svc/soap"); <- must be /soap there, otherwise 404

IAbc info = (IAbc) factory.create();

Client client = ClientProxy.getClient(info);
HTTPConduit http = (HTTPConduit) client.getConduit();

http.getAuthorization().setUserName("user");
http.getAuthorization().setPassword("pass");

String abc = info.abc();

11
2017-08-23 11:31



谢谢,这也解决了我的问题。我最初使用的是HTTP服务,但在切换到HTTPS后,我遇到了可怕的PolicyException。最初我做了 MyService ss = new MyService(new URL(wsdlUrl), new QName("http://tempuri.org/", "MyService")); IMyService port = ss.getBasicHttpBindingIMyService();。现在我做 JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.setServiceClass(IMyService.class); factory.setAddress(wsdlUrl.replace("?wsdl", "")); IMyService port = (IMyService) factory.create();。 - neu242
这真的很有帮助!谢谢!! - John Volkya
我遇到了同样的问题....虽然代码在tomcat中工作,但是当我在jboss中部署代码时,我收到了这个错误。可以请分享客户端程序的完整代码。 - aravind
你从哪个地方拿了这个肥皂后缀?这种从wsdl生成客户端和设置地址的方法解决了我的问题。很多。我很好奇,你能详细描述一下它的工作原理吗? - MyWay


答案:


我使用此代码时问题消失了:

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;

...

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();

//factory.getInInterceptors().add(new LoggingInInterceptor());
//factory.getOutInterceptors().add(new LoggingOutInterceptor());

factory.setServiceClass(IAbc.class);
factory.setAddress("https://hiddendomain.com/abc/abc.svc/soap"); <- must be /soap there, otherwise 404

IAbc info = (IAbc) factory.create();

Client client = ClientProxy.getClient(info);
HTTPConduit http = (HTTPConduit) client.getConduit();

http.getAuthorization().setUserName("user");
http.getAuthorization().setPassword("pass");

String abc = info.abc();

11
2017-08-23 11:31



谢谢,这也解决了我的问题。我最初使用的是HTTP服务,但在切换到HTTPS后,我遇到了可怕的PolicyException。最初我做了 MyService ss = new MyService(new URL(wsdlUrl), new QName("http://tempuri.org/", "MyService")); IMyService port = ss.getBasicHttpBindingIMyService();。现在我做 JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.setServiceClass(IMyService.class); factory.setAddress(wsdlUrl.replace("?wsdl", "")); IMyService port = (IMyService) factory.create();。 - neu242
这真的很有帮助!谢谢!! - John Volkya
我遇到了同样的问题....虽然代码在tomcat中工作,但是当我在jboss中部署代码时,我收到了这个错误。可以请分享客户端程序的完整代码。 - aravind
你从哪个地方拿了这个肥皂后缀?这种从wsdl生成客户端和设置地址的方法解决了我的问题。很多。我很好奇,你能详细描述一下它的工作原理吗? - MyWay


你太棒了。这解决了我的wsse问题:我的wsdl中的策略安全问题。现在我可以使用CXF调用安全服务。

我需要在我的代码中添加以下内容

    JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); 
    factory.setServiceClass(TicketServicePortType.class); 
    factory.setAddress("http://localhost:8090/services"); 
    TicketServicePortType port = (TicketServicePortType) factory.create();

    Client client = ClientProxy.getClient(port);
    HTTPConduit http = (HTTPConduit) client.getConduit();

    http.getAuthorization().setUserName("user");
    http.getAuthorization().setPassword("password");


    Endpoint cxfEndpoint = client.getEndpoint();

    Map<String,Object> outProps = new HashMap<String,Object>();

    outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
    outProps.put(WSHandlerConstants.USER, "user");
    outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
    outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, 
    ClientPasswordCallback.class.getName());

    WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
    cxfEndpoint.getOutInterceptors().add(wssOut);

1
2018-06-23 05:19



1)最好使用outProps.put(WSHandlerConstants.PW_CALLBACK_REF,new ClientPasswordCallback()); 2)http.getAuthorization()中的用户名/密码初始化似乎没用... - ursa


为我删除 CXF束 从项目立即帮助:

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-bundle</artifactId>
    <version>2.7.17</version>
</dependency>

1
2017-09-28 09:28