简体   繁体   中英

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:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM