JAX WS客户端无法进行身份validation

我正在尝试使用标准JAVA 7 JAX WS工具来使用安全(HTTPS模式)Web服务。 此Web服务需要身份validation。

我已经成功将证书添加到我的本地java密钥库。 我借助wsimport工具从WSDL文件生成所有需要的类。

现在我尝试使用以下调用来运行一个简单的测试:

 public class ReportingWebServiceTest { static ReportingServiceService service; static ReportingService port; @BeforeClass public static void setUpBeforeClass(){ service = new ReportingServiceService(); port = service.getReportingServicePort(); Map rContext = ((BindingProvider) port).getRequestContext(); Map<String, List> headers = new HashMap<String, List>(); headers.put("Authorization", Collections.singletonList("Basic YWRtaW5AYWRhcHRsb2dpYy5jb206MTIxMjE****=")); // headers.put("Username", Collections.singletonList("*****@******.com")); // headers.put("Password", Collections.singletonList("********")); rContext.put(MessageContext.HTTP_REQUEST_HEADERS, headers); // rContext.put(BindingProvider.USERNAME_PROPERTY, "*****@******.com"); // rContext.put(BindingProvider.PASSWORD_PROPERTY, "********"); } @Test public void test() { WEBCAMPAIGNROW row = port.getCampaignRowById(14081); toConsole(row.toString()); } protected static void toConsole(String msg) { System.out.println(msg); } } 

当我运行测试时,它给出了以下exception:

 javax.xml.ws.WebServiceException: Failed to access the WSDL at: https://reporting-stage.admp.mtv3.adtlgc.com/admp/ReportingService?wsdl. It failed with: Got Server returned HTTP response code: 401 for URL: https://reporting-stage.admp.mtv3.adtlgc.com/admp/ReportingService?wsdl while opening stream from https://reporting-stage.admp.mtv3.adtlgc.com/admp/ReportingService?wsdl. at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.tryWithMex(RuntimeWSDLParser.java:173) at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:155) at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:120) at com.sun.xml.internal.ws.client.WSServiceDelegate.parseWSDL(WSServiceDelegate.java:257) at com.sun.xml.internal.ws.client.WSServiceDelegate.(WSServiceDelegate.java:220) at com.sun.xml.internal.ws.client.WSServiceDelegate.(WSServiceDelegate.java:168) at com.sun.xml.internal.ws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:96) at javax.xml.ws.Service.(Service.java:77) at com.enreach.admp.reporting.ReportingServiceService.(ReportingServiceService.java:42) at me.enreach.automation.mtv3.ReportingWebServiceTest.setUpBeforeClass(ReportingWebServiceTest.java:26) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24) at org.junit.runners.ParentRunner.run(ParentRunner.java:309) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) Caused by: java.io.IOException: Got Server returned HTTP response code: 401 for URL: https://reporting-stage.admp.mtv3.adtlgc.com/admp/ReportingService?wsdl while opening stream from https://reporting-stage.admp.mtv3.adtlgc.com/admp/ReportingService?wsdl at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.createReader(RuntimeWSDLParser.java:842) at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.resolveWSDL(RuntimeWSDLParser.java:283) at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:140) ... 23 more Caused by: java.io.IOException: Server returned HTTP response code: 401 for URL: https://reporting-stage.admp.mtv3.adtlgc.com/admp/ReportingService?wsdl at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1626) at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254) at java.net.URL.openStream(URL.java:1037) at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.createReader(RuntimeWSDLParser.java:827) ... 25 more 

如你所见,我试图应用三种不同的身份validation技术,但没有任何运气。 在所有三种情况下,例外情况都是相同的。 我究竟做错了什么?

PS如果我尝试在浏览器中访问WSDL,我在代码中使用的凭据可以正常工作。

您的问题与SSL证书无关。 您的问题与身份validation有关。 服务实例需要能够访问WSDL内容(在您的存根调用实际Web方法之前)但它失败了,这就是您遇到该错误的原因。

你有2个解决方案:

  1. 注册默认身份validation器:

     static { java.net.Authenticator.setDefault(new java.net.Authenticator() { @Override protected java.net.PasswordAuthentication getPasswordAuthentication() { return new java.net.PasswordAuthentication("myuser", "mypasswd".toCharArray()); } }); } 
  2. 下载WSDL文档并将其保存到LOCAL存储,然后使用本地WSDL文件。 对于此解决方案,您必须创建Service实例,而不是像您一样使用生成的代码。

     Service service = Service.create( new URL(**"file:///C:/reportingService.wsdl"**), new QName("http://services.app/", "ReportingService") ); // ... binding.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "myuser"); binding.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "mypasswd"); 

让我们尝试一些事情:

1.)您知道服务器期望的身份validation类型吗?

2.)当您尝试访问https://reporting-stage.admp.mtv3.adtlgc.com/admp/ReportingService?wsdl时 ,您看到了什么吗? 例如,我假设有一个IP白名单或其他东西,你会在那里输入凭证或类似的? 因为我看不到任何东西。

3.)当涉及到代码时,我通过HTTP以这种方式对安全的Web服务进行身份validation:

 ReportingServiceService service new ReportingServiceService(); ReportingService port = service.getReportingServicePort(); BindingProvider binding = (BindingProvider) port; // Configure service endpoint (override defined one of the WSDL) BindingProvider binding = (BindingProvider) port; binding.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "https.."); // Add HTTP Basic Authentification credentials to this request binding.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "myuser"); binding.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "mypasswd"); port.getCampaignRowById(14081); 

将端点属性设置为存储在wsdl的wsdl:port …中的任何内容,我希望看起来像这样(并且应该是默认值…):

       

编辑

 BindingProvider.ENDPOINT_ADDRESS_PROPERTY 

用于在运行时设置目标端点。 因此,如果Web服务的端点与wsdl中的端点不同,请确保以这种方式将其设置为实际端点。