10

I am trying to connect to the Tomcat Web Server on my machine using a digest authentication. I am using the memory realm of tomcat. Here is how the server is configured:

1) In server.xml:

<Realm className="org.apache.catalina.realm.MemoryRealm" digest="MD5" />

2) In tomcat-users.xml

<user username="testuser" password="81dc9bdb52d04dc20036dbd8313ed055" roles="test"/>

3) In web.xml of my web project:

<auth-method>DIGEST</auth-method>

As you can see I have specified as a digest method "MD5" and I have encryped the password using the digest.sh of Tomcat.

Here is my code on the client side:

private static void testGet() throws IOException {

    // Create a URL
    URL test = new URL("http://localhost:8080/TestWebProject/TestServlet");

    // Open a connection to the URL
    HttpURLConnection conn = (HttpURLConnection) test.openConnection();

    MessageDigest md5 = null;
    try {
      md5 = MessageDigest.getInstance("MD5");
    } catch(NoSuchAlgorithmException e) {
      e.printStackTrace();
    }

    // Digest password using the MD5 algorithm
    String password = "1234";
    md5.update(password.getBytes());
    String digestedPass = digest2HexString(md5.digest());

    // Set header "Authorization"
    String credentials = "testuser:" + digestedPass;
    conn.setRequestProperty("Authorization", "Digest " + credentials);

    // Print status code and message
    System.out.println("Test HTTP GET method:");
    System.out.println("Status code: " + conn.getResponseCode());
    System.out.println("Message: " + conn.getResponseMessage());
    System.out.println();

}

private static String digest2HexString(byte[] digest)
{
   String digestString="";
   int low, hi ;

   for(int i=0; i < digest.length; i++)
   {
      low =  ( digest[i] & 0x0f ) ;
      hi  =  ( (digest[i] & 0xf0)>>4 ) ;
      digestString += Integer.toHexString(hi);
      digestString += Integer.toHexString(low);
   }
   return digestString ;
}

I think that my client side code is ok and the configuration of the server, too. Though the server keeps sending me the status code 401 with message "Unauthorized". As I am not an experienced java developer, I want to ask if anyone has idea or sees an error in my implementation.

Thank you in advance!

user485624
  • 141
  • 2
  • 2
  • 4
  • Generally, if digest authentication is not obligatory, it may be better to use HTTPS connection and some standard HTML-based authentication form, because HTTP authentication does not support "Log out" until client closes web browser. – Kel Oct 24 '10 at 14:13
  • Possible duplicate of [Digest authentication in Android using HttpURLConnection](http://stackoverflow.com/questions/32689185/digest-authentication-in-android-using-httpurlconnection) – ceph3us Jan 24 '16 at 07:30

5 Answers5

5

Digest authentication is far more complex than just sending username:password (that is actually Basic authentication... and the username:password tuple needs to be Base64 encoded!).

You can read all about digest here.

If you're not required to use HttpUrlConnection take a look at these two projects:

Both of them already support Digest (and other useful stuff) out of the box.

biasedbit
  • 2,860
  • 4
  • 30
  • 47
2

HttpUrlConnection is OK for simple jobs, but if you want something with more advanced features (like digest authentication), I'd recommend Commons HTTP Client.

Mike Baranczak
  • 8,291
  • 8
  • 47
  • 71
2

I am able to get it done working following code, please let me know if i am missing something;

        DefaultHttpClient httpclient = new DefaultHttpClient();

        ResponseHandler<String> responseHandler = new BasicResponseHandler();

        httpclient.getCredentialsProvider().setCredentials(
                new AuthScope("localhost", 8080), 
                new UsernamePasswordCredentials("username", "password"));   

        HttpGet httpget = new HttpGet(urlStr);
         System.out.println("executing request" + httpget.getRequestLine());

        String response = httpclient.execute(httpget, responseHandler);
        System.out.println("Response :: " + response);
Maths
  • 37
  • 1
  • DefaultHttpClient in now deprecated and HttpClient has no longer getCredentialsProvider method ... does anyone has a updated example? – Rafael Feb 28 '14 at 22:14
  • This has nothing to do with digest authentication, this is basic HTTP auth ;) – Sobvan Jul 10 '18 at 22:35
  • The OP asked for HttpURLConnection and this is using Apache HTTP Client. – Alex R Oct 28 '18 at 03:25
1

Use the following code, it works if your server doesn't require an 'opaque' return.

import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;

CredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(
                new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
                new UsernamePasswordCredentials(username, password));
        CloseableHttpClient httpclient = HttpClients.custom()
                .setDefaultCredentialsProvider(credsProvider)
                .build();


HttpResponse response = httpClient.execute(get);
Alex R
  • 11,364
  • 15
  • 100
  • 180
Yandrapu
  • 27
  • 1
1

Strangely enough Digest authentication works natively on jdk with this code while Basic auth does not:

Authenticator.setDefault(new Authenticator() {

    @Override
    protected PasswordAuthentication getPasswordAuthentication() {

        return new PasswordAuthentication (
            "username",
            "password".toCharArray()
        );
    }
});
ron190
  • 1,032
  • 1
  • 17
  • 29