kopia lustrzana https://github.com/martin-ger/esp_mqtt
user/password auth added
rodzic
10700b7b94
commit
171b75c65c
20
README.md
20
README.md
|
@ -36,6 +36,8 @@ Basic commands (enough to get it working in nearly all environments):
|
|||
- set [ap_ssid|ap_password] _value_: changes the settings for the soft-AP of the ESP (for your stations)
|
||||
- show [config|stats|script|mqtt]: prints the current config or some status information and statistics
|
||||
- save: saves the current config parameters to flash
|
||||
- set broker_user _unsername_: sets the username for authentication of MQTT clients ("none" if no auth, default)
|
||||
- set broker_password _password_: sets the password for authentication of MQTT clients ("none" if empty, default)
|
||||
- lock [_password_]: saves and locks the current config, changes are not allowed. Password can be left open if already set before
|
||||
- unlock _password_: unlocks the config, requires password from the lock command
|
||||
- reset [factory]: resets the esp, 'factory' optionally resets WiFi params to default values (works on a locked device only from serial console)
|
||||
|
@ -70,7 +72,7 @@ By default the "remote" MQTT client is disabled. It can be enabled by setting th
|
|||
# Scripting
|
||||
The esp_uMQTT_broker comes with a build-in scripting engine. A script enables the ESP not just to act as a passive broker but to react on events (publications and timing events) and to send out its own items.
|
||||
|
||||
Here is a demo of a script to give you an idea of the power of the scripting feature. This script controls a Sonoff switch module. It connects to a remote MQTT broker and in parallel offers locally its own. On both brokers it subscribes to a topic named '/martinshome/switch/1/command', where it receives commands, and it publishes the topic '/martinshome/switch/1/status' with the current state of the switch relay. It understands the commands 'on','off', 'toggle', and 'blink'. Blinking is realized via a timer event. Local status is stored in the two variables $1 (switch state) and $2 (blinking on/off). The 'on gpio_interrupt' clause reacts on pressing the pushbutton of the Sonnoff and simply toggle the switch (and stops blinking). The last two 'on clock' clauses implement a daily on and off period:
|
||||
Here is a demo of a script to give you an idea of the power of the scripting feature. This script controls a Sonoff switch module. It connects to a remote MQTT broker and in parallel offers locally its own. On both brokers it subscribes to a topic named '/martinshome/switch/1/command', where it receives commands, and it publishes the topic '/martinshome/switch/1/status' with the current state of the switch relay. It understands the commands 'on','off', 'toggle', and 'blink'. Blinking is realized via a timer event. Local status is stored in the two variables $1 (switch state) and $2 (blinking on/off). The 'on gpio_interrupt' clause reacts on pressing the pushbutton of the Sonnoff and simply toggles the switch (and stops blinking). The last two 'on clock' clauses implement a daily on and off period:
|
||||
|
||||
```
|
||||
% Config params, overwrite any previous settings from the commandline
|
||||
|
@ -78,6 +80,8 @@ config ap_ssid MyAP
|
|||
config ap_password stupidPassword
|
||||
config ntp_server 1.pool.ntp.org
|
||||
config mqtt_host 192.168.1.20
|
||||
config broker_user Martin
|
||||
config broker_password secret
|
||||
|
||||
% Now the initialization, this is done once after booting
|
||||
on init
|
||||
|
@ -143,7 +147,7 @@ do
|
|||
publish local /martinshome/switch/1/status $1 retained
|
||||
publish remote /martinshome/switch/1/status $1 retained
|
||||
|
||||
% The local pushbotton
|
||||
% The local pushbutton
|
||||
on gpio_interrupt 0 pullup
|
||||
do
|
||||
println "New state GPIO 0: " | $this_gpio
|
||||
|
@ -263,10 +267,9 @@ The broker does support:
|
|||
- retained messages
|
||||
- LWT
|
||||
- QoS level 0
|
||||
- a subset of MQTT (CONNECT, DISCONNECT, SUBSCRIBE, UNSUBSCRIBE, PUBLISH, PING)
|
||||
- username/password authentication
|
||||
|
||||
The broker does not yet support:
|
||||
- username, password authentication
|
||||
- QoS levels other than 0
|
||||
- many TCP(=MQTT) clients
|
||||
- non-clear sessions
|
||||
|
@ -294,3 +297,12 @@ void MQTT_local_onData(MqttDataCallback dataCb);
|
|||
|
||||
With these functions you can publish and subscribe topics as a local client like you would with a remote MQTT broker.
|
||||
|
||||
Username/password authentication is provided with the following interface:
|
||||
|
||||
```c
|
||||
typedef bool (*MqttAuthCallback)(const char* username, const char *password);
|
||||
|
||||
void MQTT_server_onAuth(MqttAuthCallback authCb);
|
||||
```
|
||||
|
||||
If an *MqttAuthCallback* function is provided, it is called on each connect request. Based on username and password the function has to return *true* for authenticated or *false* for rejected. No provided username/password are empty strings. If no *MqttAuthCallback* function is set, each request will be admitted.
|
||||
|
|
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
|
@ -14,6 +14,8 @@
|
|||
|
||||
#define LOCAL_MQTT_CLIENT ((void*)-1)
|
||||
|
||||
typedef bool (*MqttAuthCallback)(const char* username, const char *password);
|
||||
|
||||
typedef struct _MQTT_ClientCon {
|
||||
struct espconn *pCon;
|
||||
// uint8_t security;
|
||||
|
@ -38,6 +40,7 @@ typedef struct _MQTT_ClientCon {
|
|||
extern MQTT_ClientCon *clientcon_list;
|
||||
|
||||
bool MQTT_server_start(uint16_t portno, uint16_t max_subscriptions, uint16_t max_retained_topics);
|
||||
void MQTT_server_onAuth(MqttAuthCallback authCb);
|
||||
|
||||
bool MQTT_local_publish(uint8_t* topic, uint8_t* data, uint16_t data_length, uint8_t qos, uint8_t retain);
|
||||
bool MQTT_local_subscribe(uint8_t* topic, uint8_t qos);
|
||||
|
|
|
@ -36,6 +36,7 @@ LOCAL uint8_t zero_len_id[2] = { 0, 0 };
|
|||
|
||||
MQTT_ClientCon *clientcon_list;
|
||||
LOCAL MqttDataCallback local_data_cb = NULL;
|
||||
LOCAL MqttAuthCallback local_auth_cb = NULL;
|
||||
|
||||
//#define MQTT_INFO os_printf
|
||||
#define MQTT_WARNING os_printf
|
||||
|
@ -335,22 +336,18 @@ static void ICACHE_FLASH_ATTR MQTT_ClientCon_recv_cb(void *arg, char *pdata, uns
|
|||
}
|
||||
}
|
||||
|
||||
uint16_t msg_used_len = var_header_len;
|
||||
|
||||
MQTT_INFO("MQTT: Connect flags %x\r\n", variable_header->flags);
|
||||
clientcon->connect_info.clean_session = (variable_header->flags & MQTT_CONNECT_FLAG_CLEAN_SESSION) != 0;
|
||||
if ((variable_header->flags & MQTT_CONNECT_FLAG_USERNAME) != 0 ||
|
||||
(variable_header->flags & MQTT_CONNECT_FLAG_PASSWORD) != 0) {
|
||||
MQTT_WARNING("MQTT: Connect option currently not supported\r\n");
|
||||
msg_conn_ret = CONNECTION_REFUSE_NOT_AUTHORIZED;
|
||||
clientcon->connState = TCP_DISCONNECTING;
|
||||
break;
|
||||
}
|
||||
|
||||
clientcon->connect_info.keepalive = (variable_header->keepaliveMsb << 8) + variable_header->keepaliveLsb;
|
||||
espconn_regist_time(clientcon->pCon, 2 * clientcon->connect_info.keepalive, 1);
|
||||
MQTT_INFO("MQTT: Keepalive %d\r\n", clientcon->connect_info.keepalive);
|
||||
|
||||
// Get the client id
|
||||
uint16_t id_len = clientcon->mqtt_state.message_length - (2 + var_header_len);
|
||||
const char *client_id = mqtt_get_str(&clientcon->mqtt_state.in_buffer[2 + var_header_len], &id_len);
|
||||
uint16_t id_len = clientcon->mqtt_state.message_length - (2 + msg_used_len);
|
||||
const char *client_id = mqtt_get_str(&clientcon->mqtt_state.in_buffer[2 + msg_used_len], &id_len);
|
||||
if (client_id == NULL || id_len > 80) {
|
||||
MQTT_WARNING("MQTT: Client Id invalid\r\n");
|
||||
msg_conn_ret = CONNECTION_REFUSE_ID_REJECTED;
|
||||
|
@ -384,6 +381,7 @@ static void ICACHE_FLASH_ATTR MQTT_ClientCon_recv_cb(void *arg, char *pdata, uns
|
|||
break;
|
||||
}
|
||||
}
|
||||
msg_used_len += 2 + id_len;
|
||||
|
||||
// Get the LWT
|
||||
clientcon->connect_info.will_retain = (variable_header->flags & MQTT_CONNECT_FLAG_WILL_RETAIN) != 0;
|
||||
|
@ -396,9 +394,9 @@ static void ICACHE_FLASH_ATTR MQTT_ClientCon_recv_cb(void *arg, char *pdata, uns
|
|||
return;
|
||||
}
|
||||
} else {
|
||||
uint16_t lw_topic_len = clientcon->mqtt_state.message_length - (4 + var_header_len + id_len);
|
||||
uint16_t lw_topic_len = clientcon->mqtt_state.message_length - (2 + msg_used_len);
|
||||
const char *lw_topic =
|
||||
mqtt_get_str(&clientcon->mqtt_state.in_buffer[4 + var_header_len + id_len], &lw_topic_len);
|
||||
mqtt_get_str(&clientcon->mqtt_state.in_buffer[2 + msg_used_len], &lw_topic_len);
|
||||
|
||||
if (lw_topic == NULL) {
|
||||
MQTT_WARNING("MQTT: Last Will topic invalid\r\n");
|
||||
|
@ -422,11 +420,12 @@ static void ICACHE_FLASH_ATTR MQTT_ClientCon_recv_cb(void *arg, char *pdata, uns
|
|||
clientcon->connState = TCP_DISCONNECTING;
|
||||
break;
|
||||
}
|
||||
msg_used_len += 2 + lw_topic_len;
|
||||
|
||||
uint16_t lw_data_len =
|
||||
clientcon->mqtt_state.message_length - (6 + var_header_len + id_len + lw_topic_len);
|
||||
clientcon->mqtt_state.message_length - (2 + msg_used_len);
|
||||
const char *lw_data =
|
||||
mqtt_get_str(&clientcon->mqtt_state.in_buffer[6 + var_header_len + id_len + lw_topic_len],
|
||||
mqtt_get_str(&clientcon->mqtt_state.in_buffer[2 + msg_used_len],
|
||||
&lw_data_len);
|
||||
|
||||
if (lw_data == NULL) {
|
||||
|
@ -446,6 +445,71 @@ static void ICACHE_FLASH_ATTR MQTT_ClientCon_recv_cb(void *arg, char *pdata, uns
|
|||
clientcon->connState = TCP_DISCONNECTING;
|
||||
break;
|
||||
}
|
||||
msg_used_len += 2 + lw_data_len;
|
||||
}
|
||||
|
||||
// Get the username
|
||||
if ((variable_header->flags & MQTT_CONNECT_FLAG_USERNAME) != 0) {
|
||||
uint16_t username_len = clientcon->mqtt_state.message_length - (2 + msg_used_len);
|
||||
const char *username =
|
||||
mqtt_get_str(&clientcon->mqtt_state.in_buffer[2 + msg_used_len], &username_len);
|
||||
|
||||
if (username == NULL) {
|
||||
MQTT_WARNING("MQTT: Username invalid\r\n");
|
||||
MQTT_ServerDisconnect(clientcon);
|
||||
return;
|
||||
}
|
||||
|
||||
clientcon->connect_info.username = (char *)os_zalloc(username_len+1);
|
||||
if (clientcon->connect_info.username != NULL) {
|
||||
os_memcpy(clientcon->connect_info.username, username, username_len);
|
||||
clientcon->connect_info.username[username_len] = '\0';
|
||||
MQTT_INFO("MQTT: Username %s\r\n", clientcon->connect_info.username);
|
||||
} else {
|
||||
MQTT_ERROR("MQTT: Out of mem\r\n");
|
||||
msg_conn_ret = CONNECTION_REFUSE_SERVER_UNAVAILABLE;
|
||||
clientcon->connState = TCP_DISCONNECTING;
|
||||
break;
|
||||
}
|
||||
msg_used_len += 2 + username_len;
|
||||
}
|
||||
|
||||
// Get the password
|
||||
if ((variable_header->flags & MQTT_CONNECT_FLAG_PASSWORD) != 0) {
|
||||
|
||||
if ((variable_header->flags & MQTT_CONNECT_FLAG_USERNAME) == 0) {
|
||||
MQTT_WARNING("MQTT: Password without username\r\n");
|
||||
MQTT_ServerDisconnect(clientcon);
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t password_len = clientcon->mqtt_state.message_length - (2 + msg_used_len);
|
||||
const char *password =
|
||||
mqtt_get_str(&clientcon->mqtt_state.in_buffer[2 + msg_used_len], &password_len);
|
||||
|
||||
if (password != NULL)
|
||||
clientcon->connect_info.password = (char *)os_zalloc(password_len+1);
|
||||
if (clientcon->connect_info.password != NULL) {
|
||||
os_memcpy(clientcon->connect_info.password, password, password_len);
|
||||
clientcon->connect_info.password[password_len] = '\0';
|
||||
MQTT_INFO("MQTT: Password %s\r\n", clientcon->connect_info.password);
|
||||
} else {
|
||||
MQTT_ERROR("MQTT: Out of mem\r\n");
|
||||
msg_conn_ret = CONNECTION_REFUSE_SERVER_UNAVAILABLE;
|
||||
clientcon->connState = TCP_DISCONNECTING;
|
||||
break;
|
||||
}
|
||||
msg_used_len += 2 + password_len;
|
||||
}
|
||||
|
||||
// Check Auth
|
||||
if ((local_auth_cb != NULL) &&
|
||||
local_auth_cb(clientcon->connect_info.username==NULL?"":clientcon->connect_info.username,
|
||||
clientcon->connect_info.password==NULL?"":clientcon->connect_info.password) == false) {
|
||||
MQTT_WARNING("MQTT: Authorization failed\r\n");
|
||||
msg_conn_ret = CONNECTION_REFUSE_NOT_AUTHORIZED;
|
||||
clientcon->connState = TCP_DISCONNECTING;
|
||||
break;
|
||||
}
|
||||
|
||||
msg_conn_ret = CONNECTION_ACCEPTED;
|
||||
|
@ -812,3 +876,7 @@ bool ICACHE_FLASH_ATTR MQTT_local_unsubscribe(uint8_t * topic) {
|
|||
void ICACHE_FLASH_ATTR MQTT_local_onData(MqttDataCallback dataCb) {
|
||||
local_data_cb = dataCb;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR MQTT_server_onAuth(MqttAuthCallback authCb) {
|
||||
local_auth_cb = authCb;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,9 @@ void config_load_default(sysconfig_p config) {
|
|||
config->clock_speed = 80;
|
||||
config->config_port = CONSOLE_SERVER_PORT;
|
||||
|
||||
os_sprintf(config->mqtt_broker_user, "%s", "none");
|
||||
config->mqtt_broker_password[0] = 0;
|
||||
|
||||
#ifdef MQTT_CLIENT
|
||||
os_sprintf(config->mqtt_host, "%s", "none");
|
||||
config->mqtt_port = 1883;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
#define FLASH_BLOCK_NO 0xc
|
||||
|
||||
#define MAGIC_NUMBER 0x015005fc
|
||||
#define MAGIC_NUMBER 0x015005fd
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -46,6 +46,9 @@ typedef struct
|
|||
uint16_t clock_speed; // Freq of the CPU
|
||||
uint16_t config_port; // Port on which the concole listenes (0 if no access)
|
||||
|
||||
uint8_t mqtt_broker_user[32]; // Username for client login, "none" if empty
|
||||
uint8_t mqtt_broker_password[32]; // Password for client login
|
||||
|
||||
#ifdef MQTT_CLIENT
|
||||
uint8_t mqtt_host[32]; // IP or hostname of the MQTT broker, "none" if empty
|
||||
uint16_t mqtt_port; // Port of the MQTT broker
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
config ap_ssid DerKluge
|
||||
config ap_password Bonn2016
|
||||
config ntp_server 1.de.pool.ntp.org
|
||||
config broker_user Martin
|
||||
config broker_password secret
|
||||
config mqtt_host martinshome.fritz.box
|
||||
config speed 160
|
||||
|
||||
|
@ -70,7 +72,7 @@ do
|
|||
publish remote /martinshome/switch/1/status $1 retained
|
||||
|
||||
|
||||
% The local pushbotton
|
||||
% The local pushbutton
|
||||
on gpio_interrupt 0 pullup
|
||||
do
|
||||
println "New state GPIO 0: " | $this_gpio
|
||||
|
|
|
@ -348,7 +348,7 @@ void ICACHE_FLASH_ATTR console_handle_command(struct espconn *pespconn) {
|
|||
|
||||
if (strcmp(tokens[0], "help") == 0) {
|
||||
os_sprintf(response,
|
||||
"show [config|stats|mqtt|script]\r\n|set [ssid|password|auto_connect|ap_ssid|ap_password|network|dns|ip|netmask|gw|ap_on|ap_open|speed|config_port] <val>\r\n|quit|save [config]|reset [factory]|lock [<password>]|unlock <password>");
|
||||
"show [config|stats|mqtt|script]\r\n|set [ssid|password|auto_connect|ap_ssid|ap_password|network|dns|ip|netmask|gw|ap_on|ap_open|speed|config_port|broker_user|broker_password] <val>\r\n|quit|save [config]|reset [factory]|lock [<password>]|unlock <password>");
|
||||
to_console(response);
|
||||
#ifdef SCRIPTED
|
||||
os_sprintf(response, "|script <port>");
|
||||
|
@ -396,6 +396,14 @@ void ICACHE_FLASH_ATTR console_handle_command(struct espconn *pespconn) {
|
|||
// if static DNS, add it
|
||||
os_sprintf(response, config.dns_addr.addr ? "DNS: %d.%d.%d.%d\r\n" : "", IP2STR(&config.dns_addr));
|
||||
to_console(response);
|
||||
|
||||
if (os_strcmp(config.mqtt_broker_user, "none") != 0) {
|
||||
os_sprintf(response,
|
||||
"MQTT broker username: %s password: %s\r\n",
|
||||
config.mqtt_broker_user,
|
||||
config.locked ? "***" : (char *)config.mqtt_broker_password);
|
||||
to_console(response);
|
||||
}
|
||||
#ifdef MQTT_CLIENT
|
||||
os_sprintf(response, "MQTT client %s\r\n", mqtt_enabled ? "enabled" : "disabled");
|
||||
to_console(response);
|
||||
|
@ -819,6 +827,23 @@ void ICACHE_FLASH_ATTR console_handle_command(struct espconn *pespconn) {
|
|||
goto command_handled;
|
||||
}
|
||||
#endif
|
||||
if (strcmp(tokens[1], "broker_user") == 0) {
|
||||
os_strncpy(config.mqtt_broker_user, tokens[2], 32);
|
||||
config.mqtt_broker_user[31] = '\0';
|
||||
os_sprintf(response, "Broker username set\r\n");
|
||||
goto command_handled;
|
||||
}
|
||||
|
||||
if (strcmp(tokens[1], "broker_password") == 0) {
|
||||
if (os_strcmp(tokens[2], "none") == 0) {
|
||||
config.mqtt_broker_password[0] = '\0';
|
||||
} else {
|
||||
os_strncpy(config.mqtt_broker_password, tokens[2], 32);
|
||||
config.mqtt_broker_password[31] = '\0';
|
||||
}
|
||||
os_sprintf(response, "Broker password set\r\n");
|
||||
goto command_handled;
|
||||
}
|
||||
#ifdef NTP
|
||||
if (strcmp(tokens[1], "ntp_server") == 0) {
|
||||
os_strncpy(config.ntp_server, tokens[2], 32);
|
||||
|
@ -1188,7 +1213,21 @@ void ICACHE_FLASH_ATTR user_set_station_config(void) {
|
|||
wifi_station_set_auto_connect(config.auto_connect != 0);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR user_init() {
|
||||
|
||||
bool ICACHE_FLASH_ATTR mqtt_broker_auth(const char* username, const char *password) {
|
||||
if (os_strcmp(config.mqtt_broker_user, "none") == 0)
|
||||
return true;
|
||||
|
||||
if (os_strcmp(username, config.mqtt_broker_user) != 0 ||
|
||||
os_strcmp(password, config.mqtt_broker_password) != 0) {
|
||||
os_printf("Authentication with %s/%s failed\r\n", username, password);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void user_init() {
|
||||
struct ip_info info;
|
||||
|
||||
connected = false;
|
||||
|
@ -1297,11 +1336,12 @@ void ICACHE_FLASH_ATTR user_init() {
|
|||
espconn_tcp_set_max_con(10);
|
||||
os_printf("Max number of TCP clients: %d\r\n", espconn_tcp_get_max_con());
|
||||
|
||||
MQTT_local_onData(MQTT_local_DataCallback);
|
||||
MQTT_server_onAuth(mqtt_broker_auth);
|
||||
|
||||
MQTT_server_start(1883 /*port */ , 30 /*max_subscriptions */ ,
|
||||
30 /*max_retained_items */ );
|
||||
|
||||
MQTT_local_onData(MQTT_local_DataCallback);
|
||||
|
||||
//Start task
|
||||
system_os_task(user_procTask, user_procTaskPrio, user_procTaskQueue, user_procTaskQueueLen);
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue