【问题标题】:JAX-WS Client CXF WS-Policy IssueJAX-WS 客户端 CXF WS-Policy 问题
【发布时间】:2023-08-28 02:17:02
【问题描述】:

我必须实现一个使用来自外部合作伙伴的服务的 JAX-WS-Client。我使用 Apache CXF。该服务在 wsdl 中定义了两个用于身份验证的 WS-Policies - KerberosToken 和 UsernameToken。由于服务来自外部合作伙伴,因此无法更改。

问题:Kerberos-Authentication 的身份验证失败,因为我想使用 简单的 UsernameToken-Authentication。

WSLD-策略部分:

<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" 
  xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
  wsu:Id="SecurityServiceUsernameUnsecureTransportPolicy">
  <wsp:ExactlyOne>
  <wsp:All>
    <sp:SupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
    <wsp:Policy>
      <sp:KerberosToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
      <wsp:Policy>
        <sp:WssGssKerberosV5ApReqToken11/>
      </wsp:Policy>
      </sp:KerberosToken>
    </wsp:Policy>
    </sp:SupportingTokens>
  </wsp:All>
  <wsp:All>
    <sp:SupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
    <wsp:Policy>
      <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
      <wsp:Policy>
        <sp:WssUsernameToken10/>
      </wsp:Policy>
      </sp:UsernameToken>
    </wsp:Policy>
    </sp:SupportingTokens>
  </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

在 CXF-Endpoint 设置用户名/密码:

public void addAuthenticationProperties( Endpoint endpoint ) {
  endpoint.put( SecurityConstants.USERNAME, userName );
  endpoint.put( SecurityConstants.PASSWORD, password );
}

据我了解,-Tag 意味着,如果此政策中的任何一项(特别是一项)已完成,请继续前进。但 CXF 甚至不会尝试填写 UsernameToken - Policy。

如果我删除 KerberosToken 身份验证的 -Block 可以正常工作,但在生产中这是不可能的。

有什么提示吗?如果 wsdl 或我的方法有错误,请告诉我。请详细说明 - 我是这个领域的菜鸟。

提前致谢!

【问题讨论】:

    标签: authentication cxf jax-ws policy


    【解决方案1】:

    几天后,我找到了解决这个问题的方法 - 不能称之为解决方案;-)

    起初是旧版本: CXF 生成了一个类ExampleWS_Service 和一个对应的接口ExampleWS。所以我使用ExampleWS_Service 来设置一切并调用服务:

    // creating Port
    URL url = new URL( config.getSchema(), config.getHost(), config.getPort(), config.getPath() );
    
    ExampleWS_Service service = new ExampleWS_Service( url );
    ExampleWS port = service.getExampleWSPort();
    
    // Adding authentication-info
    Client client = ClientProxy.getClient( port );
    Endpoint cxfEndpoint = client.getEndpoint();
    
    cxfEndpoint.put( SecurityConstants.USERNAME, userName );
    cxfEndpoint.put( SecurityConstants.PASSWORD, password );
    
    ...
    // invoke service
    port.doSomething( [data] );
    

    解决方法: 我切换到JaxWsProxyFactoryBean 并设置了一切。在这种情况下,需要 WSS4JOutInterceptor 将身份验证信息放入请求标头中。一些代码:

    URL url = new URL( config.getSchema(), config.getHost(), config.getPort(), config.getPath() );
    
    JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
    factory.setServiceClass( ExampleWS.class );
    factory.setAddress( url.toString() );
    factory.setBindingId( "http://schemas.xmlsoap.org/wsdl/soap12/" );
    
    ExampleWS port = ( ExampleWS )factory.create();
    
    // Adding authentication-info using WSS4JOutInterceptor
    Client client = ClientProxy.getClient( port );
    Endpoint cxfEndpoint = client.getEndpoint();
    
    Map<String, Object> outProps = new HashMap<>();
    outProps.put( WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN );
    outProps.put( WSHandlerConstants.USER, userName );
    outProps.put( WSHandlerConstants.PASSWORD_TYPE, passwordType );
    outProps.put( WSHandlerConstants.PW_CALLBACK_REF, [Instance of javax.security.auth.callback.CallbackHandler] );
    
    WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor( outProps );
    cxfEndpoint.getOutInterceptors().add( wssOut );
    
    ...
    // invoke service
    port.doSomething( [data] );
    

    我不知道为什么这种解决方法确实有效,但确实有效 :-) 也许你们中的某个人能给我这样的启迪。

    【讨论】:

      【解决方案2】:

      出于安全考虑,CXF 不会在出站端处理多个策略选项,仅在入站端处理。因此,您唯一的选择是将策略收紧到 Kerberos 或 UsernameToken,具体取决于您希望客户端使用的任何策略。

      【讨论】:

      • 感谢 Colm O hEigeartaigh!有没有办法告诉客户端忽略此策略并仅发送 UsernameToken-Request?我无法收紧政策,因为服务器端是由外部合作伙伴定义的。
      • 这可能会对您有所帮助:cxf.apache.org/ws-policy-framework.html。默认情况下会选择第一个策略替代方案,但可能有一种配置方法。
      • 谢谢科尔姆哦,嘿!我会调查一下。除此之外,我找到了一种解决方法。也许您可以对这种解决方法提出一些优点或缺点。