Skip to content

Commit 6837b64

Browse files
committed
http: server-side Digest Auth with htdigest file support
Add server-side HTTP Digest Auth support using the standard htdigest file format (username:realm:HA1_hex per line). - New mount auth mode LWSAUTHM_DIGEST_AUTH - New mount field basic_auth_realm for the auth realm - lws_check_digest_auth() parses Authorization: Digest headers and validates against the htdigest file - lws_unauthorised_digest_auth() sends 401 with a fresh random nonce - Nonce is stored per-wsi and verified on keep-alive retries - Constant-time response comparison via lws_timingsafe_bcmp - Wired into HTTP/1.1, HTTP/2 and WS upgrade paths - Added minimal example minimal-http-server-digestauth - LWS_WITH_HTTP_DIGEST_AUTH now implies LWS_WITH_HTTP_BASIC_AUTH so the shared lws_authorization_rewrite helper is available Signed-off-by: Bastian Germann <bage@debian.org> Co-developed-by: Claude Sonnet 4.6
1 parent 4e59faf commit 6837b64

13 files changed

Lines changed: 872 additions & 1 deletion

File tree

CMakeLists-implied-options.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ endif()
274274

275275
if (LWS_WITH_HTTP_DIGEST_AUTH)
276276
set(LWS_WITH_GENCRYPTO 1)
277+
set(LWS_WITH_HTTP_BASIC_AUTH 1)
277278
endif()
278279

279280
if (APPLE)

include/libwebsockets/lws-context-vhost.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1505,7 +1505,8 @@ enum lws_mount_protocols {
15051505
*/
15061506
enum lws_authentication_mode {
15071507
LWSAUTHM_DEFAULT = 0, /**< default authenticate only if basic_auth_login_file is provided */
1508-
LWSAUTHM_BASIC_AUTH_CALLBACK = 1 << 28 /**< Basic auth with a custom verifier */
1508+
LWSAUTHM_BASIC_AUTH_CALLBACK = 1 << 28, /**< Basic auth with a custom verifier */
1509+
LWSAUTHM_DIGEST_AUTH = 2 << 28 /**< Digest auth via htdigest-format file (requires LWS_WITH_HTTP_DIGEST_AUTH) */
15091510
};
15101511

15111512
/** The authentication mode is stored in the top 4 bits of lws_http_mount.auth_mask */
@@ -1557,6 +1558,12 @@ struct lws_http_mount {
15571558
const char *basic_auth_login_file;
15581559
/**<NULL, or filepath to use to check basic auth logins against. (requires LWSAUTHM_DEFAULT) */
15591560

1561+
const char *basic_auth_realm;
1562+
/**< NULL (defaults to "lwsws"), or realm string sent in the WWW-Authenticate challenge
1563+
* for both Basic and Digest auth. For Digest auth (LWSAUTHM_DIGEST_AUTH), this must
1564+
* match the realm stored in the htdigest file.
1565+
*/
1566+
15601567
const char *cgi_chroot_path;
15611568
/**< NULL, or chroot patch for child cgi process */
15621569

lib/core-net/close.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,11 @@ __lws_reset_wsi(struct lws *wsi)
144144
lws_free(wsi->http.digest_auth_hdr);
145145
wsi->http.digest_auth_hdr = NULL;
146146
}
147+
if (wsi->http.digest_auth_nonce) {
148+
lws_free(wsi->http.digest_auth_nonce);
149+
wsi->http.digest_auth_nonce = NULL;
150+
}
151+
wsi->http.digest_auth_nc = 0;
147152
#endif
148153
#endif
149154

lib/roles/h2/ops-h2.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,27 @@ lws_h2_bind_for_post_before_action(struct lws *wsi)
938938
lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
939939
return lws_http_transaction_completed(wsi);
940940
}
941+
#endif
942+
#if defined(LWS_WITH_HTTP_DIGEST_AUTH)
943+
944+
/* digest auth? */
945+
946+
if ((hit->auth_mask & AUTH_MODE_MASK) == LWSAUTHM_DIGEST_AUTH) {
947+
switch (lws_check_digest_auth(wsi,
948+
hit->basic_auth_login_file,
949+
hit->basic_auth_realm)) {
950+
case LCBA_CONTINUE:
951+
case LCBA_AUTH_RETRY_KEEPALIVE:
952+
break;
953+
case LCBA_FAILED_AUTH:
954+
return lws_unauthorised_digest_auth(wsi,
955+
hit->basic_auth_realm);
956+
case LCBA_END_TRANSACTION:
957+
lws_return_http_status(wsi,
958+
HTTP_STATUS_FORBIDDEN, NULL);
959+
return lws_http_transaction_completed(wsi);
960+
}
961+
}
941962
#endif
942963
}
943964

lib/roles/http/private-lib-roles-http.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,10 @@ struct _lws_http_mode_related {
306306
char auth_username[64];
307307
char auth_password[64];
308308
char *digest_auth_hdr;
309+
#if defined(LWS_WITH_HTTP_DIGEST_AUTH)
310+
char *digest_auth_nonce; /**< nonce sent in last Digest 401 challenge (server-side) */
311+
uint32_t digest_auth_nc; /**< last nc value seen on this connection */
312+
#endif
309313
char *extra_onward_headers;
310314
};
311315

@@ -342,6 +346,14 @@ lws_check_basic_auth(struct lws *wsi, const char *basic_auth_login_file, unsigne
342346
int
343347
lws_unauthorised_basic_auth(struct lws *wsi);
344348

349+
#if defined(LWS_WITH_HTTP_DIGEST_AUTH)
350+
enum lws_check_basic_auth_results
351+
lws_check_digest_auth(struct lws *wsi, const char *htdigest_file, const char *realm);
352+
353+
int
354+
lws_unauthorised_digest_auth(struct lws *wsi, const char *realm);
355+
#endif
356+
345357
#if defined(LWS_ROLE_H1)
346358
int
347359
lws_read_h1(struct lws *wsi, unsigned char *buf, lws_filepos_t len);

0 commit comments

Comments
 (0)