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

时间:2020-03-05 18:40:47  来源:igfitidea点击:

我需要从Java调用用.NET编写的Web服务。该Web服务实现WS-Security堆栈(WSE 2或者WSE 3,从我掌握的信息中还不清楚)。

我从服务提供商那里收到的信息包括WSDL,policyCache.config文件,一些示例Ccode和可以成功调用该服务的示例应用程序。

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

我在Web上找到了几个示例,但是在所有情况下,示例的作者都控制了服务和客户端,因此能够对双方进行调整以使其正常工作。我不在那个位置。

有人成功做到了吗?

解决方案

回答

CXF我会研究CXF。我已使用它使用ws-secuirty在Java中创建Web服务和客户端。我还连接了一个.net Web服务。

他们也有很好的文档。我比轴更幸运。

回答

  • Apache Axis可以从WSDL http://ws.apache.org/axis/java/user-guide.html#UsingWSDLWithAxis生成代理代码
  • 带有RESTful Web服务插件的NetBeans可以为我们生成代码。有关用于eBay购物Web服务的示例客户端的说明,位于http://ebay.custhelp.com/cgi-bin/ebay.cfg/php/enduser/std_adp.php?p_faqid=1230。

回答

我想我应该更清楚一点,我已经使用wsdl2java代码生成器来生成服务的客户端代码。但是,生成的代码不包含必需的WS-Security SOAP标头,以便该服务将接受请求。

回答

@麦克风

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

我使用了wsdl2java,然后添加了此代码以将Web服务与ws-security一起使用。

我希望这能够帮到你。

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();
        }
    }
}

回答

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

在客户端上,我们将需要使用Rampart将必要的WS-Security标头添加到外发客户端消息中。由于WSDL不会报告必需的WS-Security设置,因此最好向服务提供商咨询需要什么。 WS-Security要求可以是简单的纯文本密码,也可以是X509证书,或者可以是加密的消息..... Rampart应该能够处理大多数此类情况。

通过在axis2.xml文件中使用该模块来"打开" Apache Rampart。我们需要下载Rampart模块并将其放置在axis2目录中的特定位置,然后修改xml文件。我们也可以通过编程方式参与Rampart(如果这是必要条件,请编辑原始问题,我将对此答复进行编辑)。

根据我们配置垒的方式(通过其他XML文件或者以编程方式),它会拦截所有传出的消息并向其中添加必要的WS-Security信息。我亲自使用axis2和ramart调用了WSE3服务,该服务以纯文本格式由UsernameToken保护,并且效果很好。类似但更高级的方案也应该起作用。在上面链接的网站上,有更多有关如何设置和开始使用Rampart的详细信息。如果我们对Rampart的细节或者如何在特定WSE设置中使用Rampart有疑问,请编辑问题,我将尽力回答。

回答

这似乎是一个很受欢迎的问题,所以我将概述我们在这种情况下所做的事情。

似乎.NET内置的服务遵循的是旧的ws寻址标准(http://schemas.xmlsoap.org/ws/2004/03/addressing/),而axis2仅理解较新的标准(http:// schemas。 xmlsoap.org/ws/2004/08/addressing/)。

此外,提供的policyCache.config文件的格式是axis2的ramart模块无法理解的格式。

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

  • 阅读policyCache.config并尝试理解它。然后将其重写为垒可以理解的策略。 (一些更新的文档有所帮助。)
  • 使用此策略配置城墙。
  • 取得.pfx文件中提供的密钥,并将其转换为Java密钥存储区。 Jetty附带有一个实用程序可以做到这一点。
  • 使用该密钥库配置垒。
  • 编写一个自定义的axis2处理程序,该处理程序将从axis2出来的较新的ws-addressing内容反向转换为该服务期望的较旧的内容。
  • 配置axis2以在传出消息上使用处理程序。

最后,许多东西和配置和代码应该是厂商支持的开放标准。

尽管我不确定替代方案是什么...我们可以等待供应商(或者在这种情况下,一个供应商)确保一切互操作吗?

作为后记,我要补充一点,我并没有结束工作,而是我团队中的其他人,但是我认为我的主要细节正确。我正在考虑的另一个选项(在我的队友接手之前)是直接调用WSS4J API来构造.NET服务所期望的SOAP信封。我认为那也行得通。