Java Web Service client basic authentication
I have created a JAX-WS Web Service on top of Glassfish which requires basic HTTP authentication.
Now I want to create a standalone java application client for that Web Service but I don't have a clue of how to pass the username and password.
It works with Eclipse's Web Service explorer, and examining the wire I found this:
开发者_如何学JAVAPOST /SnaProvisioning/SnaProvisioningV1_0 HTTP/1.1
Host: localhost:8080
Content-Type: text/xml; charset=utf-8
Content-Length: 311
Accept: application/soap+xml, application/dime, multipart/related, text/*
User-Agent: IBM Web Services Explorer
Cache-Control: no-cache
Pragma: no-cache
SOAPAction: ""
Authorization: Basic Z2VybWFuOmdlcm1hbg==
Connection: close
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:q0="http://ngin.ericsson.com/sna/types/v1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<q0:listServiceScripts/>
</soapenv:Body>
</soapenv:Envelope>
How do I pass the username and password in this "Authorization" header using java code? Is it hashed or something like that? What is the algorithm?
Without security involved I have a working standalone java client:
SnaProvisioning myPort = new SnaProvisioning_Service().getSnaProvisioningV10Port();
myPort.listServiceScripts();
The JAX-WS way for basic authentication is
Service s = new Service();
Port port = s.getPort();
BindingProvider prov = (BindingProvider)port;
prov.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "myusername");
prov.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "mypassword");
port.call();
It turned out that there's a simple, standard way to achieve what I wanted:
import java.net.Authenticator;
import java.net.PasswordAuthentication;
Authenticator myAuth = new Authenticator()
{
@Override
protected PasswordAuthentication getPasswordAuthentication()
{
return new PasswordAuthentication("german", "german".toCharArray());
}
};
Authenticator.setDefault(myAuth);
No custom "sun" classes or external dependencies, and no manually encode anything.
I'm aware that BASIC security is not, well, secure, but we are also using HTTPS.
for Axis2
client this may be helpful
...
serviceStub = new TestBeanServiceStub("<WEB SERVICE URL>"); // Set your value
HttpTransportProperties.Authenticator basicAuthenticator = new HttpTransportProperties.Authenticator();
List<String> authSchemes = new ArrayList<String>();
authSchemes.add(Authenticator.BASIC);
basicAuthenticator.setAuthSchemes(authSchemes);
basicAuthenticator.setUsername("<UserName>"); // Set your value
basicAuthenticator.setPassword("<Password>"); // Set your value
basicAuthenticator.setPreemptiveAuthentication(true);
serviceStub._getServiceClient().getOptions().setProperty(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, basicAuthenticator);
serviceStub._getServiceClient().getOptions().setProperty(org.apache.axis2.transport.http.HTTPConstants.CHUNKED, "false");
...
Some context additional about basic authentication, it consists in a header which contains the key/value pair:
Authorization: Basic Z2VybWFuOmdlcm1hbg==
where "Authorization" is the headers key, and the headers value has a string ( "Basic" word plus blank space) concatenated to "Z2VybWFuOmdlcm1hbg==", which are the user and password in base 64 joint by double dot
String name = "username";
String password = "secret";
String authString = name + ":" + password;
String authStringEnc = new BASE64Encoder().encode(authString.getBytes());
...
objectXXX.header("Authorization", "Basic " + authStringEnc);
If you are using a JAX-WS implementation for your client, such as Metro Web Services, the following code shows how to pass username and password in the HTTP headers:
MyService port = new MyService();
MyServiceWS service = port.getMyServicePort();
Map<String, List<String>> credentials = new HashMap<String,List<String>>();
credentials.put("username", Collections.singletonList("username"));
credentials.put("password", Collections.singletonList("password"));
((BindingProvider)service).getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, credentials);
Then subsequent calls to the service will be authenticated. Beware that the password is only encoded using Base64, so I encourage you to use other additional mechanism like client certificates to increase security.
This worked for me:
BindingProvider bp = (BindingProvider) port;
Map<String, Object> map = bp.getRequestContext();
map.put(BindingProvider.USERNAME_PROPERTY, "aspbbo");
map.put(BindingProvider.PASSWORD_PROPERTY, "9FFFN6P");
To make your life simpler, you may want to consider using JAX-WS framework such as Apache CXF or Apache Axis2.
Here is the link that describes how to setup WS-Security for Apache CXF -> http://cxf.apache.org/docs/ws-security.html
EDIT
By the way, the Authorization
field just uses simple Base64 encoding.
According to this ( http://www.motobit.com/util/base64-decoder-encoder.asp ), the decoded value is german:german
.
If you use JAX-WS, the following works for me:
//Get Web service Port
WSTestService wsService = new WSTestService();
WSTest wsPort = wsService.getWSTestPort();
// Add username and password for Basic Authentication
Map<String, Object> reqContext = ((BindingProvider)
wsPort).getRequestContext();
reqContext.put(BindingProvider.USERNAME_PROPERTY, "username");
reqContext.put(BindingProvider.PASSWORD_PROPERTY, "password");
The easiest option to get this working is to include Username and Password under of request. See sample below.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:typ="http://xml.demo.com/types" xmlns:ser="http://xml.demo.com/location/services"
xmlns:typ1="http://xml.demo.com/location/types">
<soapenv:Header>
<typ:requestHeader>
<typ:timestamp>?</typ:timestamp>
<typ:sourceSystemId>TEST</typ:sourceSystemId>
<!--Optional: -->
<typ:sourceSystemUserId>1</typ:sourceSystemUserId>
<typ:sourceServerId>1</typ:sourceServerId>
<typ:trackingId>HYD-12345</typ:trackingId>
</typ:requestHeader>
<wsse:Security soapenv:mustUnderstand="1"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-emmprepaid"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>your-username</wsse:Username>
<wsse:Password
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">your-password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<ser:getLocation>
<!--Optional: -->
<ser:GetLocation>
<typ1:locationID>HYD-GoldenTulipsEstates</typ1:locationID>
</ser:GetLocation>
</ser:getLocation>
</soapenv:Body>
</soapenv:Envelope>
For me below code works
Map<String, Object> requestContext = ((BindingProvider)port).getRequestContext();
Map<String, List<String>> requestHeaders = new HashMap<String, List<String>>();
String authString = "<Userid>" + ":" + "<Pwd>";
String authorization = Base64.getEncoder().encodeToString(authString.getBytes());
requestHeaders.put("Authorization", Collections.singletonList("Basic " + authorization));
requestContext.put(MessageContext.HTTP_REQUEST_HEADERS, requestHeaders);
精彩评论