From 9b1eab21fb3d57d7f78d7e5fd250fe75d730e6fd Mon Sep 17 00:00:00 2001 From: raven-worx Date: Thu, 8 Dec 2022 19:03:31 +0100 Subject: [PATCH] added option for http authentication --- CMakeLists.txt | 2 +- README.md | 2 ++ include/mbuspico.conf.h.in | 2 ++ options.cmake | 3 +- options.ini | 4 ++- src/http.c | 65 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 75 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4134e64..ec65c86 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ include(options.cmake) include(pico_sdk_import.cmake) set(TARGETNAME "mbuspico") -project(MBusPico VERSION 1.3) +project(MBusPico VERSION 1.4) # initialize the Raspberry Pi Pico SDK pico_sdk_init() diff --git a/README.md b/README.md index a4e1147..6eb8214 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,8 @@ docker run -v ${PWD}:/opt/mbuspico mbuspico/build | MBUSPICO_UDP_INTERVAL_S | 30 | no | the maximum interval [sec] the meter data should be send out via UDP | | MBUSPICO_HTTP_ENABLED | ON | no | specifies if the device should launch a simple HTTP server to provide the read meter data | | MBUSPICO_HTTP_SERVER_PORT | 80 | no | specifies the listening port for the HTTP webserver | +| MBUSPICO_HTTP_AUTH_USER | | no | Protect access to data with authentication +| MBUSPICO_HTTP_AUTH_PWD | | no | Protect access to data with authentication # Transfer MBusPico onto the device diff --git a/include/mbuspico.conf.h.in b/include/mbuspico.conf.h.in index f3a58f2..b89f11e 100644 --- a/include/mbuspico.conf.h.in +++ b/include/mbuspico.conf.h.in @@ -15,3 +15,5 @@ #cmakedefine01 MBUSPICO_HTTP_ENABLED #cmakedefine MBUSPICO_HTTP_SERVER_PORT @MBUSPICO_HTTP_SERVER_PORT@ // optional, default 80 +#cmakedefine MBUSPICO_HTTP_AUTH_USER "@MBUSPICO_HTTP_AUTH_USER@" // optional +#cmakedefine MBUSPICO_HTTP_AUTH_PWD "@MBUSPICO_HTTP_AUTH_PWD@" // optional diff --git a/options.cmake b/options.cmake index 29820b2..618153b 100644 --- a/options.cmake +++ b/options.cmake @@ -18,7 +18,8 @@ cmake_dependent_option(MBUSPICO_UDP_INTERVAL_S "UDP send interval [s]" 30 "MBUSP # HTTP SERVER cmake_dependent_option(MBUSPICO_HTTP_ENABLED "Enable HTTP server" ON "MBUSPICO_WIFI_ENABLED" OFF) cmake_dependent_option(MBUSPICO_HTTP_SERVER_PORT "HTTP server port" 80 "MBUSPICO_WIFI_ENABLED;MBUSPICO_HTTP_ENABLED" 80) - +cmake_dependent_option(MBUSPICO_HTTP_AUTH_USER "HTTP Authentication user" "" "MBUSPICO_WIFI_ENABLED;MBUSPICO_HTTP_ENABLED" "") +cmake_dependent_option(MBUSPICO_HTTP_AUTH_PWD "HTTP Authentication password" "" "MBUSPICO_WIFI_ENABLED;MBUSPICO_HTTP_ENABLED" "") # # INIT OPTIONS FROM FILE diff --git a/options.ini b/options.ini index 9a2e79f..3355799 100644 --- a/options.ini +++ b/options.ini @@ -15,4 +15,6 @@ MBUSPICO_UDP_INTERVAL_S=30 # HTTP SERVER MBUSPICO_HTTP_ENABLED=ON -MBUSPICO_HTTP_SERVER_PORT=80 \ No newline at end of file +MBUSPICO_HTTP_SERVER_PORT=80 +MBUSPICO_HTTP_AUTH_USER= +MBUSPICO_HTTP_AUTH_PWD= \ No newline at end of file diff --git a/src/http.c b/src/http.c index 7708b42..513233e 100644 --- a/src/http.c +++ b/src/http.c @@ -4,6 +4,23 @@ #include #include +#include + +#if defined(MBUSPICO_HTTP_AUTH_USER) || defined(MBUSPICO_HTTP_AUTH_PWD) +# define MBUSPICO_HTTP_AUTH_ENABLED 1 + +# ifndef MBUSPICO_HTTP_AUTH_USER +# define MBUSPICO_HTTP_AUTH_USER "" +# endif +# ifndef MBUSPICO_HTTP_AUTH_PWD +# define MBUSPICO_HTTP_AUTH_PWD "" +# endif + +# define RESPONSE_UNAUTH_HEADER \ + "WWW-Authenticate: Basic realm=" PROJECT_NAME "\r\n" +#else +# define MBUSPICO_HTTP_AUTH_ENABLED 0 +#endif #define RESPONSE_BUFFER_SIZE 512 @@ -19,12 +36,48 @@ RESPONSE_HEADERS \ "Content-Type: text/html" "\r\n" +#if MBUSPICO_HTTP_AUTH_ENABLED +static int check_auth(struct mg_http_message *hm) { + struct mg_str *s = mg_http_get_header(hm, "Authorization"); + if (s == NULL) { + MBUSPICO_LOG_D(LOG_TAG_HTTP, "no auth header"); + return 0; + } + + static const char auth_user[] = MBUSPICO_HTTP_AUTH_USER; + static const size_t auth_user_len = sizeof(auth_user); + static const char auth_pwd[] = MBUSPICO_HTTP_AUTH_PWD; + static const size_t auth_pwd_len = sizeof(auth_pwd); + + char user[auth_user_len]; + memset(user, 0, auth_user_len); + char pwd[auth_pwd_len]; + memset(pwd, 0, auth_pwd_len); + + mg_http_creds(hm, user, auth_user_len, pwd, auth_pwd_len); + MBUSPICO_LOG_D(LOG_TAG_HTTP, "checking auth header: user: '%s' ==' %s', pwd: '%s' == '%s'", user, auth_user, pwd, auth_pwd); + + if (strncmp(auth_user, user, auth_user_len) == 0 && strncmp(auth_pwd, pwd, auth_pwd_len) == 0) { + return 1; + } + + MBUSPICO_LOG_E(LOG_TAG_HTTP, "rejected auth attempt: user: '%s', pwd: '%s'", user, pwd); + return 0; +} +#endif + static void http_serve_fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; if (strncmp(hm->method.ptr, "GET", hm->method.len) == 0) { // METER DATA if (mg_http_match_uri(hm, "/")) { + #if MBUSPICO_HTTP_AUTH_ENABLED + if (!check_auth(hm)) { + mg_http_reply(c, 401, RESPONSE_HEADERS_HTML RESPONSE_UNAUTH_HEADER, "%s", "Unauthorized\n"); + return; + } + #endif char data_buffer[RESPONSE_BUFFER_SIZE] = {0}; size_t data_size = mbuspico_get_meterdata_json(data_buffer, RESPONSE_BUFFER_SIZE); if (data_size > 0) { @@ -37,6 +90,12 @@ static void http_serve_fn(struct mg_connection *c, int ev, void *ev_data, void * } // UPDATE else if (mg_http_match_uri(hm, "/update")) { + #if MBUSPICO_HTTP_AUTH_ENABLED + if (!check_auth(hm)) { + mg_http_reply(c, 401, RESPONSE_HEADERS_HTML RESPONSE_UNAUTH_HEADER, "%s", "Unauthorized\n"); + return; + } + #endif if (mbuspico_schedule_reboot_usb(2000)) { char msg[] = "Device is restarting into USB mode..."; mg_http_reply(c, 202, RESPONSE_HEADERS_HTML, "%s\n", msg); @@ -48,6 +107,12 @@ static void http_serve_fn(struct mg_connection *c, int ev, void *ev_data, void * } // REBOOT else if (mg_http_match_uri(hm, "/reboot")) { + #if MBUSPICO_HTTP_AUTH_ENABLED + if (!check_auth(hm)) { + mg_http_reply(c, 401, RESPONSE_HEADERS_HTML RESPONSE_UNAUTH_HEADER, "%s", "Unauthorized\n"); + return; + } + #endif if (mbuspico_schedule_reboot(2000)) { char msg[] = "Device is restarting..."; mg_http_reply(c, 202, RESPONSE_HEADERS_HTML, "%s\n", msg);