0

I'm trying to implement a Digest authentication based login using SHA-256 algorithm in java, but not getting much help. I'm able to login using POSTMAN and getting HTTP status code 200, but not sure how POSTMAN has used the SHA-256 here, Postman request config snapshot and My implementation below, which throws SSLHandshakeException. enter image description here

Here's my code using which I'm getting Handshake failure :

import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.http.*;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.*;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.auth.DigestScheme;
import org.apache.http.impl.client.*;

import junit.framework.Assert;

public class DigestTest {

    private static final String URL = "https://10.0.1.190/API/Web/Login";
    private static final String USER = "admin";
    private static final String PASSWORD = "testing123456";


    public static void main(String[] args) throws Exception {

        new DigestTest().run();
    }

    public void run() throws Exception {
        System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,SSLv3");

        HttpPost httpPost = new HttpPost(URL);

        HttpHost target
                = new HttpHost(httpPost.getURI().getHost(), 443, "https");
        CredentialsProvider credsProvider = new BasicCredentialsProvider();

        UsernamePasswordCredentials credentials
                = new UsernamePasswordCredentials(USER, PASSWORD);
        credsProvider.setCredentials(
                new AuthScope(target.getHostName(), target.getPort()),
                credentials);

        CookieStore cookieStore = new BasicCookieStore();

        CloseableHttpClient httpclient
                = HttpClients.custom().setDefaultCookieStore(cookieStore)
                        .setDefaultCredentialsProvider(credsProvider).build();

        try {

            DigestScheme digestAuth = new DigestScheme();

            digestAuth.overrideParamter("qop", "auth");
            digestAuth.overrideParamter("nc", "0");
            digestAuth.overrideParamter("cnonce", DigestScheme.createCnonce());
            digestAuth.overrideParamter("algorithm", "SHA-256");

            AuthCache authCache = new BasicAuthCache();
            authCache.put(target, digestAuth);

            HttpClientContext localContext = HttpClientContext.create();
            localContext.setAuthCache(authCache);

            CloseableHttpResponse response;

            response = httpclient.execute(target, httpPost, localContext);
            Map<String, String> wwwAuth = Arrays
                    .stream(response.getHeaders("WWW-Authenticate")[0]
                            .getElements())
                    .collect(Collectors.toMap(HeaderElement::getName,
                            HeaderElement::getValue));

            // the first call ALWAYS fails with a 401
//            Assert.assertEquals(response.getStatusLine().getStatusCode(), 401);

            digestAuth.overrideParamter("opaque", wwwAuth.get("opaque"));
            digestAuth.overrideParamter("nonce", wwwAuth.get("nonce"));
            digestAuth.overrideParamter("realm", wwwAuth.get("Digest realm"));
            Header authenticate = digestAuth.authenticate(credentials, httpPost,
                    localContext);
            httpPost.addHeader(authenticate);

            response = httpclient.execute(target, httpPost, localContext);

            // the 2nd call is the real deal
//            Assert.assertEquals(response.getStatusLine().getStatusCode(), 200);

            //System.out.println(IOUtils
              //      .toString(response.getEntity().getContent(), "utf-8"));
            System.out.println(response.getEntity().getContent().toString());

        } catch(Exception e){
            System.out.println("Exception : \n"+e);
        } finally {
            httpclient.close();
        }
    }

}

I'm getting the exception below :

Exception : javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

Please help with the code rectification.

1

1 Answer 1

0

In postman you can export your request to a code snippet (see https://learning.postman.com/docs/sending-requests/generate-code-snippets/ how).

In your case, the java snippet using the OkHttp client will be:

OkHttpClient client = new OkHttpClient().newBuilder()
  .build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody body = RequestBody.create(mediaType, "{}");
Request request = new Request.Builder()
  .url("https://test.it/uri")
  .method("POST", body)
  .addHeader("Authorization", 
             "Digest username=\"username\", realm=\"test\", nonce=\"nonce\", uri=\"/uri\", 
             algorithm=\"SHA-256\", 
             response=\"6d46e1187d1e79c88241d4ae0e57eda1cd572dfb027ce9eded02aea499f15695\""
  )
  .addHeader("Content-Type", "text/plain")
  .build();
Response response = client.newCall(request).execute();

(Notice that you need to replace the username, realm, nonce and uri with your actual values.).

To compute the response value, you can see the formula (for MD5) in https://en.wikipedia.org/wiki/Digest_access_authentication.

In the code above the computation with SHA256 instead of MD5 is the following:

HA1 = SHA256(username:realm:password) = SHA256(username:test:password) = 338c3ad443d25c378fdcdb90df9f81d42161278b8f1f03276a2d14f0803165f2
HA2 = SHA256(method:digestURI) = SHA256(POST:/uri) = fc51c21830fc2b6ffe97afe3290df89e7c2b1e287d6e373ad4282ce7fe912650
response = SHA256(HA1:nonce:HA2) = SHA256(338c3ad443d25c378fdcdb90df9f81d42161278b8f1f03276a2d14f0803165f2:nonce:fc51c21830fc2b6ffe97afe3290df89e7c2b1e287d6e373ad4282ce7fe912650)
= 6d46e1187d1e79c88241d4ae0e57eda1cd572dfb027ce9eded02aea499f15695
Sign up to request clarification or add additional context in comments.

3 Comments

While this is helpful, OP is using HttpClient and not OkHttp.
Thanks @Andrea , I've tried using OkHttp but not able to fetch response headers such as nonce, opaque, etc.
I don't think that is related with the authentication but with the certificate from your service

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.