從Java調用.NET Web服務(WSE 2/3,WS-Security) (Calling .NET Web Service (WSE 2/3, WS-Security) from Java)


問題描述

從 Java 調用 .NET Web 服務(WSE 2/3,WS‑Security) (Calling .NET Web Service (WSE 2/3, WS‑Security) from Java)

我需要從 Java 調用一個用 .NET 編寫的 Web 服務。Web 服務實現了 WS‑Security 堆棧(WSE 2 或 WSE 3,從我掌握的信息中並不清楚)。

我從服務提供商那裡收到的信息包括 WSDL、一個 policyCache.config 文件、一些示例 C# 代碼和一個可以成功調用服務的示例應用程序。

這是'不像聽起來那麼有用,因為不清楚我應該如何使用這些信息來編寫 Java 客戶端。如果 Web 服務請求未根據策略簽名,則它會被服務拒絕。我正在嘗試使用 Apache Axis2,但找不到任何關於我應該如何使用 policyCahce.config 文件和 WSDL 來生成客戶端的說明。

我在 Web 上找到了幾個示例,但在所有情況下,示例的作者都控制了服務和客戶端,因此能夠在雙方進行調整以使其正常工作。我不在那個位置。

有沒有人成功做到這一點?


參考解法

方法 1:

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

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.

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

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.

方法 2:

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/).

In addition, the policyCache.config file provided is in a form that the axis2 rampart module can't understand.

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.)
  • 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.

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.

方法 3:

<p>@Mike</p>

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.

I used wsdl2java and then added this code to use the web service with ws‑security.

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:


#wse #java #ws-security #.net #axis2






相關問題

Windows 2000 下的 WSE 服務器 (WSE Server under Windows 2000)

在 wse 中使用自己的異常,而不僅僅是 SoapException (Using own exceptions in wse, not only SoapException)

從Java調用.NET Web服務(WSE 2/3,WS-Security) (Calling .NET Web Service (WSE 2/3, WS-Security) from Java)

從 WCF 調用 WSE 服務的提示? (Tips for calling WSE service from WCF?)

在 Web 服務 (WSE) 中公開自定義類型(類) (exposing custom types (classes) in a web service (WSE))

在具有自定義類型的 WSE 服務中,構造函數是否在消費客戶端工作? (In WSE services, with custom types, do constructors work on the consuming client's side?)

從 Visual Studio 2005 遷移到 2008 時要注意什麼? (What to look out for when moving from Visual Studio 2005 to 2008?)

通過代理調用 WSE Web 服務 (Calling a WSE web-service though a proxy)

VS 2008 上的 WSE 2.0 SP2 (WSE 2.0 SP2 on VS 2008)

如何在使用 WCF(或 WSE 3)的 Web 服務客戶端應用程序的請求和響應中混合消息編碼類型(文本/MTOM)? (How do I mix message encoding types (Text/MTOM) in the Request & Response of a Web Service client application using WCF (or WSE 3)?)

從 wsdl 創建肥皂 Web 服務客戶端,沒有合同方法 (Create soap web service client from wsdl with no contract methods)

Windows 上的 X.509 證書入門 (Primer for X.509 certificates on Windows)







留言討論