From eca14cf81c9e9c27a0f6fe5b7b821555f7b69cf8 Mon Sep 17 00:00:00 2001 From: Rick Watson Date: Tue, 30 Apr 2019 23:49:28 +0100 Subject: [PATCH] playing with some ideas for security management --- data/config/securitySettings.json | 1 + src/SecurityManager.cpp | 63 +++++++++++++++++++++++-------- src/SecurityManager.h | 32 ++++++++++------ src/main.cpp | 6 +++ 4 files changed, 75 insertions(+), 27 deletions(-) diff --git a/data/config/securitySettings.json b/data/config/securitySettings.json index 4b7a9d2..4d169f0 100644 --- a/data/config/securitySettings.json +++ b/data/config/securitySettings.json @@ -1,5 +1,6 @@ { "jwt_secret":"esp8266-react", + "roles": ["admin", "guest"], "users": [ { "username": "admin", diff --git a/src/SecurityManager.cpp b/src/SecurityManager.cpp index 01909e4..b293825 100644 --- a/src/SecurityManager.cpp +++ b/src/SecurityManager.cpp @@ -1,51 +1,84 @@ #include SecurityManager::SecurityManager(AsyncWebServer* server, FS* fs) : SettingsPersistence(fs, SECURITY_SETTINGS_FILE) { + server->on(USERS_PATH, HTTP_GET, std::bind(&SecurityManager::fetchUsers, this, std::placeholders::_1)); } SecurityManager::~SecurityManager() {} void SecurityManager::readFromJsonObject(JsonObject& root) { + // secret _jwtSecret = root["jwt_secret"] | DEFAULT_JWT_SECRET; - while (_numUsers > 0){ - delete _users[--_numUsers]; + // roles + _roles.clear(); + if (root["roles"].is()) { + JsonArray roles = root["roles"]; + for (JsonVariant role : roles) { + _roles.push_back(role.as()); + } } + // users + _users.clear(); if (root["users"].is()) { JsonArray users = root["users"]; - _numUsers = 0; - // TODO - complete defence against bad data - for (int i =0; i < min(SECURITY_MANAGER_MAX_USERS, (int) users.size()); i++){ - JsonObject user = users[i]; - String username = user["username"];; + for (JsonVariant user : users) { + String username = user["username"]; String password = user["password"]; String role = user["role"]; - _users[_numUsers++] = new User(username, password, role); + _users.push_back(User(username, password, role)); } } } void SecurityManager::writeToJsonObject(JsonObject& root) { - // TODO + // secret + root["jwt_secret"] = _jwtSecret; + + // roles + JsonArray roles = root.createNestedArray("roles"); + for (String _role : _roles) { + roles.add(_role); + } + + // users + JsonArray users = root.createNestedArray("users"); + for (User _user : _users) { + JsonObject user = users.createNestedObject(); + user["username"] = _user.getUsername(); + user["password"] = _user.getPassword(); + user["role"] = _user.getRole(); + } +} + +void SecurityManager::fetchUsers(AsyncWebServerRequest *request) { + AsyncJsonResponse * response = new AsyncJsonResponse(MAX_USERS_SIZE); + JsonObject jsonObject = response->getRoot(); + writeToJsonObject(jsonObject); + response->setLength(); + request->send(response); } void SecurityManager::begin() { - // TODO + readFromFS(); } User SecurityManager::verifyUser(String jwt) { // TODO return NOT_AUTHENTICATED; } -User authenticate(String username, String password) { - // TODO + +User SecurityManager::authenticate(String username, String password) { + for (User _user : _users) { + if (_user.getUsername() == username && _user.getPassword() == password){ + return _user; + } + } return NOT_AUTHENTICATED; } -String generateJWT(User user) { +String SecurityManager::generateJWT(User user) { // TODO return ""; } - - diff --git a/src/SecurityManager.h b/src/SecurityManager.h index 8f419a4..5bda393 100644 --- a/src/SecurityManager.h +++ b/src/SecurityManager.h @@ -1,5 +1,8 @@ -#ifndef APSettingsConfig_h -#define APSettingsConfig_h +#ifndef SecurityManager_h +#define SecurityManager_h + +#include +#include #include #include @@ -8,16 +11,17 @@ #define DEFAULT_JWT_SECRET "esp8266-react" #define SECURITY_SETTINGS_FILE "/config/securitySettings.json" + +#define USERS_PATH "/rest/users" #define AUTHENTICATE_PATH "/rest/authenticate" #define SECURITY_MANAGER_MAX_USERS 5 -#define UNAUTHENTICATED_USERNAME "" +#define UNAUTHENTICATED_USERNAME "_anonymous" #define UNAUTHENTICATED_PASSWORD "" #define UNAUTHENTICATED_ROLE "" -#define ROLE_ADMIN "admin" -#define ROLE_GUEST "guest" +#define MAX_USERS_SIZE 1024 class User { private: @@ -38,9 +42,6 @@ class User { bool isAuthenticated() { return _username != UNAUTHENTICATED_USERNAME; } - bool isAdmin() { - return isAuthenticated() && _username == ROLE_ADMIN; - } }; const User NOT_AUTHENTICATED = User(UNAUTHENTICATED_USERNAME, UNAUTHENTICATED_PASSWORD, UNAUTHENTICATED_ROLE); @@ -55,7 +56,7 @@ class SecurityManager : public SettingsPersistence { void begin(); User verifyUser(String jwt); - User authenticate(); + User authenticate(String username, String password); String generateJWT(User user); protected: @@ -65,10 +66,17 @@ class SecurityManager : public SettingsPersistence { private: + // server instance + AsyncWebServer* _server; + // access point settings String _jwtSecret; - User *_users[SECURITY_MANAGER_MAX_USERS]; - int _numUsers; + std::list _roles; + std::list _users; + + // endpoint functions + void fetchUsers(AsyncWebServerRequest *request); + }; -#endif // end APSettingsConfig_h \ No newline at end of file +#endif // end SecurityManager_h \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 23112a6..7544857 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,11 +18,14 @@ #include #include #include +#include #define SERIAL_BAUD_RATE 115200 AsyncWebServer server(80); +SecurityManager securityManager = SecurityManager(&server, &SPIFFS); + WiFiSettingsService wifiSettingsService = WiFiSettingsService(&server, &SPIFFS); APSettingsService apSettingsService = APSettingsService(&server, &SPIFFS); NTPSettingsService ntpSettingsService = NTPSettingsService(&server, &SPIFFS); @@ -40,6 +43,9 @@ void setup() { Serial.begin(SERIAL_BAUD_RATE); SPIFFS.begin(); + // start security manager + securityManager.begin(); + // start services ntpSettingsService.begin(); otaSettingsService.begin();