How to Use Digest HTTP Authentication in soapUI

What is Digest Access Authentication?

Digest access authentication is a method a web server can use to negotiate credentials with a web browser. It uses encryption to send the credentials over the network which is safer than the (basic HTTP authentication - see my previous blog post) that sends plain text.

It is an application of MD5 cryptographic hashing using nonce values specified by RFC 2069 ( An Extension to HTTP: Digest Access Authentication) and later expanded by RFC 2617 (HTTP Authentication: Basic and Digest Access Authentication).

How does it work?

The same as  basic HTTP authentication when a client requests content for which authentication is required, the server informs a client that authentication is required and its authentication type. So, that would be something like this:

    1. Client sends request for some content:

      GET /user/list.html HTTP/1.1
      Host: localhost

    2. Server returns HTTP error 401 which means that authentication is required, with authentication type:

      HTTP/1.0 401 Unauthorized
      Server: HTTPd/0.9
      Date: Sun, 10 Apr 2005 20:26:47 GMT
      WWW-Authenticate: Digest realm="Secure Area",
      qop="auth,auth-int",
      nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
      opaque="5ccc069c403ebaf9f0171e9517f40e41"
      Content-Type: text/html
      Content-Length: 311

      <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
      "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
      <HTML>
      <HEAD>
      <TITLE>Error</TITLE>
      <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1">
      </HEAD>
      <BODY><H1>401 Unauthorized.</H1></BODY>
      </HTML>

      Where in the response header the following:

       

      WWW-Authenticate: Digest realm="Secure Area",
      qop="auth,auth-int",
      nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
      opaque="5ccc069c403ebaf9f0171e9517f40e41"

      is the HTTP header which carries this information. The header contains:

      • realm - A string to be displayed to users so they know which username and password to use.
      • qop - quality of protection, where auth indicates authentication and auth-int authentication with integrity protection
      • nonce - a server specified string
      • opaque - a server specified string


  1. Client sends the request again, with authentication:

    GET /user/list.html HTTP/1.0
    Host: localhost
    Authorization: Digest username="Robert",
    realm="Secure Area",
    nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
    uri="/user/list.html",
    qop=auth,
    nc=00000001,
    cnonce="0a4f113b",
    response="6629fae49393a05397450978507c4ef1",
    opaque="5ccc069c403ebaf9f0171e9517f40e41"

  2. Server then sends the requested content.

    What is what?

    • nonce is a server generated string which should be generated each time 401 a response is made. It is used in MD5 cryptographic hashing when sending authentication.
    • opaque is a server specified string which should be returned by the client unchanged in the subsequent request in the same protection space.
    • cnonce is a client nonce used by the client and server for mutual authentication, to avoid plain text attacks and message integrity. If a client sends qop, like above, this is a must.
    • nc is nonce count and it is a hexadecimal count of the number of requests. It is a must if the server sends qop directive, otherwise it is a must not. It is used by the server to detect if a request is replayed.
    • response is a string of 32 hex digits computed with MD5 cryptographic hashing, which holds credentials.

How to calculate a response?

In the first version ( RFC 2069 ) the algorithm is:

A1 = username:realm:password
A2 = method:digestURI
HA1 = MD5( A1 )
HA2 = MD5( A2 )
response = MD5( HA1:nonce:HA2 )

After RFC 2617 introduced qop HA2 it can be calculated:

  • qop = "auth";
    A2 = method:digestURI ( back compatability )

  • qop = "auth-int";
    A2 = method:digetsURI:MD5(entityBody)

  • qop = "auth" or (auth-int)
    response = MD5( HA1:nonce:nc:qop:HA2 )

  • qop not specified
    response = MD5( HA1:nonce:HA2 ) ( back compatability )

How does this work in soapUI?

Just to make things simple, I assume digest authentication is done like in RFC 2069. But even that will not make your life easier since digest HTTP authentication does not work out of the box in soapUI. soapUI’s request test steps work with a single request/response pair, they do not repeat a response after 401 is received, and for digest HTTP this is what is needed. So how do you execute it?

Well, with a little help of Groovy and the soapUI API. All that is needed is to set a Groovy script after a request test-step, which we will do next:

if( http 401 is received )
than if digest http is required
than
extract digest realm, nonce and opaque
calculate response
set http headers in request
repeat response

I will not write the whole script here but I’ll provide hints. Consider doing the whole script as homework. To calculate a response the following can be used:

import org.apache.commons.codec.digest.DigestUtils

def md5(user, realm, pass, method, String uri, nonce) {

def A1 = DigestUtils.md5Hex ("$user:$realm:$pass")
def A2 = DigestUtils.md5Hex ("$method:$uri")

DigestUtils.md5Hex ("$A1:$nonce:$A2")
}

To get headers from requests you can use:

def headers = testRunner.testCase.testSteps[<request step name >].testRequest.requestHeaders

Where testRunner is available in the Groovy test-step. To set headers you can use:

testRunner.testCase.testSteps[<request step name>].testRequest.setRequestHeaders( headers )

And to repeat the request again use:

import com.eviware.soapui.impl.wsdl.actions.teststep.RunFromTestStepAction
def action = new RunFromTestStepAction()
action.perform(testRunner.testCase.testSteps['PingOperation'], null)

Digest HTTP Authentication in soapUI MockService

This is the same situation as for basic HTTP authentication, only a script should be modified to extract a calculated response and a username from the request. There is no need to decode it, the server actually already knows the password, so it calculates a response for the given realm (set by the server itself) and the sent username by the client, and finally compares the response from the client and the calculated one.


That’s it...Now it is time to do your homework... :)

Robert

Follow me on Twitter

Follow soapUI on Twitter


Close

Add a little SmartBear to your life

Stay on top of your Software game with the latest developer tips, best practices and news, delivered straight to your inbox

By submitting this form, you agree to our
Terms of Use and Privacy Policy

Thanks for Subscribing

Keep an eye on your inbox for more great content.

Continue Reading