简体   繁体   English

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

[英]Calling .NET Web Service (WSE 2/3, WS-Security) from Java

I need to call a web service written in .NET from Java. 我需要从Java调用用.NET编写的Web服务。 The web service implements the WS-Security stack (either WSE 2 or WSE 3, it's not clear from the information I have). Web服务实现了WS-Security堆栈(WSE 2或WSE 3,从我的信息中不清楚)。

The information that I received from the service provider included WSDL, a policyCache.config file, some sample C# code, and a sample application that can successfully call the service. 我从服务提供商处收到的信息包括WSDL,policyCache.config文件,一些示例C#代码以及可以成功调用服务的示例应用程序。

This isn't as useful as it sounds because it's not clear how I'm supposed to use this information to write a Java client. 这听起来没那么有用,因为我不清楚我应该如何使用这些信息来编写Java客户端。 If the web service request isn't signed according to the policy then it is rejected by the service. 如果Web服务请求未根据策略签名,则服务将拒绝该服务请求。 I'm trying to use Apache Axis2 and I can't find any instructions on how I'm supposed to use the policyCahce.config file and the WSDL to generate a client. 我正在尝试使用Apache Axis2,我找不到任何有关如何使用policyCahce.config文件和WSDL来生成客户端的说明。

There are several examples that I have found on the Web but in all cases the authors of the examples had control of both the service and the client and so were able to make tweaks on both sides in order to get it to work. 我在网上找到了几个例子,但在所有情况下,示例的作者都控制了服务和客户端,因此能够对双方进行调整以使其工作。 I'm not in that position. 我不在那个位置。

Has anyone done this successfully? 有人做过这个吗?

This seems to be a popular question so I'll provide an overview of what we did in our situation. 这似乎是一个受欢迎的问题,因此我将概述我们在我们的情况下所做的工作。

It seems that services built in .NET are following an older ws-addressing standard ( http://schemas.xmlsoap.org/ws/2004/03/addressing/ ) and axis2 only understands the newer standard ( http://schemas.xmlsoap.org/ws/2004/08/addressing/ ). 似乎用.NET构建的服务遵循较旧的ws-addressing标准( http://schemas.xmlsoap.org/ws/2004/03/addressing/ ),而axis2只能理解较新的标准( http:// schemas。 xmlsoap.org/ws/2004/08/addressing/ )。

In addition, the policyCache.config file provided is in a form that the axis2 rampart module can't understand. 此外,提供的policyCache.config文件采用axis2 rampart模块无法理解的形式。

So the steps we had to do, in a nutshell: 所以我们必须采取的步骤,简而言之:

  • Read the policyCache.config and try to understand it. 阅读policyCache.config并尝试理解它。 Then rewrite it into a policy that rampart could understand. 然后将其重写为一个可以理解的策略。 (Some updated docs helped.) (一些更新的文档有帮助。)
  • Configure rampart with this policy. 使用此策略配置rampart。
  • Take the keys that were provided in the .pfx file and convert them to a java key store. 获取.pfx文件中提供的密钥并将其转换为Java密钥库。 There is a utility that comes with Jetty that can do that. Jetty附带的实用程序可以做到这一点。
  • Configure rampart with that key store. 使用该密钥库配置rampart。
  • Write a custom axis2 handler that backward-converts the newer ws-addressing stuff that comes out of axis2 into the older stuff expected by the service. 编写一个自定义的axis2处理程序,它将来自axis2的较新的ws-addressing东西反向转换为服务所期望的旧东西。
  • Configure axis2 to use the handler on outgoing messages. 配置axis2以在传出消息上使用处理程序。

In the end it was a lot of configuration and code for something that is supposed to be an open standard supported by the vendors. 最后,很多配置和代码都应该是供应商支持的开放标准。

Although I'm not sure what the alternative is...can you wait for the vendors (or in this case, the one vendor) to make sure that everything will inter-op? 虽然我不确定替代方案是什么......你可以等待供应商(或者在这种情况下,一个供应商)确保一切都将是互操作的吗?

As a postscript I'll add that I didn't end up doing the work, it was someone else on my team, but I think I got the salient details correct. 作为后记我会补充一点,我最终没有完成这项工作,这是我团队中的其他人,但我认为我的重要细节是正确的。 The other option that I was considering (before my teammate took over) was to call the WSS4J API directly to construct the SOAP envelope as the .NET service expected it. 我正在考虑的另一个选项(在我的队友接手之前)是直接调用WSS4J API来构建SOAP信封,就像.NET服务所期望的那样。 I think that would have worked too. 我认为这也会奏效。

WS-Security specifications are not typically contained in a WSDL (never in a WSE WSDL). WS-Security规范通常不包含在WSDL中(从不在WSE WSDL中)。 So wsdl2java does not know that WS-Security is even required for this service. 所以wsdl2java不知道这项服务甚至需要WS-Security。 The fact that security constraints are not present in a WSE WSDL is a big disappointment to me (WCF will include WS-Trust information in a WSDL). WSE WSDL中不存在安全性约束这一事实对我来说是一个很大的失望(WCF将在WSDL中包含WS-Trust信息)。

On the client end, you'll need to use Rampart to add the necessary WS-Security headers to your outgoing client message. 在客户端,您需要使用Rampart将必要的WS-Security标头添加到传出客户端消息中。 Since the WSDL does not report what WS-Security settings are necessary, you're best off by asking the service provider what is required. 由于WSDL不报告需要哪些WS-Security设置,因此最好向服务提供商询问所需的内容。 WS-Security requirements may be simple plaintext password, or might be X509 certificates, or might be encrypted message..... Rampart should be able to handle most of these scenarios. WS-Security要求可能是简单的明文密码,或者可能是X509证书,或者可能是加密消息...... Rampart应该能够处理大多数这些场景。

Apache Rampart is "turned on" by engaging the module in your axis2.xml file. 通过在axis2.xml文件中使用模块来“打开”Apache Rampart。 You'll need to download the Rampart module and put it in a specific place in your axis2 directory, then modify the xml file. 您需要下载Rampart模块并将其放在axis2目录中的特定位置,然后修改xml文件。 You can also engage Rampart programatically (please edit your original question if this is a requirement and I'll edit this response). 您也可以以编程方式使用Rampart(如果需要,请编辑原始问题,我将编辑此响应)。

Depending on how you configure rampart (through other XML files or programatically), it will intercept any outgoing messages and add the necessary WS-Security information to it. 根据您配置rampart的方式(通过其他XML文件或以编程方式),它将拦截任何传出消息并向其添加必要的WS-Security信息。 I've personally used axis2 with rampart to call a WSE3 service that is secured with UsernameToken in plaintext and it worked great. 我个人使用带有rampart的axis2来调用一个用明文用UsernameToken保护的WSE3服务,它工作得很好。 Similar, but more advanced scenarios should also work. 类似但更高级的方案也应该有效。 There are more details on how to set up and get started with Rampart on the site linked above. 有关如何在上面链接的网站上设置和开始使用Rampart的详细信息。 If you have problems about the specifics of Rampart or how to use Rampart with your particular WSE setup, then edit your question and I'll try my best to answer. 如果您对Rampart的具体问题或如何在您的特定WSE设置中使用Rampart有疑问,请编辑您的问题,我会尽力回答。

@Mike @麦克风

I recently did a test and this is the code I used. 我最近做了一个测试,这是我使用的代码。 I'm not using policy stuff, but I used WS-Security with plain text authentication. 我没有使用策略,但我使用了WS-Security和纯文本身份验证。 CXF has really good documentation on how to accomplish this stuff. CXF在如何完成这些工作方面有很好的文档。

I used wsdl2java and then added this code to use the web service with ws-security. 我使用wsdl2java然后添加此代码以使用带有ws-security的Web服务。

I hope this helps you out. 我希望这能够帮到你。

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

CXF - I'd look into CXF. CXF - 我会看看CXF。 I've used it to create a web service and client in java using ws-secuirty. 我用它来使用ws-secuirty在java中创建一个Web服务和客户端。 I also connected a .net web service to it. 我还连接了一个.net Web服务。

They have pretty good documentation too. 他们也有很好的文档。 I had more luck with it than axis. 我比它更幸运。

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

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