Fork of the excellent esp8266-react - https://github.com/rjwats/esp8266-react
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

112 lines
4.0 KiB

  1. #include <SecuritySettingsService.h>
  2. SecuritySettingsService::SecuritySettingsService(AsyncWebServer* server, FS* fs) :
  3. _httpEndpoint(SecuritySettings::serialize,
  4. SecuritySettings::deserialize,
  5. this,
  6. server,
  7. SECURITY_SETTINGS_PATH,
  8. this),
  9. _fsPersistence(SecuritySettings::serialize, SecuritySettings::deserialize, this, fs, SECURITY_SETTINGS_FILE),
  10. _jwtHandler(FACTORY_JWT_SECRET) {
  11. addUpdateHandler([&](const String& originId) { configureJWTHandler(); }, false);
  12. }
  13. void SecuritySettingsService::begin() {
  14. _fsPersistence.readFromFS();
  15. configureJWTHandler();
  16. }
  17. Authentication SecuritySettingsService::authenticateRequest(AsyncWebServerRequest* request) {
  18. AsyncWebHeader* authorizationHeader = request->getHeader(AUTHORIZATION_HEADER);
  19. if (authorizationHeader) {
  20. String value = authorizationHeader->value();
  21. if (value.startsWith(AUTHORIZATION_HEADER_PREFIX)) {
  22. value = value.substring(AUTHORIZATION_HEADER_PREFIX_LEN);
  23. return authenticateJWT(value);
  24. }
  25. } else if (request->hasParam(ACCESS_TOKEN_PARAMATER)) {
  26. AsyncWebParameter* tokenParamater = request->getParam(ACCESS_TOKEN_PARAMATER);
  27. String value = tokenParamater->value();
  28. return authenticateJWT(value);
  29. }
  30. return Authentication();
  31. }
  32. void SecuritySettingsService::configureJWTHandler() {
  33. _jwtHandler.setSecret(_state.jwtSecret);
  34. }
  35. Authentication SecuritySettingsService::authenticateJWT(String& jwt) {
  36. DynamicJsonDocument payloadDocument(MAX_JWT_SIZE);
  37. _jwtHandler.parseJWT(jwt, payloadDocument);
  38. if (payloadDocument.is<JsonObject>()) {
  39. JsonObject parsedPayload = payloadDocument.as<JsonObject>();
  40. String username = parsedPayload["username"];
  41. for (User _user : _state.users) {
  42. if (_user.username == username && validatePayload(parsedPayload, &_user)) {
  43. return Authentication(_user);
  44. }
  45. }
  46. }
  47. return Authentication();
  48. }
  49. Authentication SecuritySettingsService::authenticate(const String& username, const String& password) {
  50. for (User _user : _state.users) {
  51. if (_user.username == username && _user.password == password) {
  52. return Authentication(_user);
  53. }
  54. }
  55. return Authentication();
  56. }
  57. inline void populateJWTPayload(JsonObject& payload, User* user) {
  58. payload["username"] = user->username;
  59. payload["admin"] = user->admin;
  60. }
  61. boolean SecuritySettingsService::validatePayload(JsonObject& parsedPayload, User* user) {
  62. DynamicJsonDocument jsonDocument(MAX_JWT_SIZE);
  63. JsonObject payload = jsonDocument.to<JsonObject>();
  64. populateJWTPayload(payload, user);
  65. return payload == parsedPayload;
  66. }
  67. String SecuritySettingsService::generateJWT(User* user) {
  68. DynamicJsonDocument jsonDocument(MAX_JWT_SIZE);
  69. JsonObject payload = jsonDocument.to<JsonObject>();
  70. populateJWTPayload(payload, user);
  71. return _jwtHandler.buildJWT(payload);
  72. }
  73. ArRequestFilterFunction SecuritySettingsService::filterRequest(AuthenticationPredicate predicate) {
  74. return [this, predicate](AsyncWebServerRequest* request) {
  75. Authentication authentication = authenticateRequest(request);
  76. return predicate(authentication);
  77. };
  78. }
  79. ArRequestHandlerFunction SecuritySettingsService::wrapRequest(ArRequestHandlerFunction onRequest,
  80. AuthenticationPredicate predicate) {
  81. return [this, onRequest, predicate](AsyncWebServerRequest* request) {
  82. Authentication authentication = authenticateRequest(request);
  83. if (!predicate(authentication)) {
  84. request->send(401);
  85. return;
  86. }
  87. onRequest(request);
  88. };
  89. }
  90. ArJsonRequestHandlerFunction SecuritySettingsService::wrapCallback(ArJsonRequestHandlerFunction callback,
  91. AuthenticationPredicate predicate) {
  92. return [this, callback, predicate](AsyncWebServerRequest* request, JsonVariant& json) {
  93. Authentication authentication = authenticateRequest(request);
  94. if (!predicate(authentication)) {
  95. request->send(401);
  96. return;
  97. }
  98. callback(request, json);
  99. };
  100. }