Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit df0c189

Browse files
committedNov 4, 2022
Tweaks after testing against docs and latest Library tree
1 parent 0b4cf21 commit df0c189

File tree

6 files changed

+161
-36
lines changed

6 files changed

+161
-36
lines changed
 

‎libraries/WebServer/examples/HttpAuthCallbackInline/HttpAuthCallbackInline.ino

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -35,28 +35,32 @@ void setup() {
3535

3636
server.on("/", []() {
3737
if (!server.authenticate([](HTTPAuthMethod mode, String username, String params[]) -> String * {
38-
// Scan the password list for the username and return the password.
39-
//
40-
for (credentials_t * entry = passwdfile; entry->username; entry++) {
41-
if (username == entry->username)
42-
return new String(entry->password);
43-
return NULL;
44-
}))
45-
{
46-
server.requestAuthentication();
47-
return;
48-
}
49-
server.send(200, "text/plain", "Login OK");
50-
});
51-
server.begin();
52-
53-
Serial.print("Open http://");
54-
Serial.print(WiFi.localIP());
55-
Serial.println("/ in your browser to see it working");
56-
}
38+
// Scan the password list for the username and return the password if
39+
// we find the username.
40+
//
41+
for (credentials_t * entry = passwdfile; entry->username; entry++) {
42+
if (username == entry->username) {
43+
return new String(entry->password);
44+
};
45+
};
46+
// we've not found the user in the list.
47+
return NULL;
48+
}))
49+
{
50+
server.requestAuthentication();
51+
return;
52+
}
53+
server.send(200, "text/plain", "Login OK");
54+
});
55+
server.begin();
56+
57+
Serial.print("Open http://");
58+
Serial.print(WiFi.localIP());
59+
Serial.println("/ in your browser to see it working");
60+
}
5761

58-
void loop() {
59-
ArduinoOTA.handle();
60-
server.handleClient();
61-
delay(2);//allow the cpu to switch to other tasks
62-
}
62+
void loop() {
63+
ArduinoOTA.handle();
64+
server.handleClient();
65+
delay(2);//allow the cpu to switch to other tasks
66+
}

‎libraries/WebServer/examples/HttpAuthOneTimePassword/HttpAuthOneTimePassword.ino

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,17 @@
44
#include <WebServer.h>
55
#include <lwip/apps/sntp.h>
66

7-
// https://github.com/dirkx/Arduino-Base32-Decode
7+
// https://github.com/dirkx/Arduino-Base32-Decode or simply from
8+
// Sketch->Include Library->Library manager and search for
9+
// "Base32-Decode".
10+
//
811
#include <Base32-Decode.h>
912

10-
// https://github.com/dirkx/Arduino-TOTP-RFC6238-generator
11-
#include <TOTP-generator.hpp>
13+
// https://github.com/dirkx/Arduino-TOTP-RFC6238-generator or simply from
14+
// Sketch->Include Library->Library manager and search for
15+
// "TOTP-RC6236-generator".
16+
//
17+
#include <TOTP-RC6236-generator.hpp>
1218

1319
#include <mbedtls/md.h> // for the hmac/ cookie
1420

@@ -123,10 +129,10 @@ String * checkOTP(HTTPAuthMethod mode, String username, String params[]) {
123129
// people their typical clocks.
124130
//
125131
for (int i = -2 ; i <= 2; i++) {
126-
String * otp = TOTP::currentOTP(*seed); //, time(NULL) + i * TOTP::RFC6238_DEFAULT_interval);
132+
String * otp = TOTP::currentOTP(time(NULL) + i * TOTP::RFC6238_DEFAULT_interval, *seed);
127133

128134
if (!params[0].startsWith(*otp))
129-
next;
135+
continue;
130136

131137
// Issue 3) Use proper 2FA/MFA - and insist the user types the token followed by the password
132138
//
@@ -212,4 +218,4 @@ void loop() {
212218

213219
delete otp;
214220
}
215-
}
221+
}

‎libraries/WebServer/examples/HttpAuthOneTimePasswordNaive/HttpAuthOneTimePasswordNaive.ino

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,17 @@
44
#include <WebServer.h>
55
#include <lwip/apps/sntp.h>
66

7-
// https://github.com/dirkx/Arduino-Base32-Decode
7+
// https://github.com/dirkx/Arduino-Base32-Decode or simply from
8+
// Sketch->Include Library->Library manager and search for
9+
// "Base32-Decode".
10+
//
811
#include <Base32-Decode.h>
912

10-
// https://github.com/dirkx/Arduino-TOTP-RFC6238-generator
11-
#include <TOTP-generator.hpp>
13+
// https://github.com/dirkx/Arduino-TOTP-RFC6238-generator or simply from
14+
// Sketch->Include Library->Library manager and search for
15+
// "TOTP-RC6236-generator".
16+
//
17+
#include <TOTP-RC6236-generator.hpp>
1218

1319
// Naive RFC 6238 one time password; with a couple of possibly flawed
1420
// assumptionms:
@@ -82,7 +88,7 @@ void setup() {
8288
server.on("/", []() {
8389
if (!server.authenticate([](HTTPAuthMethod mode, String username, String params[]) -> String * {
8490
if (username == demouser)
85-
return otp = TOTP::currentOTP(seed);
91+
return TOTP::currentOTP(seed);
8692
return NULL;
8793
}))
8894
{
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#include <WiFi.h>
2+
#include <ESPmDNS.h>
3+
#include <ArduinoOTA.h>
4+
#include <WebServer.h>
5+
#include "mbedtls/sha1.h"
6+
#include "sodium/utils.h"
7+
8+
9+
/// We have two options - we either come in with a bearer
10+
// token - i.e. a special header or API token; or we
11+
// get a normal HTTP style basic auth prompt.
12+
//
13+
// To do a bearer fetch - use something like Swagger or with curl:
14+
//
15+
// curl https://myesp.com/ -H "Authorization: Bearer SecritToken"
16+
//
17+
// We avoid hardcoding this "SecritToken" into the code by
18+
// using a SHA1 instead (which is not paricularly secure).
19+
20+
// Create the secet token SHA1 with:
21+
// echo -n SecritToken | openssl sha1
22+
//
23+
String secret_token_hex = "d2cce6b472959484a21c3194080c609b8a2c910b";
24+
25+
// Wifi credentials
26+
//
27+
const char* ssid = "........";
28+
const char* password = "........";
29+
30+
WebServer server(80);
31+
32+
// Rather than specify the admin password as plaintext; we
33+
// provide it as an (unsalted!) SHA1 hash. This is not
34+
// much more secure (SHA1 is past its retirement age,
35+
// and long obsolte/insecure) - but it helps a little.
36+
37+
// The sha1 of 'esp32' (without the trailing \0) expressed as 20
38+
// bytes of hex. Created by for example 'echo -n esp32 | openssl sha1'
39+
// or http://www.sha1-online.com.
40+
//
41+
const char* www_username_hex = "hexadmin";
42+
const char* www_password_hex = "8cb124f8c277c16ec0b2ee00569fd151a08e342b";
43+
44+
// The same; but now expressed as a base64 string (e.g. as commonly used
45+
// by webservers). Created by ` echo -n esp32 | openssl sha1 -binary | openssl base64`
46+
//
47+
const char* www_username_base64 = "base64admin";
48+
const char* www_password_base64 = "jLEk+MJ3wW7Asu4AVp/RUaCONCs=";
49+
50+
String * check_bearer_or_auth(HTTPAuthMethod mode, String authReq, String params[]) {
51+
// we expect authReq to be "bearer some-secret"
52+
//
53+
String lcAuthReq = authReq;
54+
lcAuthReq.toLowerCase();
55+
if (mode == OTHER_AUTH && (lcAuthReq.startsWith("bearer "))) {
56+
String secret = authReq.substring(7);
57+
secret.trim();
58+
59+
uint8_t sha1[20];
60+
mbedtls_sha1((const uint8_t*) secret.c_str(), secret.length(), sha1);
61+
62+
char sha1calc[48]; // large enough for base64 and Hex represenation
63+
sodium_bin2hex(sha1calc, sizeof(sha1calc), sha1, sizeof(sha1));
64+
65+
if (secret_token_hex.equalsConstantTime(sha1calc))
66+
return new String("anything non null");
67+
};
68+
69+
// that failed - so do a normal auth
70+
//
71+
return server.authenticateBasicSHA1(www_username_hex, www_password_hex) ?
72+
new String(params[0]) : NULL;
73+
};
74+
75+
void setup() {
76+
Serial.begin(115200);
77+
WiFi.mode(WIFI_STA);
78+
WiFi.begin(ssid, password);
79+
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
80+
Serial.println("WiFi Connect Failed! Rebooting...");
81+
delay(1000);
82+
ESP.restart();
83+
}
84+
ArduinoOTA.begin();
85+
86+
server.on("/", []() {
87+
if (!server.authenticate(&check_bearer_or_auth)) {
88+
Serial.println("No/failed authentication");
89+
return server.requestAuthentication();
90+
}
91+
server.send(200, "text/plain", "Login okOK");
92+
return;
93+
});
94+
95+
server.begin();
96+
97+
Serial.print("Open http://");
98+
Serial.print(WiFi.localIP());
99+
Serial.println("/ in your browser to see it working");
100+
}
101+
102+
void loop() {
103+
ArduinoOTA.handle();
104+
server.handleClient();
105+
delay(2);//allow the cpu to switch to other tasks
106+
}

‎libraries/WebServer/src/WebServer.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,11 @@ bool WebServer::authenticate(THandlerFunctionAuthCheck fn) {
284284

285285
log_v("The Proper response=%s", _responsecheck.c_str());
286286
return _response == _responsecheck;
287+
} else if (authReq.length()) {
288+
String * ret = fn(OTHER_AUTH, authReq, {});
289+
if (ret)
290+
return true;
287291
}
288-
289292
exf:
290293
authReq = "";
291294
return false;

‎libraries/WebServer/src/WebServer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END,
3434
UPLOAD_FILE_ABORTED };
3535
enum HTTPClientStatus { HC_NONE, HC_WAIT_READ, HC_WAIT_CLOSE };
36-
enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH };
36+
enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH, OTHER_AUTH };
3737

3838
#define HTTP_DOWNLOAD_UNIT_SIZE 1436
3939

0 commit comments

Comments
 (0)
Please sign in to comment.