Implement role-aware HTTPS and SSH authentication
This commit is contained in:
+30
-36
@@ -1,5 +1,5 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-only */
|
||||
/* UART0 HTTPS lifecycle, shared credentials, certificate, and recovery commands. */
|
||||
/* UART0 HTTPS lifecycle, legacy recovery credential, and certificate commands. */
|
||||
|
||||
#include "web_console.h"
|
||||
|
||||
@@ -43,22 +43,20 @@ static int show_status(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
char username[WEB_SECURITY_USERNAME_CAPACITY + 1U] = {0};
|
||||
size_t username_length = 0U;
|
||||
esp_err_t security_error = web_security_copy_username(
|
||||
username, sizeof(username), &username_length);
|
||||
user_database_snapshot_t users;
|
||||
esp_err_t users_error = user_database_get_snapshot(&users);
|
||||
printf("HTTPS: initialized=%s running=%s transitioning=%s port=%u last-error=%s\n",
|
||||
snapshot.initialized ? "yes" : "no",
|
||||
snapshot.running ? "yes" : "no",
|
||||
snapshot.transitioning ? "yes" : "no",
|
||||
(unsigned int)snapshot.port,
|
||||
esp_err_to_name(snapshot.last_error));
|
||||
if (security_error == ESP_OK) {
|
||||
printf("Authentication: HTTP Basic over TLS, username=%.*s, shared with SSH\n",
|
||||
(int)username_length, username);
|
||||
if (users_error == ESP_OK) {
|
||||
printf("Authentication: HTTP Basic over TLS via user database, users=%u admins=%u\n",
|
||||
(unsigned int)users.user_count, (unsigned int)users.admin_count);
|
||||
} else {
|
||||
printf("Authentication material unavailable: %s; use 'web reset --force' to replace it.\n",
|
||||
esp_err_to_name(security_error));
|
||||
printf("Authentication database unavailable: %s; use 'user recover --force'.\n",
|
||||
esp_err_to_name(users_error));
|
||||
}
|
||||
printf("Endpoints: GET /, GET /api/status, POST /api/ws-ticket, WSS /ws/serial\n");
|
||||
|
||||
@@ -81,11 +79,20 @@ static int show_status(void)
|
||||
if (!session->active) {
|
||||
continue;
|
||||
}
|
||||
printf(" slot=%u fd=%d generation=%" PRIu32 " broker=%" PRIu32
|
||||
" role=%s tx-pending=%s closing=%s\n",
|
||||
printf(" slot=%u fd=%d generation=%" PRIu32 " account=%s user-role=%s"
|
||||
" method=%s broker=%" PRIu32
|
||||
" broker-role=%s tx-pending=%s closing=%s\n",
|
||||
(unsigned int)index,
|
||||
session->socket_fd,
|
||||
session->generation,
|
||||
session->principal_valid ? session->username : "-",
|
||||
session->principal_valid
|
||||
? user_role_to_string(session->user_role)
|
||||
: "-",
|
||||
session->principal_valid &&
|
||||
session->auth_method == USER_AUTH_METHOD_PASSWORD
|
||||
? "password"
|
||||
: "unknown",
|
||||
session->broker_client_id,
|
||||
session->writer ? "writer" : "observer",
|
||||
session->tx_pending ? "yes" : "no",
|
||||
@@ -169,7 +176,8 @@ static int show_credentials(void)
|
||||
credentials.username);
|
||||
printf("Password: %.*s\n", (int)credentials.password_length,
|
||||
credentials.password);
|
||||
printf("These credentials protect HTTPS and SSH. Keep them private.\n");
|
||||
printf("Phase 8B uses the user database for HTTPS and SSH authentication.\n");
|
||||
printf("This legacy credential is retained only for migration and physical recovery.\n");
|
||||
secure_wipe(&credentials, sizeof(credentials));
|
||||
return 0;
|
||||
}
|
||||
@@ -241,6 +249,12 @@ static void synchronize_migrated_user(
|
||||
return;
|
||||
}
|
||||
if (synchronized) {
|
||||
(void)web_serial_transport_revoke_user(
|
||||
(const uint8_t *)credentials->username,
|
||||
credentials->username_length);
|
||||
(void)ssh_transport_revoke_user(
|
||||
(const uint8_t *)credentials->username,
|
||||
credentials->username_length);
|
||||
printf("The pre-bootstrap migrated user credential was synchronized.\n");
|
||||
return;
|
||||
}
|
||||
@@ -248,7 +262,7 @@ static void synchronize_migrated_user(
|
||||
user_database_snapshot_t snapshot;
|
||||
if (user_database_get_snapshot(&snapshot) == ESP_OK &&
|
||||
snapshot.admin_bootstrapped) {
|
||||
printf("Phase 8A note: this legacy HTTPS/SSH credential is separate from bootstrapped user passwords until Phase 8B.\n");
|
||||
printf("This legacy recovery credential is separate from role-based user passwords.\n");
|
||||
} else {
|
||||
printf("Warning: no matching pre-bootstrap migrated user was synchronized; establish an administrator with 'user bootstrap'.\n");
|
||||
}
|
||||
@@ -264,17 +278,7 @@ static int rotate_credentials(void)
|
||||
}
|
||||
|
||||
synchronize_migrated_user(&credentials);
|
||||
esp_err_t web_revoke_error = web_serial_transport_revoke_sessions();
|
||||
esp_err_t ssh_revoke_error = ssh_transport_revoke_sessions();
|
||||
printf("Administrative credentials rotated and persisted. Existing HTTPS and SSH credentials are now invalid.\n");
|
||||
if (web_revoke_error != ESP_OK && web_revoke_error != ESP_ERR_INVALID_STATE) {
|
||||
printf("Warning: existing WebSocket sessions could not be revoked: %s\n",
|
||||
esp_err_to_name(web_revoke_error));
|
||||
}
|
||||
if (ssh_revoke_error != ESP_OK && ssh_revoke_error != ESP_ERR_INVALID_STATE) {
|
||||
printf("Warning: existing SSH sessions could not be revoked: %s\n",
|
||||
esp_err_to_name(ssh_revoke_error));
|
||||
}
|
||||
printf("Legacy migration/recovery credential rotated and persisted.\n");
|
||||
printf("Username: %.*s\nPassword: %.*s\n",
|
||||
(int)credentials.username_length, credentials.username,
|
||||
(int)credentials.password_length, credentials.password);
|
||||
@@ -311,17 +315,7 @@ static int reset_material(void)
|
||||
}
|
||||
|
||||
synchronize_migrated_user(&credentials);
|
||||
esp_err_t web_revoke_error = web_serial_transport_revoke_sessions();
|
||||
esp_err_t ssh_revoke_error = ssh_transport_revoke_sessions();
|
||||
printf("Administrative credentials, HTTPS certificate, and HTTPS private key replaced and persisted.\n");
|
||||
if (web_revoke_error != ESP_OK && web_revoke_error != ESP_ERR_INVALID_STATE) {
|
||||
printf("Warning: existing WebSocket sessions could not be revoked: %s\n",
|
||||
esp_err_to_name(web_revoke_error));
|
||||
}
|
||||
if (ssh_revoke_error != ESP_OK && ssh_revoke_error != ESP_ERR_INVALID_STATE) {
|
||||
printf("Warning: existing SSH sessions could not be revoked: %s\n",
|
||||
esp_err_to_name(ssh_revoke_error));
|
||||
}
|
||||
printf("Legacy recovery credential, HTTPS certificate, and HTTPS private key replaced and persisted.\n");
|
||||
printf("Username: %.*s\nPassword: %.*s\n",
|
||||
(int)credentials.username_length, credentials.username,
|
||||
(int)credentials.password_length, credentials.password);
|
||||
|
||||
Reference in New Issue
Block a user