[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
This commit is contained in:
Florian authored and GitHub committed 2023-11-02 09:10:20 -05:00
1 parent 7c48129f37
commit 99de6ef4a6
8 files changed
+129 -41

No files matched your search

+1 -1
View File
@@ -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'
+5 -3
View File
@@ -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)
+6
View File
@@ -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
+1 -1
View File
@@ -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.
+3 -6
View File
@@ -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();
+73 -3
View File
@@ -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<JSON_MSG_BUFFER> jsonBuffer;
JsonObject WEBtoSYS = jsonBuffer.to<JsonObject>();
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
+6 -3
View File
@@ -43,11 +43,12 @@
#define configure_1 "<p><form action='wi' method='get'><button>Configure WiFi</button></form></p>"
#define configure_2 "<p><form action='mq' method='get'><button>Configure MQTT</button></form></p>"
#if defined(ZgatewayCloud)
/*#if defined(ZgatewayCloud)
# define configure_3 "<p><form action='cl' method='get'><button>Configure Cloud</button></form></p>"
#else
# define configure_3
#endif
#endif*/
#define configure_3 "<p><form action='cg' method='get'><button>Configure Gateway</button></form></p>"
#define configure_4 "<p><form action='wu' method='get'><button>Configure WebUI</button></form></p>"
#define configure_5 "<p><form action='lo' method='get'><button>Configure Logging</button></form></p>"
#ifdef ZgatewayLORA
@@ -82,7 +83,7 @@ const char config_body[] = body_header "" configure_1 "" configure_2 "" configur
const char reset_body[] = body_header "<div style='text-align:center;'>%s</div><br><div style='text-align:center;'>Device will restart in a few seconds</div><br>" body_footer_main_menu;
const char config_cloud_body[] = body_header "<fieldset class=\"set1\"><legend><span><b>&nbsp;Cloud Configuration&nbsp;</b></span></legend><form method='get' action='cl'><p><label><input id='cl-en' type='checkbox' %s><b>Enable Cloud Connection</b></label></p><br><p><label><input id='cl-lk' type='checkbox' disabled><b>Cloud Account%s Linked</b></label></p><br><button name='save' type='submit' class='button bgrn'>Save</button></form></fieldset><p><form action='%s' method='get'><input type='hidden' name='macAddress' value='%s'/><input type='hidden' name='redirect_uri' value='%s'/><input type='hidden' name='gateway_name' value='%s'/><input type='hidden' name='uptime' value='%d'/><input type='hidden' name='RT' value='%d'/><button>Link Cloud Account</button></form></p>" body_footer_config_menu;
//const char config_cloud_body[] = body_header "<fieldset class=\"set1\"><legend><span><b>&nbsp;Cloud Configuration&nbsp;</b></span></legend><form method='get' action='cl'><p><label><input id='cl-en' type='checkbox' %s><b>Enable Cloud Connection</b></label></p><br><p><label><input id='cl-lk' type='checkbox' disabled><b>Cloud Account%s Linked</b></label></p><br><button name='save' type='submit' class='button bgrn'>Save</button></form></fieldset><p><form action='%s' method='get'><input type='hidden' name='macAddress' value='%s'/><input type='hidden' name='redirect_uri' value='%s'/><input type='hidden' name='gateway_name' value='%s'/><input type='hidden' name='uptime' value='%d'/><input type='hidden' name='RT' value='%d'/><button>Link Cloud Account</button></form></p>" body_footer_config_menu;
const char token_body[] = body_header "<div style='text-align:center;'>Link Cloud Account</div><br><div style='text-align:center;'>Cloud was successfully linked</div><br><div id=but2d style=\"display: block;\"></div><p><form id=but2 style=\"display: block;\" action='cn' method='get'><button>Configuration</button></form></p>";
@@ -98,6 +99,8 @@ const char config_wifi_body[] = body_header "%s<br><div><a href='/wi?scan='><b>S
const char config_mqtt_body[] = body_header "<fieldset class=\"set1\"><legend><span><b>MQTT Parameters</b></span></legend><form method='get' action='mq'><p><b>MQTT Server</b><br><input id='mh' placeholder=" MQTT_SERVER " value='%s'></p><p><b>MQTT Port</b><br><input id='ml' placeholder=" MQTT_PORT " value='%s'></p><p><b>MQTT Username</b><br><input id='mu' placeholder=" MQTT_USER " value='%s'></p><p><label><b>MQTT Password</b><input type='checkbox' onclick='sp(\"mp\")'></label><br><input id='mp' type='password' placeholder=\"Password\" value='%s'></p><p><b>MQTT Secure Connection</b><br><input id='sc' type='checkbox' %s></p><p><b>Gateway Name</b><br><input id='h' placeholder=" Gateway_Name " value=\"%s\"></p><p><b>MQTT Base Topic</b><br><input id='mt' placeholder='' value='%s'></p><br><button name='save' type='submit' class='button bgrn'>Save</button></form></fieldset>" body_footer_config_menu;
const char config_gateway_body[] = body_header "<fieldset class=\"set1\"><legend><span><b>Gateway Configuration</b></span></legend><form method='get' action='cg'><p><b>Gateway Password (8 characters min)</b><br><input id='gp' type='password' placeholder=\"********\"></p><br><button name='save' type='submit' class='button bgrn'>Save</button></form></fieldset>" body_footer_config_menu;
const char config_logging_body[] = body_header "<fieldset class=\"set1\"><legend><span><b>OpenMQTTGateway Logging</b></span></legend><form method='get' action='lo'><p><b>Log Level</b><br><select id='lo'><option %s value='0'>Silent</option><option %s value='1'>Fatal</option><option %s value='2'>Error</option><option %s value='3'>Warning</option><option %s value='4'>Notice</option><option %s value='5'>Trace</option><option %s value='6'>Verbose</option></select></p><br><button name='save' type='submit' class='button bgrn'>Save</button></form></fieldset>" body_footer_config_menu;
const char config_webui_body[] = body_header "<fieldset class=\"set1\"><legend><span><b>Configure WebUI</b></span></legend><form method='get' action='wu'><p><b>Display Metric</b><br><input id='dm' type='checkbox' %s></p><p><b>Secure WebUI</b><br><input id='sw' type='checkbox' %s></p><br><button name='save' type='submit' class='button bgrn'>Save</button></form></fieldset>" body_footer_config_menu;
+34 -24
View File
@@ -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", "<br/>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);
}
}
}