add authentication service
This commit is contained in:
		
							
								
								
									
										52
									
								
								src/AsyncAuthJsonWebHandler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/AsyncAuthJsonWebHandler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | |||||||
|  | #ifndef AsyncAuthJsonWebHandler_H_ | ||||||
|  | #define AsyncAuthJsonWebHandler_H_ | ||||||
|  |  | ||||||
|  | #include <ESPAsyncWebServer.h> | ||||||
|  | #include <AsyncJsonWebHandler.h> | ||||||
|  | #include <ArduinoJson.h> | ||||||
|  | #include <SecurityManager.h> | ||||||
|  |  | ||||||
|  | typedef std::function<void(AsyncWebServerRequest *request, JsonDocument &jsonDocument, Authentication &authentication)> AuthenticationJsonRequestCallback; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Extends AsyncJsonWebHandler with a wrapper which verifies the user is authenticated. | ||||||
|  |  *  | ||||||
|  |  * TODO - Extend with role checking support, possibly with a callback to verify the user. | ||||||
|  |  */ | ||||||
|  | class AsyncAuthJsonWebHandler: public AsyncJsonWebHandler { | ||||||
|  |  | ||||||
|  |   private: | ||||||
|  |     SecurityManager *_securityManager; | ||||||
|  |     using AsyncJsonWebHandler::onRequest; | ||||||
|  |      | ||||||
|  |   public: | ||||||
|  |  | ||||||
|  |     AsyncAuthJsonWebHandler() :  | ||||||
|  |       AsyncJsonWebHandler(), _securityManager(NULL) {} | ||||||
|  |  | ||||||
|  |     ~AsyncAuthJsonWebHandler() {} | ||||||
|  |  | ||||||
|  |     void setSecurityManager(SecurityManager *securityManager) {  | ||||||
|  |       _securityManager = securityManager; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void onRequest(AuthenticationJsonRequestCallback callback) { | ||||||
|  |       AsyncJsonWebHandler::onRequest([this, callback](AsyncWebServerRequest *request, JsonDocument &jsonDocument) { | ||||||
|  |         if(!_securityManager) { | ||||||
|  |           Serial.print("Security manager not configured for endpoint: "); | ||||||
|  |           Serial.println(_uri);            | ||||||
|  |           request->send(500); | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  |         Authentication authentication = _securityManager->authenticateRequest(request); | ||||||
|  |         if (!authentication.isAuthenticated()) { | ||||||
|  |           request->send(401); | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  |         callback(request, jsonDocument, authentication); | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif // end AsyncAuthJsonWebHandler_H_ | ||||||
| @@ -17,24 +17,25 @@ | |||||||
| 
 | 
 | ||||||
| typedef std::function<void(AsyncWebServerRequest *request, JsonDocument &jsonDocument)> JsonRequestCallback; | typedef std::function<void(AsyncWebServerRequest *request, JsonDocument &jsonDocument)> JsonRequestCallback; | ||||||
| 
 | 
 | ||||||
| class AsyncJsonRequestWebHandler: public AsyncWebHandler { | class AsyncJsonWebHandler: public AsyncWebHandler { | ||||||
| 
 | 
 | ||||||
|   private: |   private: | ||||||
| 
 |  | ||||||
|     String _uri; |  | ||||||
|     WebRequestMethodComposite _method; |     WebRequestMethodComposite _method; | ||||||
|     JsonRequestCallback _onRequest; |     JsonRequestCallback _onRequest; | ||||||
|     size_t _maxContentLength; |     size_t _maxContentLength; | ||||||
| 
 | 
 | ||||||
|  |   protected: | ||||||
|  |     String _uri; | ||||||
|  | 
 | ||||||
|   public: |   public: | ||||||
| 
 | 
 | ||||||
|     AsyncJsonRequestWebHandler() : |     AsyncJsonWebHandler() :       | ||||||
|       _uri(), |  | ||||||
|       _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), |       _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), | ||||||
|       _onRequest(NULL), |       _onRequest(NULL), | ||||||
|       _maxContentLength(ASYNC_JSON_REQUEST_DEFAULT_MAX_SIZE) {} |       _maxContentLength(ASYNC_JSON_REQUEST_DEFAULT_MAX_SIZE), | ||||||
|  |       _uri() {} | ||||||
| 
 | 
 | ||||||
|     ~AsyncJsonRequestWebHandler() {} |     ~AsyncJsonWebHandler() {} | ||||||
| 
 | 
 | ||||||
|     void setUri(const String& uri) { _uri = uri; } |     void setUri(const String& uri) { _uri = uri; } | ||||||
|     void setMethod(WebRequestMethodComposite method) { _method = method; } |     void setMethod(WebRequestMethodComposite method) { _method = method; } | ||||||
| @@ -61,7 +62,9 @@ class AsyncJsonRequestWebHandler: public AsyncWebHandler { | |||||||
|     virtual void handleRequest(AsyncWebServerRequest *request) override final { |     virtual void handleRequest(AsyncWebServerRequest *request) override final { | ||||||
|       // no request configured
 |       // no request configured
 | ||||||
|       if(!_onRequest) { |       if(!_onRequest) { | ||||||
|         request->send(404); |         Serial.print("No request callback was configured for endpoint: "); | ||||||
|  |         Serial.println(_uri);            | ||||||
|  |         request->send(500); | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
							
								
								
									
										45
									
								
								src/AuthenticationService.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/AuthenticationService.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | #include <AuthenticationService.h> | ||||||
|  |  | ||||||
|  | AuthenticationService::AuthenticationService(AsyncWebServer* server, SecurityManager* securityManager): | ||||||
|  |   _server(server), _securityManager(securityManager) {     | ||||||
|  |   server->on(VERIFY_AUTHORIZATION_PATH, HTTP_GET, std::bind(&AuthenticationService::verifyAuthorization, this, std::placeholders::_1)); | ||||||
|  |  | ||||||
|  |   _signInHandler.setUri(SIGN_IN_PATH); | ||||||
|  |   _signInHandler.setMethod(HTTP_POST); | ||||||
|  |   _signInHandler.setMaxContentLength(MAX_SECURITY_MANAGER_SETTINGS_SIZE); | ||||||
|  |   _signInHandler.onRequest(std::bind(&AuthenticationService::signIn, this, std::placeholders::_1, std::placeholders::_2)); | ||||||
|  |   server->addHandler(&_signInHandler); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | AuthenticationService::~AuthenticationService() {} | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Verifys that the request supplied a valid JWT. | ||||||
|  |  */ | ||||||
|  | void AuthenticationService::verifyAuthorization(AsyncWebServerRequest *request) { | ||||||
|  |   Authentication authentication = _securityManager->authenticateRequest(request); | ||||||
|  |   request->send(authentication.isAuthenticated() ? 200: 401); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Signs in a user if the username and password match. Provides a JWT to be used in the Authorization header in subsequent requests. | ||||||
|  |  */ | ||||||
|  | void AuthenticationService::signIn(AsyncWebServerRequest *request, JsonDocument &jsonDocument){ | ||||||
|  |   if (jsonDocument.is<JsonObject>()) { | ||||||
|  |     String username =  jsonDocument["username"]; | ||||||
|  |     String password = jsonDocument["password"]; | ||||||
|  |     Authentication authentication = _securityManager->authenticate(username, password); | ||||||
|  |     if (authentication.isAuthenticated()) { | ||||||
|  |       User* user = authentication.getUser();       | ||||||
|  |       AsyncJsonResponse * response = new AsyncJsonResponse(MAX_USERS_SIZE); | ||||||
|  |       JsonObject jsonObject = response->getRoot(); | ||||||
|  |       jsonObject["access_token"] = _securityManager->generateJWT(user); | ||||||
|  |       response->setLength(); | ||||||
|  |       request->send(response); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   AsyncWebServerResponse *response =  request->beginResponse(401); | ||||||
|  |   request->send(response); | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										30
									
								
								src/AuthenticationService.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/AuthenticationService.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | #ifndef AuthenticationService_H_ | ||||||
|  | #define AuthenticationService_H_ | ||||||
|  |  | ||||||
|  | #include <SecurityManager.h> | ||||||
|  |  | ||||||
|  | #define VERIFY_AUTHORIZATION_PATH "/rest/verifyAuthorization" | ||||||
|  | #define SIGN_IN_PATH "/rest/signIn" | ||||||
|  |  | ||||||
|  | #define MAX_AUTHENTICATION_SIZE 256 | ||||||
|  |  | ||||||
|  | class AuthenticationService  { | ||||||
|  |  | ||||||
|  |   public: | ||||||
|  |  | ||||||
|  |     AuthenticationService(AsyncWebServer* server, SecurityManager* securityManager) ; | ||||||
|  |     ~AuthenticationService(); | ||||||
|  |  | ||||||
|  |   private: | ||||||
|  |     // server instance  | ||||||
|  |     AsyncWebServer* _server; | ||||||
|  |     SecurityManager* _securityManager; | ||||||
|  |     AsyncJsonWebHandler _signInHandler; | ||||||
|  |  | ||||||
|  |     // endpoint functions | ||||||
|  |     void signIn(AsyncWebServerRequest *request, JsonDocument &jsonDocument); | ||||||
|  |     void verifyAuthorization(AsyncWebServerRequest *request); | ||||||
|  |  | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif // end SecurityManager_h | ||||||
| @@ -1,23 +1,7 @@ | |||||||
| #include <SecurityManager.h> | #include <SecurityManager.h> | ||||||
|  |  | ||||||
| SecurityManager::SecurityManager(AsyncWebServer* server, FS* fs) : SettingsPersistence(fs, SECURITY_SETTINGS_FILE) { | SecurityManager::SecurityManager(AsyncWebServer* server, FS* fs) : SettingsPersistence(fs, SECURITY_SETTINGS_FILE) { | ||||||
|   // fetch users |  | ||||||
|   server->on(USERS_PATH, HTTP_GET, std::bind(&SecurityManager::fetchUsers, this, std::placeholders::_1)); |   server->on(USERS_PATH, HTTP_GET, std::bind(&SecurityManager::fetchUsers, this, std::placeholders::_1)); | ||||||
|  |  | ||||||
|   // sign in request |  | ||||||
|   _signInRequestHandler.setUri(SIGN_IN_PATH); |  | ||||||
|   _signInRequestHandler.setMethod(HTTP_POST); |  | ||||||
|   _signInRequestHandler.setMaxContentLength(MAX_SECURITY_MANAGER_SETTINGS_SIZE); |  | ||||||
|   _signInRequestHandler.onRequest(std::bind(&SecurityManager::signIn, this, std::placeholders::_1, std::placeholders::_2)); |  | ||||||
|   server->addHandler(&_signInRequestHandler); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     // sign in request |  | ||||||
|   _testVerifiction.setUri(TEST_VERIFICATION_PATH); |  | ||||||
|   _testVerifiction.setMethod(HTTP_POST); |  | ||||||
|   _testVerifiction.setMaxContentLength(MAX_SECURITY_MANAGER_SETTINGS_SIZE); |  | ||||||
|   _testVerifiction.onRequest(std::bind(&SecurityManager::testVerification, this, std::placeholders::_1, std::placeholders::_2)); |  | ||||||
|   server->addHandler(&_testVerifiction); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| SecurityManager::~SecurityManager() {} | SecurityManager::~SecurityManager() {} | ||||||
| @@ -68,54 +52,6 @@ void SecurityManager::writeToJsonObject(JsonObject& root) { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| // TODO - Decide about default role behaviour, don't over-engineer (multiple roles, boolean admin flag???). |  | ||||||
| void SecurityManager::signIn(AsyncWebServerRequest *request, JsonDocument &jsonDocument){ |  | ||||||
|   if (jsonDocument.is<JsonObject>()) { |  | ||||||
|     // authenticate user |  | ||||||
|     String username =  jsonDocument["username"]; |  | ||||||
|     String password = jsonDocument["password"]; |  | ||||||
|     Authentication authentication = authenticate(username, password); |  | ||||||
|  |  | ||||||
|     if (authentication.isAuthenticated()) { |  | ||||||
|       User& user = authentication.getUser(); |  | ||||||
|  |  | ||||||
|       // create JWT |  | ||||||
|       DynamicJsonDocument _jsonDocument(MAX_JWT_SIZE);       |  | ||||||
|       JsonObject jwt = _jsonDocument.to<JsonObject>(); |  | ||||||
|       jwt["username"] = user.getUsername(); |  | ||||||
|       jwt["role"] = user.getRole(); |  | ||||||
|        |  | ||||||
|       // send JWT response |  | ||||||
|       AsyncJsonResponse * response = new AsyncJsonResponse(MAX_USERS_SIZE); |  | ||||||
|       JsonObject jsonObject = response->getRoot(); |  | ||||||
|       jsonObject["access_token"] = jwtHandler.buildJWT(jwt); |  | ||||||
|       response->setLength(); |  | ||||||
|       request->send(response); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // authentication failed |  | ||||||
|   AsyncWebServerResponse *response =  request->beginResponse(401); |  | ||||||
|   request->send(response); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void SecurityManager::testVerification(AsyncWebServerRequest *request, JsonDocument &jsonDocument){ |  | ||||||
|   if (jsonDocument.is<JsonObject>()) {     |  | ||||||
|     String accessToken =  jsonDocument["access_token"]; |  | ||||||
|     DynamicJsonDocument parsedJwt(MAX_JWT_SIZE); |  | ||||||
|     jwtHandler.parseJWT(accessToken, parsedJwt); |  | ||||||
|     if (parsedJwt.is<JsonObject>()){ |  | ||||||
|       AsyncWebServerResponse *response =  request->beginResponse(200); |  | ||||||
|       request->send(response); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   // authentication failed |  | ||||||
|   AsyncWebServerResponse *response =  request->beginResponse(401); |  | ||||||
|   request->send(response); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void SecurityManager::fetchUsers(AsyncWebServerRequest *request) { | void SecurityManager::fetchUsers(AsyncWebServerRequest *request) { | ||||||
|   AsyncJsonResponse * response = new AsyncJsonResponse(MAX_USERS_SIZE); |   AsyncJsonResponse * response = new AsyncJsonResponse(MAX_USERS_SIZE); | ||||||
|   JsonObject jsonObject = response->getRoot();   |   JsonObject jsonObject = response->getRoot();   | ||||||
| @@ -132,36 +68,56 @@ void SecurityManager::begin() { | |||||||
|   jwtHandler.setSecret(_jwtSecret); |   jwtHandler.setSecret(_jwtSecret); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* | Authentication SecurityManager::authenticateRequest(AsyncWebServerRequest *request) { | ||||||
| * TODO - VERIFY JWT IS CORRECT! |   AsyncWebHeader* authorizationHeader = request->getHeader(AUTHORIZATION_HEADER); | ||||||
| */ |   if (authorizationHeader) { | ||||||
| Authentication SecurityManager::verify(String jwt) { |     String value = authorizationHeader->value(); | ||||||
|   DynamicJsonDocument parsedJwt(MAX_JWT_SIZE); |     value.startsWith(AUTHORIZATION_HEADER_PREFIX); | ||||||
|   jwtHandler.parseJWT(jwt, parsedJwt); |     value = value.substring(AUTHORIZATION_HEADER_PREFIX_LEN); | ||||||
|   if (parsedJwt.is<JsonObject>()) { |     return authenticateJWT(value); | ||||||
|     String username = parsedJwt["username"]; |   }   | ||||||
|  |   return Authentication(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Authentication SecurityManager::authenticateJWT(String jwt) { | ||||||
|  |   DynamicJsonDocument payloadDocument(MAX_JWT_SIZE); | ||||||
|  |   jwtHandler.parseJWT(jwt, payloadDocument); | ||||||
|  |   if (payloadDocument.is<JsonObject>()) { | ||||||
|  |     JsonObject parsedPayload = payloadDocument.as<JsonObject>(); | ||||||
|  |     String username = parsedPayload["username"]; | ||||||
|     for (User _user : _users) { |     for (User _user : _users) { | ||||||
|       if (_user.getUsername() == username){ |       if (_user.getUsername() == username && validatePayload(parsedPayload, &_user)){ | ||||||
|         return Authentication::forUser(_user); |         return Authentication(_user); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   return Authentication::notAuthenticated(); |   return Authentication(); | ||||||
| } | } | ||||||
|  |  | ||||||
| Authentication SecurityManager::authenticate(String username, String password) { | Authentication SecurityManager::authenticate(String username, String password) { | ||||||
|   for (User _user : _users) { |   for (User _user : _users) { | ||||||
|     if (_user.getUsername() == username && _user.getPassword() == password){ |     if (_user.getUsername() == username && _user.getPassword() == password){ | ||||||
|       return Authentication::forUser(_user); |       return Authentication(_user); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   return Authentication::notAuthenticated(); |   return Authentication(); | ||||||
| } | } | ||||||
|  |  | ||||||
| String SecurityManager::generateJWT(User user) { | inline void populateJWTPayload(JsonObject &payload, User *user) { | ||||||
|   DynamicJsonDocument _jsonDocument(MAX_JWT_SIZE);       |   payload["username"] = user->getUsername(); | ||||||
|   JsonObject jwt = _jsonDocument.to<JsonObject>(); |   payload["role"] = user->getRole(); | ||||||
|   jwt["username"] = user.getUsername(); | } | ||||||
|   jwt["role"] = user.getRole(); |  | ||||||
|   return jwtHandler.buildJWT(jwt); | boolean SecurityManager::validatePayload(JsonObject &parsedPayload, User *user) { | ||||||
|  |   DynamicJsonDocument _jsonDocument(MAX_JWT_SIZE);       | ||||||
|  |   JsonObject payload = _jsonDocument.to<JsonObject>(); | ||||||
|  |   populateJWTPayload(payload, user); | ||||||
|  |   return payload == parsedPayload; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | String SecurityManager::generateJWT(User *user) { | ||||||
|  |   DynamicJsonDocument _jsonDocument(MAX_JWT_SIZE);       | ||||||
|  |   JsonObject payload = _jsonDocument.to<JsonObject>(); | ||||||
|  |   populateJWTPayload(payload, user); | ||||||
|  |   return jwtHandler.buildJWT(payload); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -13,18 +13,15 @@ | |||||||
| #define SECURITY_SETTINGS_FILE "/config/securitySettings.json" | #define SECURITY_SETTINGS_FILE "/config/securitySettings.json" | ||||||
|  |  | ||||||
| #define USERS_PATH "/rest/users" | #define USERS_PATH "/rest/users" | ||||||
| #define AUTHENTICATE_PATH "/rest/authenticate" |  | ||||||
| #define SIGN_IN_PATH "/rest/signIn" | #define AUTHORIZATION_HEADER "Authorization" | ||||||
| #define TEST_VERIFICATION_PATH "/rest/verification" | #define AUTHORIZATION_HEADER_PREFIX "Bearer " | ||||||
|  | #define AUTHORIZATION_HEADER_PREFIX_LEN 7 | ||||||
|  |  | ||||||
| #define MAX_JWT_SIZE 128 | #define MAX_JWT_SIZE 128 | ||||||
| #define MAX_SECURITY_MANAGER_SETTINGS_SIZE 512 | #define MAX_SECURITY_MANAGER_SETTINGS_SIZE 512 | ||||||
| #define SECURITY_MANAGER_MAX_USERS 5 | #define SECURITY_MANAGER_MAX_USERS 5 | ||||||
|  |  | ||||||
| #define ANONYMOUS_USERNAME "_anonymous" |  | ||||||
| #define ANONYMOUS_PASSWORD "" |  | ||||||
| #define ANONYMOUS_ROLE "" |  | ||||||
|  |  | ||||||
| #define MAX_USERS_SIZE 1024 | #define MAX_USERS_SIZE 1024 | ||||||
|  |  | ||||||
| class User { | class User { | ||||||
| @@ -45,28 +42,24 @@ class User { | |||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| const User NOT_AUTHENTICATED = User(ANONYMOUS_USERNAME, ANONYMOUS_PASSWORD, ANONYMOUS_ROLE); |  | ||||||
|  |  | ||||||
| class Authentication { | class Authentication { | ||||||
|   private: |   private: | ||||||
|     User _user; |     User *_user; | ||||||
|     boolean _authenticated; |     boolean _authenticated; | ||||||
|     Authentication(User user, boolean authenticated) : _user(user), _authenticated(authenticated) {} |  | ||||||
|   public: |   public: | ||||||
|     // NOOP |     Authentication(User& user): _user(new User(user)), _authenticated(true) {} | ||||||
|     ~Authentication(){} |     Authentication() : _user(NULL), _authenticated(false) {}   | ||||||
|     User& getUser() { |     ~Authentication() { | ||||||
|  |       if (_user != NULL){ | ||||||
|  |         delete(_user); | ||||||
|  |       }       | ||||||
|  |     } | ||||||
|  |     User* getUser() { | ||||||
|       return _user; |       return _user; | ||||||
|     } |     } | ||||||
|     bool isAuthenticated() { |     bool isAuthenticated() { | ||||||
|       return _authenticated; |       return _authenticated; | ||||||
|     } |     } | ||||||
|     static Authentication forUser(User user){ |  | ||||||
|       return Authentication(user, true); |  | ||||||
|     } |  | ||||||
|     static Authentication notAuthenticated(){ |  | ||||||
|       return Authentication(NOT_AUTHENTICATED, false); |  | ||||||
|     } |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class SecurityManager : public SettingsPersistence { | class SecurityManager : public SettingsPersistence { | ||||||
| @@ -79,19 +72,19 @@ class SecurityManager :  public SettingsPersistence { | |||||||
|     void begin(); |     void begin(); | ||||||
|  |  | ||||||
|     /* |     /* | ||||||
|     * Lookup the user by JWT |     * Authenticate, returning the user if found | ||||||
|     */ |  | ||||||
|     Authentication verify(String jwt); |  | ||||||
|  |  | ||||||
|     /* |  | ||||||
|     * Authenticate, returning the user if found. |  | ||||||
|     */ |     */ | ||||||
|     Authentication authenticate(String username, String password); |     Authentication authenticate(String username, String password); | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |     * Check the request header for the Authorization token | ||||||
|  |     */ | ||||||
|  |     Authentication authenticateRequest(AsyncWebServerRequest *request); | ||||||
|  |      | ||||||
|     /* |     /* | ||||||
|     * Generate a JWT for the user provided |     * Generate a JWT for the user provided | ||||||
|     */ |     */ | ||||||
|     String generateJWT(User user); |     String generateJWT(User *user); | ||||||
|  |  | ||||||
|   protected: |   protected: | ||||||
|  |  | ||||||
| @@ -102,11 +95,6 @@ class SecurityManager :  public SettingsPersistence { | |||||||
|     // jwt handler |     // jwt handler | ||||||
|     ArduinoJsonJWT jwtHandler = ArduinoJsonJWT(DEFAULT_JWT_SECRET); |     ArduinoJsonJWT jwtHandler = ArduinoJsonJWT(DEFAULT_JWT_SECRET); | ||||||
|  |  | ||||||
|     // server instance |  | ||||||
|     AsyncWebServer* _server; |  | ||||||
|     AsyncJsonRequestWebHandler _signInRequestHandler; |  | ||||||
|     AsyncJsonRequestWebHandler _testVerifiction; |  | ||||||
|  |  | ||||||
|     // access point settings |     // access point settings | ||||||
|     String _jwtSecret; |     String _jwtSecret; | ||||||
|     std::list<String> _roles; |     std::list<String> _roles; | ||||||
| @@ -114,8 +102,17 @@ class SecurityManager :  public SettingsPersistence { | |||||||
|  |  | ||||||
|     // endpoint functions |     // endpoint functions | ||||||
|     void fetchUsers(AsyncWebServerRequest *request); |     void fetchUsers(AsyncWebServerRequest *request); | ||||||
|     void signIn(AsyncWebServerRequest *request, JsonDocument &jsonDocument); |  | ||||||
|     void testVerification(AsyncWebServerRequest *request, JsonDocument &jsonDocument); |     /* | ||||||
|  |     * Lookup the user by JWT | ||||||
|  |     */ | ||||||
|  |     Authentication authenticateJWT(String jwt); | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |     * Verify the payload is correct | ||||||
|  |     */ | ||||||
|  |     boolean validatePayload(JsonObject &parsedPayload, User *user); | ||||||
|  |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #endif // end SecurityManager_h | #endif // end SecurityManager_h | ||||||
| @@ -4,13 +4,13 @@ | |||||||
| #include <ESPAsyncWebServer.h> | #include <ESPAsyncWebServer.h> | ||||||
| #include <FS.h> | #include <FS.h> | ||||||
| #include <ArduinoJson.h> | #include <ArduinoJson.h> | ||||||
| #include <AsyncJsonRequestWebHandler.h> | #include <AsyncJsonWebHandler.h> | ||||||
| #include <AsyncArduinoJson6.h> | #include <AsyncArduinoJson6.h> | ||||||
|  |  | ||||||
| /** | /** | ||||||
| * At the moment, not expecting settings service to have to deal with large JSON | * At the moment, not expecting settings service to have to deal with large JSON | ||||||
| * files this could be made configurable fairly simply, it's exposed on | * files this could be made configurable fairly simply, it's exposed on | ||||||
| * AsyncJsonRequestWebHandler with a setter. | * AsyncJsonWebHandler with a setter. | ||||||
| */ | */ | ||||||
| #define MAX_SETTINGS_SIZE 1024 | #define MAX_SETTINGS_SIZE 1024 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ | |||||||
| #include <SettingsPersistence.h> | #include <SettingsPersistence.h> | ||||||
| #include <ESPAsyncWebServer.h> | #include <ESPAsyncWebServer.h> | ||||||
| #include <ArduinoJson.h> | #include <ArduinoJson.h> | ||||||
| #include <AsyncJsonRequestWebHandler.h> | #include <AsyncJsonWebHandler.h> | ||||||
| #include <AsyncArduinoJson6.h> | #include <AsyncArduinoJson6.h> | ||||||
|  |  | ||||||
| /* | /* | ||||||
| @@ -22,7 +22,7 @@ class SettingsService : public SettingsPersistence { | |||||||
|  |  | ||||||
| private: | private: | ||||||
|  |  | ||||||
|   AsyncJsonRequestWebHandler _updateHandler; |   AsyncJsonWebHandler _updateHandler; | ||||||
|  |  | ||||||
|   void fetchConfig(AsyncWebServerRequest *request){ |   void fetchConfig(AsyncWebServerRequest *request){ | ||||||
|     AsyncJsonResponse * response = new AsyncJsonResponse(MAX_SETTINGS_SIZE); |     AsyncJsonResponse * response = new AsyncJsonResponse(MAX_SETTINGS_SIZE); | ||||||
|   | |||||||
| @@ -12,12 +12,12 @@ | |||||||
| #include <ESPAsyncWebServer.h> | #include <ESPAsyncWebServer.h> | ||||||
| #include <ArduinoJson.h> | #include <ArduinoJson.h> | ||||||
| #include <AsyncArduinoJson6.h> | #include <AsyncArduinoJson6.h> | ||||||
| #include <AsyncJsonRequestWebHandler.h> | #include <AsyncJsonWebHandler.h> | ||||||
|  |  | ||||||
| /** | /** | ||||||
| * At the moment, not expecting services to have to deal with large JSON | * At the moment, not expecting services to have to deal with large JSON | ||||||
| * files this could be made configurable fairly simply, it's exposed on | * files this could be made configurable fairly simply, it's exposed on | ||||||
| * AsyncJsonRequestWebHandler with a setter. | * AsyncJsonWebHandler with a setter. | ||||||
| */ | */ | ||||||
| #define MAX_SETTINGS_SIZE 1024 | #define MAX_SETTINGS_SIZE 1024 | ||||||
|  |  | ||||||
| @@ -31,7 +31,7 @@ class SimpleService { | |||||||
|  |  | ||||||
| private: | private: | ||||||
|  |  | ||||||
|   AsyncJsonRequestWebHandler _updateHandler; |   AsyncJsonWebHandler _updateHandler; | ||||||
|  |  | ||||||
|   void fetchConfig(AsyncWebServerRequest *request){ |   void fetchConfig(AsyncWebServerRequest *request){ | ||||||
|     AsyncJsonResponse * response = new AsyncJsonResponse(MAX_SETTINGS_SIZE); |     AsyncJsonResponse * response = new AsyncJsonResponse(MAX_SETTINGS_SIZE); | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								src/main.cpp
									
									
									
									
									
								
							| @@ -10,15 +10,18 @@ | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #include <FS.h> | #include <FS.h> | ||||||
|  |  | ||||||
|  | #include <SecurityManager.h> | ||||||
| #include <WiFiSettingsService.h> | #include <WiFiSettingsService.h> | ||||||
| #include <WiFiStatus.h> |  | ||||||
| #include <WiFiScanner.h> |  | ||||||
| #include <APSettingsService.h> | #include <APSettingsService.h> | ||||||
| #include <NTPSettingsService.h> | #include <NTPSettingsService.h> | ||||||
| #include <NTPStatus.h> |  | ||||||
| #include <OTASettingsService.h> | #include <OTASettingsService.h> | ||||||
|  | #include <AuthenticationService.h> | ||||||
|  | #include <WiFiScanner.h> | ||||||
|  | #include <WiFiStatus.h> | ||||||
|  | #include <NTPStatus.h> | ||||||
| #include <APStatus.h> | #include <APStatus.h> | ||||||
| #include <SecurityManager.h> |  | ||||||
|  |  | ||||||
| #define SERIAL_BAUD_RATE 115200 | #define SERIAL_BAUD_RATE 115200 | ||||||
|  |  | ||||||
| @@ -30,6 +33,7 @@ WiFiSettingsService wifiSettingsService = WiFiSettingsService(&server, &SPIFFS); | |||||||
| APSettingsService apSettingsService = APSettingsService(&server, &SPIFFS); | APSettingsService apSettingsService = APSettingsService(&server, &SPIFFS); | ||||||
| NTPSettingsService ntpSettingsService = NTPSettingsService(&server, &SPIFFS); | NTPSettingsService ntpSettingsService = NTPSettingsService(&server, &SPIFFS); | ||||||
| OTASettingsService otaSettingsService = OTASettingsService(&server, &SPIFFS); | OTASettingsService otaSettingsService = OTASettingsService(&server, &SPIFFS); | ||||||
|  | AuthenticationService authenticationService = AuthenticationService(&server, &securityManager); | ||||||
|  |  | ||||||
| WiFiScanner wifiScanner = WiFiScanner(&server); | WiFiScanner wifiScanner = WiFiScanner(&server); | ||||||
| WiFiStatus wifiStatus = WiFiStatus(&server); | WiFiStatus wifiStatus = WiFiStatus(&server); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user