Question
· Jun 9, 2020

Consuming a REST Sevice with Digest Authenctication

Hi guys,

I'm trying to consume a REST Service that use Digest authentication, I'm trying to implement the authentication but I'm don't know where is my mistake.

Someone have already used this type of authentication.

Below the code I wrote to try to generate the response hash:

 // Algorithm reference: https://en.wikipedia.org/wiki/Digest_access_authentication
 //
 // Test data:
 // Do TestDigest^HC.Debug("posstman", "password", "/digest-auth", "postman-echo.com", 80)
 // Do TestDigest^HC.Debug("usr", "pwd", "/digest-auth/auth/usuario/senha/MD5", "httpbin.org", 80)
TestDigest(username, password, url, server, port) Public
{
Set httpRequest = ##Class(%Net.HttpRequest).%New()
Set httpRequest.Server = server
Set httpRequest.Port = port
Set statusCode = httpRequest.Send("GET", url)
If ($System.Status.IsError(statusCode))
{
Do $System.Status.DisplayError(statusCode)
}
Set authenticationData = httpRequest.HttpResponse.GetHeader("WWW-AUTHENTICATE")
Write !, "WWW-AUTHENTICATE: ", authenticationData, !
Set qop  = $$GetHeaderVar(authenticationData, "qop")
Set nonce = $$GetHeaderVar(authenticationData, "nonce")
Set realm = $$GetHeaderVar(authenticationData, "realm")
Set algorithm = $$GetHeaderVar(authenticationData, "algorithm")
Set nc = "00000001"
Set cnonce = $$HashValue($Horolog, 1)
Set hA1 = $$HashValue(username _ ":" _ realm _ ":" _ password)
If ($ZConvert(algorithm, "U") = "MD5-SESS")
{
Set hA1 = $$HashValue(hA1 _ ":" _ nonce _ ":" _ cnonce)
}
Set hA2 = $$HashValue("GET:" _ url)
If (qop '= "")
{
Set response = $$HashValue(hA1 _ ":" _ nonce _ ":" _ nc _ ":" _ cnonce _ ":" _ qop _ ":" _ hA2)
}
Else
{
Set response = $$HashValue(hA1 _ ":" _ nonce _ ":" _ hA2)
}
Set digestResponse = "Digest username=""*"",realm=""*"",nonce=""*"",uri=""*"",response=""*"",algorithm=""*"",qop=*,nc=*,cnonce=""*"""
Set digestResponse = $Replace(digestResponse, "*", username, 1, 1)
Set digestResponse = $Replace(digestResponse, "*", realm, 1, 1)
Set digestResponse = $Replace(digestResponse, "*", nonce, 1, 1)
Set digestResponse = $Replace(digestResponse, "*", url, 1, 1)
Set digestResponse = $Replace(digestResponse, "*", response, 1, 1)
Set digestResponse = $Replace(digestResponse, "*", algorithm, 1, 1)
Set digestResponse = $Replace(digestResponse, "*", qop, 1, 1)
Set digestResponse = $Replace(digestResponse, "*", nc, 1, 1)
Set digestResponse = $Replace(digestResponse, "*", cnonce, 1, 1)
//
Write !,"Authorization: ", digestResponse, !, !
//
Do httpRequest.SetHeader("Authorization", digestResponse)
//
Set statusCode = httpRequest.Send("GET", url)
If ($System.Status.IsError(statusCode))
{
Do $System.Status.DisplayError(statusCode)
}
Do httpRequest.HttpResponse.OutputToDevice()
}
HashValue(value) Public
{
Return $ZConvert(##Class(%xsd.hexBinary).LogicalToXSD($System.Encryption.MD5Hash(value)), "L")
}
GetHeaderVar(header, varName) Public 
{
    Set listVars = $ListFromString(header, ",")
    For index = 1 : 1 : $ListLength(listVars)
    {
    Set value = $List(listVars, index)
    If ($ZConvert(value, "U") [ $ZConvert(varName, "U"))
    {
    Return $Translate($Piece(value, "=", 2), """", "")
    }
    }
    Return ""
}
Discussion (2)1
Log in or sign up to continue

Hi Cristiano,

With some small changes, your code works for me:

Your comments on how to test should read:

/// Do TestDigest^HC.Debug("postman", "password", "/digest-auth", "postman-echo.com", 80)
/// Do TestDigest^HC.Debug("usuario", "senha", "/digest-auth/auth/usuario/senha/MD5", "httpbin.org", 80)

Change the line:

Set cnonce = $$HashValue($Horolog,1)

To:

Set cnonce = $$HashValue(+$Horolog)

After this line:

Set digestResponse = $Replace(digestResponse, "*", cnonce, 1, 1)

Add the following code:

// Opaque
Set opaque = $$GetHeaderVar(authenticationData, "opaque")
If opaque '= ""
{
Set digestResponse = digestResponse _ ",opaque=""" _ opaque _ """"
}

Hope this helps!