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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16451/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 10:45:07  来源:igfitidea点击:

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

java.netaxis2ws-securitywse

提问by Michael Sharek

I need to call a web service written in .NET from Java. The web service implements the WS-Security stack (either WSE 2 or WSE 3, it's not clear from the information I have).

我需要从 Java 调用用 .NET 编写的 Web 服务。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. If the web service request isn't signed according to the policy then it is rejected by the service. 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.

这并不像听起来那么有用,因为我不清楚应该如何使用这些信息来编写 Java 客户端。如果未根据策略对 Web 服务请求进行签名,则该请求将被服务拒绝。我正在尝试使用 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?

有没有人成功地做到了这一点?

采纳答案by Michael Sharek

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.xml) 。 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 城墙模块无法理解的。

So the steps we had to do, in a nutshell:

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

  • Read the policyCache.config and try to understand it. Then rewrite it into a policy that rampart could understand. (Some updated docshelped.)
  • Configure rampart with this policy.
  • Take the keys that were provided in the .pfx file and convert them to a java key store. There is a utility that comes with Jetty that can do that.
  • Configure rampart with that key store.
  • 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.
  • Configure axis2 to use the handler on outgoing messages.
  • 阅读 policyCache.config 并尝试理解它。然后将其重写为壁垒可以理解的策略。(一些更新的文档有所帮助。)
  • 使用此策略配置城墙。
  • 获取 .pfx 文件中提供的密钥并将它们转换为 Java 密钥存储。Jetty 附带的实用程序可以做到这一点。
  • 使用该密钥库配置城墙。
  • 编写一个自定义的axis2 处理程序,将来自axis2 的较新的ws-addressing 内容向后转换为服务期望的较旧的内容。
  • 将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. I think that would have worked too.

作为后记,我要补充一点,我最终没有完成这项工作,是我团队中的其他人完成的,但我认为我的主要细节是正确的。我正在考虑的另一个选择(在我的队友接手之前)是直接调用 WSS4J API 来构造 SOAP 信封,正如 .NET 服务所期望的那样。我认为这也会奏效。

回答by Zach

WS-Security specifications are not typically contained in a WSDL (never in a WSE WSDL). So wsdl2java does not know that WS-Security is even required for this service. 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).

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

On the client end, you'll need to use Rampartto add the necessary WS-Security headers to your outgoing client message. Since the WSDL does not report what WS-Security settings are necessary, you're best off by asking the service provider what is required. 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.

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

Apache Rampart is "turned on" by engaging the module in your axis2.xml file. You'll need to download the Rampart module and put it in a specific place in your axis2 directory, then modify the xml file. You can also engage Rampart programatically (please edit your original question if this is a requirement and I'll edit this response).

Apache Rampart 通过在axis2.xml 文件中使用该模块来“打开”。您需要下载 Rampart 模块并将其放在axis2 目录中的特定位置,然后修改xml 文件。您也可以以编程方式参与 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. I've personally used axis2 with rampart to call a WSE3 service that is secured with UsernameToken in plaintext and it worked great. 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. 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.

根据您配置城墙的方式(通过其他 XML 文件或以编程方式),它将拦截任何传出消息并向其添加必要的 WS-Security 信息。我个人使用带壁垒的axis2 来调用WSE3 服务,该服务以纯文本形式使用UsernameToken 进行保护,并且效果很好。类似但更高级的场景也应该有效。在上面链接的网站上有更多关于如何设置和开始使用 Rampart 的详细信息。如果您对 Rampart 的细节或如何在特定的 WSE 设置中使用 Rampart 有疑问,请编辑您的问题,我会尽力回答。

回答by ScArcher2

@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. CXF has really good documentation on how to accomplish this stuff.

我最近做了一个测试,这是我使用的代码。我没有使用策略的东西,但我使用了纯文本身份验证的 WS-Security。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();
        }
    }
}

回答by ESV

回答by ScArcher2

CXF- I'd look into CXF. I've used it to create a web service and client in java using ws-secuirty. I also connected a .net web service to it.

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

They have pretty good documentation too. I had more luck with it than axis.

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