Implement role-aware HTTPS and SSH authentication
This commit is contained in:
+35
-12
@@ -20,14 +20,19 @@
|
||||
#include "serial_service.h"
|
||||
#include "session_broker.h"
|
||||
#include "usb_cdc_transport.h"
|
||||
#include "user_database.h"
|
||||
#include "web_security.h"
|
||||
#include "web_serial_transport.h"
|
||||
#include "web_ui.h"
|
||||
#include "wifi_manager.h"
|
||||
|
||||
#define WEB_SERVER_PORT 443U
|
||||
#define WEB_SERVER_MAX_AUTHORIZATION 128U
|
||||
#define WEB_SERVER_MAX_BASIC_DECODED 64U
|
||||
#define WEB_SERVER_MAX_BASIC_DECODED \
|
||||
(USER_DATABASE_USERNAME_CAPACITY + 1U + USER_DATABASE_PASSWORD_CAPACITY)
|
||||
#define WEB_SERVER_MAX_BASIC_ENCODED \
|
||||
(((WEB_SERVER_MAX_BASIC_DECODED + 2U) / 3U) * 4U)
|
||||
#define WEB_SERVER_MAX_AUTHORIZATION \
|
||||
((sizeof("Basic ") - 1U) + WEB_SERVER_MAX_BASIC_ENCODED + 1U)
|
||||
#define WEB_SERVER_STATUS_JSON_CAPACITY 3072U
|
||||
|
||||
static SemaphoreHandle_t s_server_mutex;
|
||||
@@ -101,12 +106,15 @@ static esp_err_t send_authentication_required(httpd_req_t *request)
|
||||
return send_plain_error(request, "401 Unauthorized", "Authentication required.\n");
|
||||
}
|
||||
|
||||
static esp_err_t authenticate_request(httpd_req_t *request, bool *authenticated)
|
||||
static esp_err_t authenticate_request(httpd_req_t *request,
|
||||
user_principal_t *principal,
|
||||
bool *authenticated)
|
||||
{
|
||||
char authorization[WEB_SERVER_MAX_AUTHORIZATION] = {0};
|
||||
uint8_t decoded[WEB_SERVER_MAX_BASIC_DECODED] = {0};
|
||||
size_t decoded_length = 0U;
|
||||
esp_err_t result = ESP_OK;
|
||||
memset(principal, 0, sizeof(*principal));
|
||||
*authenticated = false;
|
||||
|
||||
increment_counter(&s_counters.requests);
|
||||
@@ -133,28 +141,32 @@ static esp_err_t authenticate_request(httpd_req_t *request, bool *authenticated)
|
||||
}
|
||||
size_t username_length = (size_t)(separator - decoded);
|
||||
size_t password_length = decoded_length - username_length - 1U;
|
||||
result = web_security_authenticate_basic(decoded, username_length,
|
||||
separator + 1U, password_length,
|
||||
authenticated);
|
||||
result = user_database_authenticate_password(
|
||||
decoded, username_length, separator + 1U, password_length,
|
||||
principal, authenticated);
|
||||
|
||||
cleanup:
|
||||
secure_wipe(authorization, sizeof(authorization));
|
||||
secure_wipe(decoded, sizeof(decoded));
|
||||
if (result != ESP_OK) {
|
||||
memset(principal, 0, sizeof(*principal));
|
||||
return result;
|
||||
}
|
||||
if (*authenticated) {
|
||||
increment_counter(&s_counters.authenticated_requests);
|
||||
} else {
|
||||
memset(principal, 0, sizeof(*principal));
|
||||
increment_counter(&s_counters.authentication_failures);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t authorize_or_respond(httpd_req_t *request, bool *authorized)
|
||||
static esp_err_t authorize_or_respond(httpd_req_t *request,
|
||||
user_principal_t *principal,
|
||||
bool *authorized)
|
||||
{
|
||||
*authorized = false;
|
||||
esp_err_t error = authenticate_request(request, authorized);
|
||||
esp_err_t error = authenticate_request(request, principal, authorized);
|
||||
if (error != ESP_OK) {
|
||||
*authorized = false;
|
||||
return send_plain_error(request, "503 Service Unavailable",
|
||||
@@ -167,14 +179,17 @@ static esp_err_t send_authenticated_ui(httpd_req_t *request,
|
||||
web_ui_resource_t resource,
|
||||
uint64_t *counter)
|
||||
{
|
||||
user_principal_t principal = {0};
|
||||
bool authorized = false;
|
||||
esp_err_t error = authorize_or_respond(request, &authorized);
|
||||
esp_err_t error = authorize_or_respond(request, &principal, &authorized);
|
||||
if (error != ESP_OK || !authorized) {
|
||||
secure_wipe(&principal, sizeof(principal));
|
||||
return error;
|
||||
}
|
||||
increment_counter(counter);
|
||||
|
||||
error = web_ui_send_response(request, resource);
|
||||
secure_wipe(&principal, sizeof(principal));
|
||||
if (error != ESP_OK) {
|
||||
increment_counter(&s_counters.response_errors);
|
||||
}
|
||||
@@ -195,18 +210,23 @@ static esp_err_t asset_handler(httpd_req_t *request)
|
||||
|
||||
static esp_err_t ticket_handler(httpd_req_t *request)
|
||||
{
|
||||
user_principal_t principal = {0};
|
||||
bool authorized = false;
|
||||
esp_err_t error = authorize_or_respond(request, &authorized);
|
||||
esp_err_t error = authorize_or_respond(request, &principal, &authorized);
|
||||
if (error != ESP_OK || !authorized) {
|
||||
secure_wipe(&principal, sizeof(principal));
|
||||
return error;
|
||||
}
|
||||
increment_counter(&s_counters.ticket_requests);
|
||||
if (request->content_len != 0U) {
|
||||
secure_wipe(&principal, sizeof(principal));
|
||||
return send_plain_error(request, "400 Bad Request",
|
||||
"Ticket requests must have an empty body.\n");
|
||||
}
|
||||
|
||||
error = web_serial_transport_handle_authenticated_ticket_request(request);
|
||||
error = web_serial_transport_handle_authenticated_ticket_request(
|
||||
request, &principal);
|
||||
secure_wipe(&principal, sizeof(principal));
|
||||
if (error == ESP_OK) {
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -254,11 +274,14 @@ static void format_fingerprint(const uint8_t fingerprint[WEB_SECURITY_SHA256_LEN
|
||||
|
||||
static esp_err_t status_handler(httpd_req_t *request)
|
||||
{
|
||||
user_principal_t principal = {0};
|
||||
bool authorized = false;
|
||||
esp_err_t error = authorize_or_respond(request, &authorized);
|
||||
esp_err_t error = authorize_or_respond(request, &principal, &authorized);
|
||||
if (error != ESP_OK || !authorized) {
|
||||
secure_wipe(&principal, sizeof(principal));
|
||||
return error;
|
||||
}
|
||||
secure_wipe(&principal, sizeof(principal));
|
||||
increment_counter(&s_counters.status_requests);
|
||||
|
||||
wifi_manager_snapshot_t wifi = {0};
|
||||
|
||||
Reference in New Issue
Block a user