JAX WS client cannot authenticate

Alexander Arendar picture Alexander Arendar · Mar 14, 2014 · Viewed 29k times · Source

I'm trying to consume a secure (HTTPS schema) web-service with help of standard JAVA 7 JAX WS tools. This web-service requires authentication.

I have already successfully added certificate to my local java keystore. All needed classes I've generated from WSDL file with help of wsimport tool.

Now I am trying to use the following call to run a simple test:

public class ReportingWebServiceTest {
    static ReportingServiceService service;
    static ReportingService port;

    @BeforeClass
    public static void setUpBeforeClass(){
        service = new ReportingServiceService();
        port = service.getReportingServicePort();
        Map<String, Object> rContext = ((BindingProvider) port).getRequestContext();
        Map<String, List<String>> headers = new HashMap<String, List<String>>();
        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);
    }
}

When I run the test it gives me following 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.<init>(WSServiceDelegate.java:220)
    at com.sun.xml.internal.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:168)
    at com.sun.xml.internal.ws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:96)
    at javax.xml.ws.Service.<init>(Service.java:77)
    at com.enreach.admp.reporting.ReportingServiceService.<init>(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

As you see I have tried to apply three different techniques of authentication but without any luck. Exception is the same in all three cases. What am I doing wrong?

P.S. if I try to access WSDL in browser the credentials I use in the code do work fine.

Answer

Loc picture Loc · Mar 14, 2014

Your issue is not relating to SSL certificate. Your issue is relating to Authentication. Service instance need to be able to access WSDL content (before your stub invoke actual web method) but It failed, that is why you got that error.

You have 2 solutions:

  1. Register default Authenticator:

    static {
    
        java.net.Authenticator.setDefault(new java.net.Authenticator() {
    
            @Override
            protected java.net.PasswordAuthentication getPasswordAuthentication() {
                return new java.net.PasswordAuthentication("myuser", "mypasswd".toCharArray());
            }
        });
    }
    
  2. Download WSDL document and save it to LOCAL storage then use local WSDL file. For this solution, you have to create Service instance, NOT use generated code as you did.

    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");