Dec 7, 2009

HTTP basic authentication with JAX-WS (Client)

JAX-WS does not do very well with HTTP basic authentication. In general, to create and use a web-service client you have to perform the following steps: 1. Use wsimport to generate the stub files 2. Create a service class in the client 3. Retrieve a proxy to the service, also known as a port All three steps could require HTTP basic authentication. And for each step it have to be handled in a different way.

1. The stub files generation

If access to a wsdl file is restricted with basic authentication, wsimport fails to get it. Unfortunately it does not support the common approach to write access credentials right into the
URL (RFC 1738). It is not a big deal to resolve this issue. You just need to create a server authentication file: $HOME/.metro/auth. This file should have the WSDL URL with username and password in the RFC 1738 format:
http[s]://user:password@host:port//
You can have line delimited multiple entries in this file and they can be used for various sites that need basic authentication.

2. The service class creation

A constructor of the service object requires access to the WSDL. And again it does not support basic authentication out of the box. You have an option to download the wsdl file and use it locally. Another option is to use the default authenticator:
Authenticator.setDefault(new Authenticator() {
 @Override
 protected PasswordAuthentication getPasswordAuthentication() {
   return new PasswordAuthentication(
     USER_NAME,
     PASSWORD.toCharArray());
 }
});

3. The service class configuration

And the last but not least part of our adventure is configuration of the service port:
OurWebService service = new OurWebService ();
OurWebServicePortType port = service.getOurWebServicePortType();

BindingProvider bindingProvider = (BindingProvider)port;
Map requestContext = bindingProvider.getRequestContext();
requestContext.put(BindingProvider.USERNAME_PROPERTY, USER_NAME);
requestContext.put(BindingProvider.PASSWORD_PROPERTY, PASSWORD);
Done! Now you are able to use methods of the port object to communicate with a web service.

16 comments:

Mike said...

Perfect - you saved me some trouble ;)

THX Mike

Unknown said...

Interestingly enough, we found step 3 was only necessary for running inside a Weblogic container. Glassfish seems to authenticate fine as long as the Authenticator.setDefault(..) is called with correct credentials.

Unknown said...

Saved my butt. lol Thanks.

Unknown said...

Saved my butt! LOL! Thanks.

Dawei Jin said...

Thank you! it works.
However just wondering if the following code is a global change, meaning that all program running in the same JVM will be affected?
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(
USER_NAME,
PASSWORD.toCharArray());
}
});


to be more precise, I have to WS to call, say, http://hotst1:8080/service1 and http://hotst2:8080/service2 . service1 requires username fool and password bar while service2 requires foo2:bar2.
How can I set different credentials for different services, since the method "setDefault" makes me think that all services will use the same credential.
Thank you again

Dawei Jin said...

Thank you! it works.
However just wondering if the following code is a global change, meaning that all program running in the same JVM will be affected?
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(
USER_NAME,
PASSWORD.toCharArray());
}
});


to be more precise, I have to WS to call, say, http://hotst1:8080/service1 and http://hotst2:8080/service2 . service1 requires username fool and password bar while service2 requires foo2:bar2.
How can I set different credentials for different services, since the method "setDefault" makes me think that all services will use the same credential.
Thank you again

knopfit said...

Thanx for the enlightenment.
I was really struggling with Basic Auth in a SAP Netweawer Webservice. Your post made it easy to bind and connect.

knopfit said...

Thanx for the enlightenment.
I was really struggling with Basic Auth in a SAP Netweawer Webservice. Your post made it easy to bind and connect.

Ramon Rockx said...

Thanks for these steps, helped me a lot.
Concerning step 1, for me it was necessary to set VM property -Dhttp.auth.preference=basic, otherwise NTLM authentication was used somehow. Also be sure you don't use too long username/password combinations, otherwise you might bump into base64 issues (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6459815). This one seems to be solved in Java 7.

Ramon

Unknown said...

Muchas gracias!

DEATH.COM said...

@knopfit

Hi, I am also facing the problem with SAP NetWeaver server authentication

In the above there methods, which code you fallowed??

Please give me your code, then it can help me lot.

Please...

Adrian said...

this helped on WLS
-DUseSunHttpHandler=true

Observer, Seeker, Finder said...

is there any answer to David's comment. I would be interested in that

GK Chaitanya said...

Thanks a lot.Its saved much time for me.Great help.

Krishna
www.ssrinfoservsystems.in

Anonymous said...

Thanks a ton!
It really worked for me and saved my time.

Anonymous said...

Excellent! worked as expected. Thanks a ton. keep it up