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

时间:2021-08-14 09:57:17

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?

有人做过这个吗?

6 个解决方案

#1


9  

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 Rampart to 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).

通过在axis2.xml文件中使用模块来“打开”Apache Rampart。您需要下载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.

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

#2


9  

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. Then rewrite it into a policy that rampart could understand. (Some updated docs helped.)
  • 阅读policyCache.config并尝试理解它。然后将其重写为一个可以理解的策略。 (一些更新的文档有帮助。)
  • Configure rampart with this policy.
  • 使用此策略配置rampart。
  • 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.
  • 获取.pfx文件中提供的密钥并将其转换为Java密钥库。 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. I think that would have worked too.

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

#3


2  

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

#4


1  

#5


0  

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。我用它来使用ws-secuirty在java中创建一个Web服务和客户端。我还连接了一个.net Web服务。

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

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

#6


0  

I guess I should be more clear - I have used the wsdl2java code generators to generate client code for the service. However the generated code does not include the necessary WS-Security SOAP headers so that the service will accept the requests.

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

#1


9  

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 Rampart to 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).

通过在axis2.xml文件中使用模块来“打开”Apache Rampart。您需要下载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.

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

#2


9  

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. Then rewrite it into a policy that rampart could understand. (Some updated docs helped.)
  • 阅读policyCache.config并尝试理解它。然后将其重写为一个可以理解的策略。 (一些更新的文档有帮助。)
  • Configure rampart with this policy.
  • 使用此策略配置rampart。
  • 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.
  • 获取.pfx文件中提供的密钥并将其转换为Java密钥库。 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. I think that would have worked too.

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

#3


2  

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

#4


1  

#5


0  

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。我用它来使用ws-secuirty在java中创建一个Web服务和客户端。我还连接了一个.net Web服务。

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

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

#6


0  

I guess I should be more clear - I have used the wsdl2java code generators to generate client code for the service. However the generated code does not include the necessary WS-Security SOAP headers so that the service will accept the requests.

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