-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Adds digest authentication example. #4112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
||
#define USE_SERIAL Serial | ||
|
||
ESP8266WiFiMulti WiFiMulti; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need to use ESP8266WiFiMulti
in this file? I know that some of the existing examples do that, but it would be great if the examples could be made orthogonal.
|
||
#include <ESP8266HTTPClient.h> | ||
|
||
#define USE_SERIAL Serial |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest using Serial
directly
ESP8266WiFiMulti WiFiMulti; | ||
|
||
String _exractParam(String& authReq, const String& param, const char delimit){ | ||
int _begin = authReq.indexOf(param); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please load this sketch into Arduino IDE and use Tools > Auto Format feature to fix the indentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, it is not a common practice to prefix function and field names with an underscore, when not implementing class members, at least in Arduino.
} | ||
|
||
WiFi.mode(WIFI_STA); | ||
WiFiMulti.addAP("Niligo-Prism-yyr9uma", ""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might want to replace this with something generic, e.g. "wifi-ssid", "wifi-password"
, and move these settings to the top of the sketch, after includes.
|
||
|
||
// http.begin("http://admin:[email protected]/api/state?power=1"); | ||
http.begin("http://192.168.100.1/api/state?power=0"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps a URL of an existing service can be used?
For example, http://httpbin.org/ has a test endpoint which accept Digest Auth (/digest-auth/:qop/:user/:passwd/:algorithm
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's awesome thanks, I will use it. 🙌
|
||
http.begin("http://192.168.100.1/api/state?power=0"); | ||
USE_SERIAL.println(_nonce); | ||
String Author = "Digest username=\"admin\", realm=\"Protected\", nonce=\"" + _nonce + "\", uri=\"/api/state?power=0\", algorithm=\"MD5\", qop=auth, nc=00000001, cnonce=\"gDBuFY4s\", response=\"" + _response + "\"\r\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest wrapping this part of the code (starting from extractParam calls) into a function which users can copy into their own sketch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
username and URI are duplicated here again, along with nonces...
String _H2 = md5.toString(); | ||
|
||
md5.begin(); | ||
md5.add(_H1 + ":" + _nonce + ":" + "00000001" + ":" + "gDBuFY4s" + ":" + "auth" + ":" + _H2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are the 00000001
and gDBuFY4s
magic values?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In digest authentication client must generate nonce count and client nonce we set them here manually but they can set by creating a random string.
String _H1 = md5.toString(); | ||
|
||
md5.begin(); | ||
md5.add(String("GET:") + String("/api/state?power=0")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be worth storing the URI part in a separate variable and using it both when making HTTP call and here, instead of duplicating.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I created separate variables for them
md5.calculate(); | ||
String _response = md5.toString(); | ||
|
||
http.begin("http://192.168.100.1/api/state?power=0"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likewise, use a variable for URI to avoid duplication.
USE_SERIAL.println(_nonce); | ||
String Author = "Digest username=\"admin\", realm=\"Protected\", nonce=\"" + _nonce + "\", uri=\"/api/state?power=0\", algorithm=\"MD5\", qop=auth, nc=00000001, cnonce=\"gDBuFY4s\", response=\"" + _response + "\"\r\n"; | ||
USE_SERIAL.println(Author); | ||
http.addHeader("Authorization", Author); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use lowercase names for local variables. Also, the name author
is a bit confusing, should it be authorization
?
http.end(); | ||
http.begin(String(server) + String(uri)); | ||
|
||
String authorization = "Digest username=\"admin\", realm=\"" + _realm + "\", nonce=\"" + _nonce + "\", uri=\"" + uri + "\", algorithm=\"MD5\", qop=auth, nc=00000001, cnonce=\"gDBuFY4s\", response=\"" + _response + "\""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's move the part starting from // extracting required parameters for RFC 2069 simpler Diges
to calculation of authorization
into a separate function, e.g. getDigestAuth
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please break this line, Arduino IDE window is just ~60 characters wide, most of the line will not be readable.
// extracting required parameters for RFC 2069 simpler Digest | ||
String _realm = exractParam(authReq, "realm=\"", '"'); | ||
String _nonce = exractParam(authReq, "nonce=\"", '"'); | ||
String _opaque = exractParam(authReq, "opaque=\"", '"'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned previously, it is not a common practice in Arduino sketches to start local variable names with underscores.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I am sorry about them.
String _H2 = md5.toString(); | ||
|
||
md5.begin(); | ||
md5.add(_H1 + ":" + _nonce + ":" + "00000001" + ":" + "gDBuFY4s" + ":" + "auth" + ":" + _H2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still some hard-coded strings here.
Nonce gDBuFY4s
should be randomly generated.
And as far as i understand the RFC, 00000001
should be incremented on each request, which is not the case here.
const char *uri = "/digest-auth/auth/admin/admin/MD5"; | ||
|
||
String exractParam(String& authReq, const String& param, const char delimit){ | ||
int _begin = authReq.indexOf(param); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment about reformatting the sketch using Arduino IDE is still valid, by the way. Arduino sketches use 2 spaces for indentation, this file uses tabs.
@igrr What do you think about adding digest authentication into ESP8266HTTPClient? |
Looks pretty good @1995parham! I think moving this feature into ESP8266HTTPClient class could be useful. It's up to you whether to do it or not, adding it in the form of an example is also okay with me. I have only one remaining comment about the request counter field, "00000001". I think you should pass the counter as an argument into |
@igrr Yes, I add this feature to the |
String cNonce = getCNonce(8); | ||
|
||
char nc[8]; | ||
sprintf(nc, "%08d", counter); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If that's "%08d", the size of nc
should be 9 bytes to accommodate the zero terminator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Counter is an int, so nc should have size 12. Then, the format specifier should be %11d.
Counter should actually be an unsigned int imo, it doesn't make sense for negative values. In that case, nc should have size 11.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, let's read the RFC:
The nc-value is the hexadecimal
count of the number of requests (including the current request)
that the client has sent with the nonce value in this request. For
example, in the first request sent in response to a given nonce
value, the client sends "nc=00000001".
and
nc-value = 8LHEX
and
LHEX = "0" | "1" | "2" | "3" |
"4" | "5" | "6" | "7" |
"8" | "9" | "a" | "b" |
"c" | "d" | "e" | "f"
So it must be "%08x".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, you are right, it must be in hex format so I convert it into %08x
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. But what stresses that counter should be unsigned :P
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@devyte I corrects that too :)
String nonce = exractParam(authReq, "nonce=\"", '"'); | ||
String cNonce = getCNonce(8); | ||
|
||
char nc[8]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, nc is still an 8 byte buffer, so the zero terminator will be written out of array bounds. Could you please change the array size to 9, and use snprintf(nc, sizeof(nc), "%08x", counter);
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes sorry for these mistakes.
@igrr Thanks a lot |
No description provided.