Consuming a REST Sevice with Digest Authenctication

Primary tabs

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 ""
}

Replies

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!

Thanks Navarro,

I don't see the typo in te test data, and with the change of the cnonce calculation works like a charm.

For my specific case,  the service doesn't send de opaque, but I changed the code to support the opaque too.

Abraço.