Dim hj As HttpJob
hj.Initialize("",Me)
hj.Username="admin"
hj.Password="password"
hj.Download("http://192.168.5.188/relay/0?turn=on")
Wait for (hj) JobDone(hj As HttpJob)
If hj.Success Then
label1.Text = hj.GetString
Else
label1.Text ="Error"
End If
Try the code below. I've tested it against https://httpbin.org/digest-auth/auth/test/test3/SHA-256 and it seems to work. The code is not all-encompassing regarding the RFC spec and only handles GET requests, but hopefully, it implements enough to work for your needs.what would be the proper format for sha-256 digest auth ? code snippet would be nice
Wait For(AuthenticateUrl("https://httpbin.org/digest-auth/auth/test/test3/SHA-256", "test", "test3")) Complete (j As HttpJob)
If j.Success = True
'successfully authenticated
Log(j.GetString)
Else
Log(j.ErrorMessage)
End If
'See...
pretty much everything.I get an error "Unauthorized", but the credentials are correct. What's wrong here ???
more involved than that.It seems you need to construct the authentication by concatenating "username":"device-model":"password" and hash it with SHA256. Then pass the value in Get header.
It's an http 401 errorPlease post the exact text of the error
i thought that Android or the okhttputils2 lib would handle all this stuff ?!?!where's the digest? how are you constructing it? where's the realm and the nonce returned by the server? there's a series of handshaking steps to be taken;
There is no one standard in implementing security in API. Some API developers put the security in header, some put in body, some build a digest of both. The user name and password way you use is for Basic Authentication. There are also JWT, HMAC, Public-Private key, Digital Signature, API Keys, etc.i thought that Android or the okhttputils2 lib would handle all this stuff ?!?!
You mean can I use B4A to make such API calls?Doesn't B4A handle this ?
It's a Shelly plus 2 PM. A detailed docu about the authorization can be read here: https://shelly-api-docs.shelly.cloud/gen2/General/Authentication/Can you specify which device or model you are working on?
I have no anger. just wanted to express that i was wondering why the okhttputils2 lib doesn't work with that kind of authorization.Note: Putting ?!?! to express your anger doesn't help.
That's not correct. The docu to httpjob says that digest authorization would work that way too ! See this: https://www.b4x.com/android/forum/threads/set-http-request-header-with-httputils2.78408/The user name and password way you use is for Basic Authentication.
Usually for Basic Authentication, we use Base64Encode username : password like example by @EnriqueGonzalezIt's a Shelly plus 2 PM. A detailed docu about the authorization can be read here: https://shelly-api-docs.shelly.cloud/gen2/General/Authentication/
I have no anger. just wanted to express that i was wondering why the okhttputils2 lib doesn't work with that kind of authorization.
That's not correct. The docu to httpjob says that digest authorization would work that way too ! See this: https://www.b4x.com/android/forum/threads/set-http-request-header-with-httputils2.78408/
Erel writes in post #2: "If the server implements the standard basic authentication or digest authentication methods then you should set Job.Username and Password. No need to set any header."
Sub Process_Globals
Private Const SHELLY As String = "192.168.5.188:80"
Private username As String = "admin"
Private password As String = "password"
Private realm As String = "shellyplus2pm-f008d1d8b8b8"
End Sub
Sub AppStart (Args() As String)
Dim data As Map = CreateMap("id": 1, "method": "Shelly.GetStatus")
ShellyHttpCall("Post", $"http://${SHELLY}/rpc"$, data.As(JSON).ToCompactString)
StartMessageLoop
End Sub
Sub ShellyHttpCall (HttpMethod As String, Link As String, JsonData As String)
Private AuthParams As Map
AuthParams.Initialize
Dim job As HttpJob
job.Initialize("", Me)
If HttpMethod.ToUpperCase = "POST" Then
job.PostString(Link, JsonData)
job.GetRequest.SetContentType("application/json")
Else If HttpMethod.ToUpperCase = "GET" Then
job.Download(Link)
Else
Log($"[${HttpMethod.ToUpperCase}] Is this supported?"$)
Return
End If
Wait For (job) JobDone(job As HttpJob)
If job.Success Then
Log(job.GetString)
Else
Log(job.ErrorMessage)
If job.Response.StatusCode = 401 Then
Dim headers As List
headers = job.response.GetHeaders.Get("WWW-Authenticate")
For Each header In headers
Log(header)
Dim keyvalue() As String
keyvalue = Regex.Split("=", header)
If keyvalue.Length = 2 Then
AuthParams.Put(keyvalue(0), keyvalue(1))
End If
Next
ShellyHttpCall(HttpMethod, Link, GetAuthData(AuthParams, JsonData))
End If
End If
job.Release
End Sub
Sub GetAuthData (AuthParams As Map, JsonString As String) As String
Dim algorithm As String = "SHA-256"
Dim ha1 As String = SHA256($"${username}:${realm}:${password}"$)
Dim ha2 As String = SHA256("dummy_method:dummy_uri")
Dim nonce As Int = AuthParams.Get("nonce")
Dim cnonce As Int = Rnd(100000000, 999999999)
Dim nc As Int = 1
Dim response As String = SHA256($"${ha1}:${nonce}:${nc}:${cnonce}:auth:${ha2}"$)
Dim authMap As Map
authMap.Initialize
authMap.Put("realm", realm)
authMap.Put("username", username)
authMap.Put("nonce", nonce)
authMap.Put("cnonce", cnonce)
authMap.Put("response", response)
authMap.Put("algorithm", algorithm)
Dim JsonMap As Map = JsonString.As(JSON).ToMap
JsonMap.Put("auth", authMap.As(JSON).ToCompactString)
Return JsonMap.As(JSON).ToCompactString
End Sub
' Return SHA-256 in hexadecimal
Public Sub SHA256 (str As String) As String
Dim data() As Byte
Dim MD As MessageDigest
Dim BC As ByteConverter
data = BC.StringToBytes(str, "UTF8")
data = MD.GetMessageDigest(data, "SHA-256")
Return BC.HexFromBytes(data).ToLowerCase
End Sub
I attach a code ...
Steps in the process:
- Client requests a protected resource without providing credentials.
- Server response containing error 401 (unauthorized) is received.
- Client requests the same protected resource but this time providing credentials.
- The request is successful and access to the resource is granted.
Or:
Request2
curl --digest -u admin:mypass http://${SHELLY}/rpc/Shelly.DetectLocation
Dim url As String = "http://192.168.5.188/relay/0?turn=on"
Dim hj As HttpJob
hj.Initialize("",Me)
hj.Download(url)
Wait for (hj) JobDone(hj As HttpJob)
If hj.Success Then
label1.Text = $"Unexpected success: ${hj.GetString}"$
Else
'Add some code here to ensure you are getting a 401, not something else as a response code.
'401 is expected, anything else is an error
Dim hj2 As HttpJob
hj2.Initialize("",Me)
hj2.Username="admin"
hj2.Password="password"
hj2.Download(url)
Wait for (hj2) JobDone(hj2 As HttpJob)
If hj2.Success Then
label1.Text = hj2.GetString
Else
label1.Text ="Error"
End If
hj2.release
End If
hj.release
Just tried it, but I'm sorry: doesn't work: server answers again with 401 error to h2jSo I would just try the following first:
as a proper step#1 !So the 401 (if using HTTP calls) is always expected as a proper step#2.
Who are you addressing? If you take the info here https://superuser.com/a/1575028 into account, I'm pretty sure I'm on the right track. And yes, I'm following the docs provided by one of the links abovethis is not how it works.
@drgottjr is right. This is not an "one time success" request.
What's wrong here ???
From doc: Authentication can be enabled by setting authentication details through the RPC method Shelly.SetAuth.To enable authentication, it may also need to undergo an API call.
From doc: When communicating over HTTP, this process must be repeated for each request you send to the device.Meaning, even the client has provided the right credentials, there is no way the client could successfully get a success code 200 (without calling the second time).
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?