From 99de6ef4a674cff17ec4567955f56abf33b195e3 Mon Sep 17 00:00:00 2001 From: Florian Date: Thu, 2 Nov 2023 09:10:20 -0500 Subject: [PATCH] [SYS] Password management improvements (#1787) * Use one single password for Access point, OTA and WebUI access * Enable to change the password during WM onboarding, with the WebUI, and MQTT command * Remove the default password during the first configuration to connect to the AP * When using the last 8 digits of the MAC as the password, it can now be changed * Remove gateway password sending to client --- docs/upload/builds.md | 2 +- docs/upload/portal.md | 8 +++-- docs/use/gateway.md | 6 ++++ docs/use/webui.md | 2 +- main/User_config.h | 9 ++--- main/ZwebUI.ino | 76 ++++++++++++++++++++++++++++++++++++++-- main/config_WebContent.h | 9 +++-- main/main.ino | 58 +++++++++++++++++------------- 8 files changed, 129 insertions(+), 41 deletions(-) diff --git a/docs/upload/builds.md b/docs/upload/builds.md index 71eb511..2ea4da8 100644 --- a/docs/upload/builds.md +++ b/docs/upload/builds.md @@ -90,7 +90,7 @@ build_flags = '-DMQTT_USER="mqttusername"' '-DMQTT_PASS="mqttpassword"' '-DMQTT_SERVER="mqttserver.local"' - '-Dota_password="otapassword"' + '-Dgw_password="12345678"' '-DLED_RECEIVE=LED_BUILTIN' ; Comment 1 '-DLED_RECEIVE_ON=LOW' ; Comment 2 '-DRF_RECEIVER_GPIO=13' diff --git a/docs/upload/portal.md b/docs/upload/portal.md index ffbea0a..61ca49d 100644 --- a/docs/upload/portal.md +++ b/docs/upload/portal.md @@ -4,7 +4,7 @@ Once loaded into your ESP, and if you don't use the manual configuration, you have to set your network parameters with WiFi Manager portal. -From your smartphone, search for  OpenMQTTGateway or OMG_ WiFi network and connect to it with the `WifiManager_password` you have defined (the default password is **"your_password"**), or if you are using a device sold by Theengs or the macro `-DWM_PWD_FROM_MAC=true`, the password will be the last eight digits of the device MAC Address with upper case. +From your smartphone, search for  OpenMQTTGateway or OMG_ WiFi network and connect to it without password, or if you are using a device sold by Theengs or the macro `-DWM_PWD_FROM_MAC=true`, the password will be the last eight digits of the device MAC Address with upper case. Example, the password would be `CCDDEEFF` for a MAC Address `AABBCCDDEEFF`. For the Theengs Plug, the MAC Address can be found on the device sticker, and for all the devices, it is printed on the serial monitor logs. @@ -35,8 +35,10 @@ If the board is connected by ethernet, the Wifi and password can be empty. If yo * Set your MQTT Server password (optional, 64 characters maximum) * Set your MQTT base topic if you need to change it (you must keep the / at the end) (default: home/, 64 characters maximum) * Set your gateway name if you need to change it -* Set your Over The Air password `ota_password`, this password is used for local and remote OTA - it is also the password being used for the WebUI login. (default: OTAPASSWORD, 64 characters maximum) - +* Set your gateway password (default: empty, 8 characters minimum, 64 maximum), this password is used for + * Local and remote OTA + * WebUI login (login:"admin", password: "") + * WiFi Manager Access Point password after initial config * Click on save ![WiFi manager save](../img/OpenMQTTGateway_Wifi_Manager_save.png) diff --git a/docs/use/gateway.md b/docs/use/gateway.md index e4184e9..385526f 100644 --- a/docs/use/gateway.md +++ b/docs/use/gateway.md @@ -54,6 +54,12 @@ This command can also be used with other controllers that does not support the i If the new connection fails the gateway will fallback to the previous connection. ::: +## Change the Gateway password + +The password must be 8 characters minimum. + +`mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoSYS/config" -m '{"gw_pass":"12345678"}'` + ## Change the MQTT broker credentials ``` mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoSYS/config" -m diff --git a/docs/use/webui.md b/docs/use/webui.md index 260b1dd..24198c0 100644 --- a/docs/use/webui.md +++ b/docs/use/webui.md @@ -10,7 +10,7 @@ For ESP32 based environments a WebUI is available to provide basic configuration # Login Authentication -By default access to the WebUI uses basic authentication to control access to your OpenMQTTGateway Device. The login is `admin` and the password is your ota_password (if unchanged, the default ota_password is `OTAPASSWORD`). +By default access to the WebUI uses basic authentication to control access to your OpenMQTTGateway Device. The login is `admin` and the password is your `gateway password` (if unchanged during onboarding there is no password). ::: warning The communication with the WebUI is not encrypted, which means that your data may be visible on your local network. diff --git a/main/User_config.h b/main/User_config.h index 3d06c11..7bd7348 100644 --- a/main/User_config.h +++ b/main/User_config.h @@ -121,9 +121,6 @@ const byte mac[] = {0xDE, 0xED, 0xBA, 0xFE, 0x54, 0x95}; //W5100 ethernet shield #endif //#define WM_PWD_FROM_MAC true // enable to set the password from the last 8 digits of the ESP MAC address for enhanced security, enabling this option requires to have access to the MAC address, either through a sticker or with serial monitoring -#ifndef WifiManager_password -# define WifiManager_password "your_password" //this is going to be the WPA2-PSK password for the initial setup access point -#endif #ifndef WifiManager_ssid # define WifiManager_ssid Gateway_Name //this is the network name of the initial setup access point #endif @@ -407,8 +404,8 @@ int lowpowermode = DEFAULT_LOW_POWER_MODE; #ifndef ota_hostname # define ota_hostname Gateway_Name #endif -#ifndef ota_password -# define ota_password "OTAPASSWORD" +#ifndef gw_password +# define gw_password "" #endif #ifndef ota_port # define ota_port 8266 @@ -733,7 +730,7 @@ char gateway_name[parameters_size + 1] = Gateway_Name; void connectMQTT(); #ifndef ESPWifiManualSetup -void saveMqttConfig(); +void saveConfig(); #endif unsigned long uptime(); diff --git a/main/ZwebUI.ino b/main/ZwebUI.ino index a11a0a0..ba47d64 100644 --- a/main/ZwebUI.ino +++ b/main/ZwebUI.ino @@ -768,18 +768,18 @@ void handleMQ() { # ifndef ESPWifiManualSetup if (update) { - Log.warning(F("[WebUI] Save MQTT and Restart" CR)); + Log.warning(F("[WebUI] Save MQTT and Reconnect" CR)); char jsonChar[100]; serializeJson(modules, jsonChar, measureJson(modules) + 1); char buffer[WEB_TEMPLATE_BUFFER_MAX_SIZE]; - snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, header_html, (String(gateway_name) + " - Save MQTT and Restart").c_str()); + snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, header_html, (String(gateway_name) + " - Save MQTT and Reconnect").c_str()); String response = String(buffer); response += String(restart_script); response += String(script); response += String(style); - snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, reset_body, jsonChar, gateway_name, "Save MQTT and Restart"); + snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, reset_body, jsonChar, gateway_name, "Save MQTT and Reconnect"); response += String(buffer); snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, footer, OMG_VERSION); response += String(buffer); @@ -816,6 +816,75 @@ void handleMQ() { server.send(200, "text/html", response); } +/** + * @brief /CG - Configure Gateway Page + * T: handleCG: uri: /gw, args: 2, method: 1 + * T: handleCG Arg: 0, gp=1234 + * T: handleCG Arg: 1, save= + */ + +void handleCG() { + WEBUI_TRACE_LOG(F("handleCG: uri: %s, args: %d, method: %d" CR), server.uri(), server.args(), server.method()); + WEBUI_SECURE + bool update = false; + StaticJsonDocument jsonBuffer; + JsonObject WEBtoSYS = jsonBuffer.to(); + + if (server.args()) { + for (uint8_t i = 0; i < server.args(); i++) { + WEBUI_TRACE_LOG(F("handleCG Arg: %d, %s=%s" CR), i, server.argName(i).c_str(), server.arg(i).c_str()); + } + if (server.hasArg("save") && server.hasArg("gp") && strcmp(ota_pass, server.arg("gp").c_str())) { + strncpy(ota_pass, server.arg("gp").c_str(), parameters_size); + WEBtoSYS["gw_pass"] = ota_pass; + update = true; + } + } + + if (update) { + Log.warning(F("[WebUI] Save Password and Restart" CR)); + + char jsonChar[100]; + serializeJson(modules, jsonChar, measureJson(modules) + 1); + char buffer[WEB_TEMPLATE_BUFFER_MAX_SIZE]; + + snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, header_html, (String(gateway_name) + " - Save Password and Restart").c_str()); + String response = String(buffer); + response += String(restart_script); + response += String(script); + response += String(style); + snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, reset_body, jsonChar, gateway_name, "Save Password and Restart"); + response += String(buffer); + snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, footer, OMG_VERSION); + response += String(buffer); + server.send(200, "text/html", response); + + delay(2000); // Wait for web page to be sent before + String topic = String(mqtt_topic) + String(gateway_name) + String(subjectMQTTtoSYSset); + String output; + serializeJson(WEBtoSYS, output); + Log.notice(F("[WebUI] MQTTtoSYS %s" CR), output.c_str()); + MQTTtoSYS((char*)topic.c_str(), WEBtoSYS); + } else { + Log.warning(F("[WebUI] No changes" CR)); + } + + char jsonChar[100]; + serializeJson(modules, jsonChar, measureJson(modules) + 1); + + char buffer[WEB_TEMPLATE_BUFFER_MAX_SIZE]; + + snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, header_html, (String(gateway_name) + " - Configure Gateway").c_str()); + String response = String(buffer); + response += String(script); + response += String(style); + snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, config_gateway_body, jsonChar, gateway_name, ota_pass); + response += String(buffer); + snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, footer, OMG_VERSION); + response += String(buffer); + server.send(200, "text/html", response); +} + /** * @brief /LO - Configure Logging Page * T: handleLO: uri: /lo, args: 2, method: 1 @@ -1419,6 +1488,7 @@ void WebUISetup() { server.on("/cn", handleCN); // Configuration server.on("/wi", handleWI); // Configure Wifi server.on("/mq", handleMQ); // Configure MQTT + server.on("/cg", handleCG); // Configure Gateway" server.on("/wu", handleWU); // Configure WebUI # ifdef ZgatewayLORA server.on("/la", handleLA); // Configure LORA diff --git a/main/config_WebContent.h b/main/config_WebContent.h index 90a7b2f..5aa9652 100644 --- a/main/config_WebContent.h +++ b/main/config_WebContent.h @@ -43,11 +43,12 @@ #define configure_1 "

" #define configure_2 "

" -#if defined(ZgatewayCloud) +/*#if defined(ZgatewayCloud) # define configure_3 "

" #else # define configure_3 -#endif +#endif*/ +#define configure_3 "

" #define configure_4 "

" #define configure_5 "

" #ifdef ZgatewayLORA @@ -82,7 +83,7 @@ const char config_body[] = body_header "" configure_1 "" configure_2 "" configur const char reset_body[] = body_header "
%s

Device will restart in a few seconds

" body_footer_main_menu; -const char config_cloud_body[] = body_header "
 Cloud Configuration 



" body_footer_config_menu; +//const char config_cloud_body[] = body_header "
 Cloud Configuration 



" body_footer_config_menu; const char token_body[] = body_header "
Link Cloud Account

Cloud was successfully linked

"; @@ -98,6 +99,8 @@ const char config_wifi_body[] = body_header "%s
S const char config_mqtt_body[] = body_header "
MQTT Parameters

MQTT Server

MQTT Port

MQTT Username


MQTT Secure Connection

Gateway Name

MQTT Base Topic


" body_footer_config_menu; +const char config_gateway_body[] = body_header "
Gateway Configuration

Gateway Password (8 characters min)


" body_footer_config_menu; + const char config_logging_body[] = body_header "
OpenMQTTGateway Logging

Log Level


" body_footer_config_menu; const char config_webui_body[] = body_header "
Configure WebUI

Display Metric

Secure WebUI


" body_footer_config_menu; diff --git a/main/main.ino b/main/main.ino index 5811008..caf1c5c 100644 --- a/main/main.ino +++ b/main/main.ino @@ -213,7 +213,7 @@ char mqtt_user[parameters_size + 1] = MQTT_USER; // not compulsory only if your char mqtt_pass[parameters_size + 1] = MQTT_PASS; // not compulsory only if your broker needs authentication char mqtt_server[parameters_size + 1] = MQTT_SERVER; char mqtt_port[6] = MQTT_PORT; -char ota_pass[parameters_size + 1] = ota_password; +char ota_pass[parameters_size + 1] = gw_password; #ifdef USE_MAC_AS_GATEWAY_NAME # undef WifiManager_ssid # undef ota_hostname @@ -221,10 +221,6 @@ char ota_pass[parameters_size + 1] = ota_password; char WifiManager_ssid[MAC_NAME_MAX_LEN]; char ota_hostname[MAC_NAME_MAX_LEN]; #endif -#ifdef WM_PWD_FROM_MAC -# undef WifiManager_password -char WifiManager_password[9]; -#endif bool connectedOnce = false; //indicate if we have been connected once to MQTT bool connected = false; //indicate whether we are currently connected. Used to detected re-connection int failure_number_ntwk = 0; // number of failure connecting to network @@ -1482,7 +1478,7 @@ void checkButton() { void checkButton() {} # endif -void saveMqttConfig() { +void saveConfig() { Log.trace(F("saving config" CR)); DynamicJsonDocument json(512 + ota_server_cert.length() + mqtt_cert.length()); json["mqtt_server"] = mqtt_server; @@ -1561,7 +1557,19 @@ bool loadConfigFromFlash() { } configFile.close(); } + } else { + Log.notice(F("no config file found defining default values" CR)); +# ifdef USE_MAC_AS_GATEWAY_NAME + String s = WiFi.macAddress(); + sprintf(gateway_name, "%.2s%.2s%.2s%.2s%.2s%.2s", + s.c_str(), s.c_str() + 3, s.c_str() + 6, s.c_str() + 9, s.c_str() + 12, s.c_str() + 15); +# endif +# ifdef WM_PWD_FROM_MAC // From ESP Mac Address, last 8 digits as the password + sprintf(ota_pass, "%.2s%.2s%.2s%.2s", + s.c_str() + 6, s.c_str() + 9, s.c_str() + 12, s.c_str() + 15); +# endif } + return result; } @@ -1572,18 +1580,12 @@ void setup_wifimanager(bool reset_settings) { if (reset_settings) eraseAndRestart(); - String s = WiFi.macAddress(); # ifdef USE_MAC_AS_GATEWAY_NAME - sprintf(gateway_name, "%.2s%.2s%.2s%.2s%.2s%.2s", - s.c_str(), s.c_str() + 3, s.c_str() + 6, s.c_str() + 9, s.c_str() + 12, s.c_str() + 15); + String s = WiFi.macAddress(); snprintf(WifiManager_ssid, MAC_NAME_MAX_LEN, "%s_%.2s%.2s", Gateway_Short_Name, s.c_str(), s.c_str() + 3); strcpy(ota_hostname, WifiManager_ssid); Log.notice(F("OTA Hostname: %s.local" CR), ota_hostname); # endif -# ifdef WM_PWD_FROM_MAC // From ESP Mac Address, last 8 digits as the password - sprintf(WifiManager_password, "%.2s%.2s%.2s%.2s", - s.c_str() + 6, s.c_str() + 9, s.c_str() + 12, s.c_str() + 15); -# endif wifiManager.setDebugOutput(WM_DEBUG_LEVEL); @@ -1599,7 +1601,7 @@ void setup_wifimanager(bool reset_settings) { WiFiManagerParameter custom_mqtt_secure("secure", "mqtt secure", "1", 2, mqtt_secure ? "type=\"checkbox\" checked" : "type=\"checkbox\""); WiFiManagerParameter custom_mqtt_cert("cert", "
mqtt broker cert", mqtt_cert.c_str(), 4096); WiFiManagerParameter custom_gateway_name("name", "gateway name", gateway_name, parameters_size); - WiFiManagerParameter custom_ota_pass("ota", "ota password", ota_pass, parameters_size); + WiFiManagerParameter custom_ota_pass("ota", "gateway password", ota_pass, parameters_size); # endif //WiFiManager //Local intialization. Once its business is done, there is no need to keep it around @@ -1648,7 +1650,7 @@ void setup_wifimanager(bool reset_settings) { { # ifdef ESP32 if (lowpowermode < 2) { - displayPrint("Connect your phone to WIFI AP:", WifiManager_ssid, WifiManager_password); + displayPrint("Connect your phone to WIFI AP:", WifiManager_ssid, ota_pass); } else { // in case of low power mode we put the ESP to sleep again if we didn't get connected (typical in case the wifi is down) # ifdef ZgatewayBT lowPowerESP32(); @@ -1658,12 +1660,12 @@ void setup_wifimanager(bool reset_settings) { InfoIndicatorON(); ErrorIndicatorON(); - Log.notice(F("Connect your phone to WIFI AP: %s with PWD: %s" CR), WifiManager_ssid, WifiManager_password); + Log.notice(F("Connect your phone to WIFI AP: %s with PWD: %s" CR), WifiManager_ssid, ota_pass); //fetches ssid and pass and tries to connect //if it does not connect it starts an access point with the specified name //and goes into a blocking loop awaiting configuration - if (!wifiManager.autoConnect(WifiManager_ssid, WifiManager_password)) { + if (!wifiManager.autoConnect(WifiManager_ssid, ota_pass)) { if (!ethConnected) { // If we are using ethernet, we don't want to restart the ESP Log.warning(F("failed to connect and hit timeout" CR)); delay(3000); @@ -1723,7 +1725,7 @@ void setup_wifimanager(bool reset_settings) { } # endif //save the custom parameters to FS - saveMqttConfig(); + saveConfig(); } } # ifdef ESP32_ETHERNET @@ -2635,7 +2637,7 @@ void MQTTHttpsFWUpdate(char* topicOri, JsonObject& HttpsFwUpdateData) { pub(subjectRLStoMQTT, jsondata); ota_server_cert = ota_cert; # ifndef ESPWifiManualSetup - saveMqttConfig(); + saveConfig(); # endif ESPRestart(6); break; @@ -2652,6 +2654,7 @@ void MQTTHttpsFWUpdate(char* topicOri, JsonObject& HttpsFwUpdateData) { void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding if (cmpToMainTopic(topicOri, subjectMQTTtoSYSset)) { + bool restartESP = false; Log.trace(F("MQTTtoSYS json" CR)); #if defined(ESP8266) || defined(ESP32) if (SYSdata.containsKey("cmd")) { @@ -2698,20 +2701,24 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding setESPWifiProtocolTxPower(); # endif } - ESPRestart(7); + restartESP = true; } bool disconnectClient = false; // Trigger client.disconnet if a user/password change doesn't - if (SYSdata.containsKey("mqtt_topic") || SYSdata.containsKey("gateway_name")) { + if (SYSdata.containsKey("mqtt_topic") || SYSdata.containsKey("gateway_name") || SYSdata.containsKey("gw_pass")) { if (SYSdata.containsKey("mqtt_topic")) { strncpy(mqtt_topic, SYSdata["mqtt_topic"], parameters_size); } if (SYSdata.containsKey("gateway_name")) { strncpy(gateway_name, SYSdata["gateway_name"], parameters_size); } + if (SYSdata.containsKey("gw_pass")) { + strncpy(ota_pass, SYSdata["gw_pass"], parameters_size); + restartESP = true; + } # ifndef ESPWifiManualSetup - saveMqttConfig(); + saveConfig(); # endif disconnectClient = true; // trigger reconnect in loop using the new topic/name } @@ -2788,7 +2795,7 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding } } # ifndef ESPWifiManualSetup - saveMqttConfig(); + saveConfig(); # endif } else { if (update_server) { @@ -2807,7 +2814,7 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding } connectMQTT(); } - ESPRestart(7); + restartESP = true; } # endif @@ -2846,6 +2853,9 @@ void MQTTtoSYS(char* topicOri, JsonObject& SYSdata) { // json object decoding } # endif #endif + if (restartESP) { + ESPRestart(7); + } } }