How to use digest authentication in httpBinding

I can't understand where I should write down username and password? Everytime I get 401 Unauthorized error as response.

I've never looked into this before. What would you use as the URL if you were entering directly in your browser?

Digest auth requires the credentials to be encoded in request headers, if I recall correctly. (Encoded, not just supplied.) You'll have to look up the HTTP standards for how to do this, if no one has it off the top of their heads. (I do not.)

Unfortunately it looks like digest authentication is not supported in either the binding or system.net.httpClient.

It is very strange.

Because I can choose such authentication type in binding

Hmm, I must have misunderstood the ticket I found for this.

I guess you have to put the precomputed value there, rather than supplying a username/password and it being computed for you.

(I'm not really sure how this is supposed to be obtained unless you end up making a digest-authenticated request from another HTTP client / tool and just copy it in)

Yeah, I'm gonna go ahead and stand by my original response... despite its appearance in the UI, it's essentially unsupported. It shouldn't be there.

Oh, ok.
So it is also necessary to remove the mention of this in the documentation

https://docs.inductiveautomation.com/display/DOC81/HTTP+Bindings+in+Perspective

Yes.

There's a link at the bottom of each doc page:

Found a problem? Send us an email: docs@inductiveautomation.com

I've also opened a ticket for this and mentioned both the configuration UI and the user manual.

1 Like

Would it be possible to get around this issue in the mean time with the python "requests" header?

And if so, how would I go about adding that to the scripting capabilities?

I know this is a little after the post has slowed down, please forgive me.

I can't take full credit for this, except for mostly the determination part... between myself and some AI assistance for library syntax (I didn't have any history with the hashlib or constructing digest headers) I put together this headers handshake for digestive using the httpClient and some integrated libraries. The example below is for an Axis camera, but I expect the concept would work for other digest situations. I was able to resolve the resulting data from the function into a perspective image control, so it seems functional. Don't forget to change the username and password.

import base64
import json
import re
import hashlib
import random

#constants
vapixClient = system.net.httpClient() #API Http Client
resolution = '1280x720'
uriRoot = 'http://'
uriImageJpg = '/axis-cgi/jpg/image.cgi?resolution='
username = "#####"
password = "#####"

def GetSnapshotFromCamera(IPAddress):
	
	uri = uriRoot + IPAddress + uriImageJpg + resolution
	#Send unauthenticated request
	response = vapixClient.get(uri, timeout=20000)
	
	if response:
		status = response.getStatusCode()
		auth_header = str(response.getHeaders().get("WWW-Authenticate"))
		
		if "Digest" in auth_header:
			#Parse required values from the auth challenge
			realm = re.search(r'realm="([^"]+)"', auth_header).group(1)
        	nonce = re.search(r'nonce="([^"]+)"', auth_header).group(1)
        	qop = re.search(r'qop="([^"]+)"', auth_header)
        	qop = qop.group(1) if qop else "auth"

            #Create HA1, HA2, and response hash
        	ha1 = hashlib.md5("{}:{}:{}".format(username, realm, password)).hexdigest()
        	ha2 = hashlib.md5("GET:{}".format(uri)).hexdigest()
        	nc = "00000001"  # Nonce count
        	cnonce = str(random.randint(0, 99999999))  # Client nonce
        	response_hash = hashlib.md5("{}:{}:{}:{}:{}:{}".format(ha1, nonce, nc, cnonce, qop, ha2)).hexdigest()

        	#Construct Digest Authorization header
        	auth_header_value = (
            	'Digest username="{}", realm="{}", nonce="{}", uri="{}", '
            	'algorithm=MD5, response="{}", qop={}, nc={}, cnonce="{}"'
        	).format(username, realm, nonce, uri, response_hash, qop, nc, cnonce)

        	#Send the authenticated request
        	headers = {"Authorization": auth_header_value}
        	response = vapixClient.get(uri, headers=headers)
        	status = response.getStatusCode()
        	if status == 200:
				data = response.getBody()
				en64 = "data:image/jpg;base64,"+base64.b64encode(data)
				return en64
3 Likes