JAX WS client cannot authenticate
Asked Answered
F

2

11

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.

Forrer answered 14/3, 2014 at 14:35 Comment(5)
I have also tried Authenticator.setDefault(.......) approach and it also does not help me.Forrer
Well do you know what kind of Authentication is needed?Spook
@user1902288 nope, I am not sure which kind of authentication required. But as you can see I've already tried to use all the kinds I've found so far.Forrer
could you try out either of both suggestions?Spook
The authentication must be HTTP Basic authentication.Forrer
M
28

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");
    
Mingmingche answered 14/3, 2014 at 19:45 Comment(5)
Loc, could you teach mew what is the difference if I generate classes with wsimport and if I use the approach you suggested in 2. ?Forrer
Solution 1 using Static initialization for authentication -> the authentication is shared for ALL generated client stubs. Solution 2 is needed if different client stubs may have different Username/password.Mingmingche
ok, static initialization worked for me. I had also a stupid mistake in my code where I put that static authentication snippet AFTER initializing the webservice and the port. So after I figured it out everything worked just fine.Forrer
Instead of doing solution 1 if I use BindingProvider prov = (BindingProvider) port; prov.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "UserName"); prov.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "Password"); should it work ?Sp
@Sp I think it fails when instantiating the servicePokpoke
S
5

Lets try a few things:

1.) Do you know what kind of Authentication the server expects?

2.) When you try to access https://reporting-stage.admp.mtv3.adtlgc.com/admp/ReportingService?wsdl do you see anything? e.g. i assume there is a IP-Whitelist or something and you will enter credentials there or similar? Because i cant see anything there.

3.) When it comes to the code i authenticate to a secured webservice over HTTP this way:

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

Set above endpoint propertie to whatever is stored in your wsdl's wsdl:port... part which i expect to look something like this (and should be the default...):

 <wsdl:service name="ReportingServiceFoo">
    <wsdl:port binding="tns:ReportingServiceFoo" name="ReportingService">
        <soap:address location"https://myserver.com/ReportingService">
    </wsdl:port>
 </wsdl:service>

Edit:

The

BindingProvider.ENDPOINT_ADDRESS_PROPERTY

is used to set the target-endpoint at runtime. So if the webservice has a different endpoint than the one in the wsdl make sure to set it to the actual endpoint this way.

Spook answered 14/3, 2014 at 15:9 Comment(6)
Thanks for suggestions. Answers to your questions: 1) I do not know what kind of authentication it requires 2) If I enter that URL to my browser I see the popup opening asking me to enter username and password. I enter credentials and then I can see WSDL. And yes, there is probably IP whitelisting so you cannot see this.Forrer
O.k. so faar so good which means the authentication works as in most of our services... have you yet tryed "my" above code (i dont see much of a difference but lets just trySpook
address in this WSDL element is different from the actual address that the webservice is running on. I was told by a developer that this should not be a problem since address in the <soap:address> element is just a default address while the actual webservice may be deployed at other URL.Forrer
Exactly (sorry its a bit unclear in above answer), thats why i use BindingProvider.ENDPOINT_ADDRESS_PROPERTY to set the adress to the actual services endpoint at runtime (to override the default one of the WSDL). So after all that have you tryied it out?Spook
Note that i have to admit i am not sure if there is any difference between how you tried to set the credentials (3 aproaches) and how i set the credentials.Spook
Have you figured it out?Spook

© 2022 - 2024 — McMap. All rights reserved.