代码之家  ›  专栏  ›  技术社区  ›  Michael Sharek

从爪哇调用.NET Web服务(WSE 2/3,WS-Security)

  •  22
  • Michael Sharek  · 技术社区  · 16 年前

    我需要从Java中调用.NET编写的Web服务。Web服务实现了WS-Security堆栈(无论是WSE 2还是WSE 3,从我所掌握的信息来看都不清楚)。

    我从服务提供商处收到的信息包括WSDL、policycache.config文件、一些示例C代码和一个可以成功调用服务的示例应用程序。

    这并不像听起来那么有用,因为我不清楚我应该如何使用这些信息来编写Java客户端。如果没有根据策略对Web服务请求进行签名,则该服务将拒绝该请求。我正在尝试使用ApacheAxis2,但找不到任何关于如何使用policycahce.config文件和WSDL生成客户机的说明。

    我在网上找到了几个例子,但在所有的例子中,这些例子的作者都控制着服务和客户机,因此能够在两个方面进行调整以使其正常工作。我不在那个位置。

    有人成功地做到了吗?

    5 回复  |  直到 11 年前
        1
  •  10
  •   Zach    16 年前

    WS-Security规范通常不包含在WSDL中(从不包含在WSE WSDL中)。因此,wsdl2java不知道此服务甚至需要WS-Security。WSE WSDL中不存在安全约束这一事实令我非常失望(WCF将在WSDL中包含WS-Trust信息)。

    在客户端,您需要使用 Rampart 将必要的WS-Security头添加到传出客户机消息中。由于WSDL不报告哪些WS-Security设置是必需的,所以最好向服务提供者询问需要什么。WS-Security要求可以是简单的纯文本密码,也可以是X509证书,或者是加密消息…..Rampart应该能够处理大多数这些场景。

    ApacheRampart通过在axis2.xml文件中加入模块来“打开”。您需要下载Rampart模块并将其放在您的axis2目录中的特定位置,然后修改XML文件。您还可以通过编程方式启用Rampart(如果这是一项要求,请编辑您的原始问题,我将编辑此响应)。

    根据您如何配置Rampart(通过其他XML文件或编程),它将截获任何传出消息并向其中添加必要的WS-Security信息。我个人使用了带有Rampart的Axis2来调用一个wse3服务,该服务使用明文形式的usernametoken进行安全保护,并且工作得很好。类似的,但更高级的场景也应该起作用。有关如何在上面链接的网站上设置和开始使用Rampart的详细信息。如果您对Rampart的细节或如何在特定的WSE设置中使用Rampart有问题,请编辑您的问题,我将尽力回答。

        2
  •  10
  •   Michael Sharek    15 年前

    这似乎是一个很受欢迎的问题,所以我将概述一下我们在当前形势下所做的工作。

    似乎.NET中内置的服务遵循的是旧的WS-Addressing标准( http://schemas.xmlsoap.org/ws/2004/03/addressing/ )而Axis2只理解较新的标准( http://schemas.xmlsoap.org/ws/2004/08/addressing/ )

    此外,提供的policychcache.config文件的格式是Axis2 Rampart模块无法理解的。

    所以我们要做的步骤,简而言之:

    • 读取policychcache.config并尝试理解它。然后重写成Rampart能够理解的策略。(一些) updated docs 帮助了。
    • 使用此策略配置Rampart。
    • 获取.pfx文件中提供的键,并将它们转换为Java密钥存储。码头上有一个公用设施可以做到这一点。
    • 使用该密钥存储配置Rampart。
    • 编写一个自定义的axis2处理程序,它将从axis2出来的较新的WS-Addressing内容向后转换为服务所期望的较旧内容。
    • 配置axis2以在传出消息上使用处理程序。

    最后,它是一个由供应商支持的开放标准的配置和代码。

    虽然我不确定替代方案是什么……你能等供应商(或者在本例中,是唯一的供应商)来确保一切都能顺利进行吗?

    作为后记,我要补充的是,我并没有最终完成这项工作,这是我团队中的另一个人,但我认为我得到了显著的细节。我正在考虑的另一个选择(在我的队友接手之前)是直接调用wss4jAPI来构造.NET服务所期望的SOAP信封。我想那也会奏效的。

        3
  •  3
  •   ScArcher2    16 年前

    @迈克

    我最近做了一个测试,这是我使用的代码。 我没有使用策略工具,但是我使用了纯文本身份验证的WS-Security。 CXF有关于如何完成这些工作的非常好的文档。

    我使用了wsdl2java,然后添加了这段代码来使用带有WS-Security的Web服务。

    我希望这对你有帮助。

    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    
    import javax.security.auth.callback.Callback;
    import javax.security.auth.callback.CallbackHandler;
    import javax.security.auth.callback.UnsupportedCallbackException;
    
    import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
    import org.apache.ws.security.WSConstants;
    import org.apache.ws.security.WSPasswordCallback;
    import org.apache.ws.security.handler.WSHandlerConstants;
    
    public class ServiceTest implements CallbackHandler
    {
    
         public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
    
                WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
                // set the password for our message.
                pc.setPassword("buddah");
            }
    
        public static void main(String[] args){
            PatientServiceImplService locator = new PatientServiceImplService();
            PatientService service = locator.getPatientServiceImplPort();
    
            org.apache.cxf.endpoint.Client client = org.apache.cxf.frontend.ClientProxy.getClient(service);
            org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint();
    
            Map<String, Object> outProps = new HashMap<String, Object>();
            outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN + " " +  WSHandlerConstants.TIMESTAMP);
            outProps.put(WSHandlerConstants.USER, "joe");
            outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
    
            // Callback used to retrieve password for given user.
            outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ServiceTest.class.getName());
    
            WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
            cxfEndpoint.getOutInterceptors().add(wssOut);
    
    
            try
            {
                List list = service.getInpatientCensus();
                for(Patient p : list){
                    System.out.println(p.getFirstName() + " " + p.getLastName());
                }
    
            }
            catch (Exception e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    
        4
  •  2
  •   ESV Alconja    16 年前
        5
  •  0
  •   ScArcher2    16 年前

    CXF -我会调查一下CXF。我用它来使用WS-SecuRyTy在Java中创建Web服务和客户端。我还连接了一个.NET Web服务。

    他们也有相当好的文档。我比轴心国更幸运。