Skip to content

Commit

Permalink
Fix: avoid deprecated setAuthentication() to fix memory exhaustion
Browse files Browse the repository at this point in the history
with ESPAsyncWebServer 3.3.0, the setAuthentication() method became
deprecated and a replacement method was provided which acts as a shim
and uses the new middleware-based approach to setup authentication. in
order to eventually apply a changed "read-only access allowed" setting,
the setAuthentication() method was called periodically. the shim
implementation each time allocates a new AuthenticationMiddleware and
adds it to the chain of middlewares, eventually exhausting the memory.

we now use the new middleware-based approach ourselves and only add the
respective AuthenticatonMiddleware instance once to the respective
websocket server instance.

a regression where enabling unauthenticated read-only access is not
applied until reboot is also fixed. all the AuthenticationMiddleware
instances were never removed from the chain of middlewares when calling
setAuthentication("", "").
  • Loading branch information
schlimmchen committed Sep 30, 2024
1 parent b206cee commit ebb225f
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 12 deletions.
1 change: 1 addition & 0 deletions include/WebApi.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class WebApiClass {
public:
WebApiClass();
void init(Scheduler& scheduler);
void reload();

static bool checkCredentials(AsyncWebServerRequest* request);
static bool checkCredentialsReadonly(AsyncWebServerRequest* request);
Expand Down
2 changes: 2 additions & 0 deletions include/WebApi_ws_console.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ class WebApiWsConsoleClass {
public:
WebApiWsConsoleClass();
void init(AsyncWebServer& server, Scheduler& scheduler);
void reload();

private:
AsyncWebSocket _ws;
AuthenticationMiddleware _simpleDigestAuth;

Task _wsCleanupTask;
void wsCleanupTaskCb();
Expand Down
2 changes: 2 additions & 0 deletions include/WebApi_ws_live.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class WebApiWsLiveClass {
public:
WebApiWsLiveClass();
void init(AsyncWebServer& server, Scheduler& scheduler);
void reload();

private:
static void generateInverterCommonJsonResponse(JsonObject& root, std::shared_ptr<InverterAbstract> inv);
Expand All @@ -24,6 +25,7 @@ class WebApiWsLiveClass {
void onWebsocketEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);

AsyncWebSocket _ws;
AuthenticationMiddleware _simpleDigestAuth;

uint32_t _lastPublishStats[INV_MAX_COUNT] = { 0 };

Expand Down
6 changes: 6 additions & 0 deletions src/WebApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ void WebApiClass::init(Scheduler& scheduler)
_server.begin();
}

void WebApiClass::reload()
{
_webApiWsConsole.reload();
_webApiWsLive.reload();
}

bool WebApiClass::checkCredentials(AsyncWebServerRequest* request)
{
CONFIG_T& config = Configuration.get();
Expand Down
2 changes: 2 additions & 0 deletions src/WebApi_security.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request)
WebApi.writeConfig(retMsg);

WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);

WebApi.reload();
}

void WebApiSecurityClass::onAuthenticateGet(AsyncWebServerRequest* request)
Expand Down
23 changes: 17 additions & 6 deletions src/WebApi_ws_console.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,27 @@ void WebApiWsConsoleClass::init(AsyncWebServer& server, Scheduler& scheduler)

scheduler.addTask(_wsCleanupTask);
_wsCleanupTask.enable();

_simpleDigestAuth.setUsername(AUTH_USERNAME);
_simpleDigestAuth.setRealm("console websocket");

reload();
}

void WebApiWsConsoleClass::reload()
{
_ws.removeMiddleware(&_simpleDigestAuth);

auto const& config = Configuration.get();

if (config.Security.AllowReadonly) { return; }

_simpleDigestAuth.setPassword(config.Security.Password);
_ws.addMiddleware(&_simpleDigestAuth);
}

void WebApiWsConsoleClass::wsCleanupTaskCb()
{
// see: https://github.com/me-no-dev/ESPAsyncWebServer#limiting-the-number-of-web-socket-clients
_ws.cleanupClients();

if (Configuration.get().Security.AllowReadonly) {
_ws.setAuthentication("", "");
} else {
_ws.setAuthentication(AUTH_USERNAME, Configuration.get().Security.Password);
}
}
22 changes: 16 additions & 6 deletions src/WebApi_ws_live.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,28 @@ void WebApiWsLiveClass::init(AsyncWebServer& server, Scheduler& scheduler)

scheduler.addTask(_sendDataTask);
_sendDataTask.enable();
_simpleDigestAuth.setUsername(AUTH_USERNAME);
_simpleDigestAuth.setRealm("live websocket");

reload();
}

void WebApiWsLiveClass::reload()
{
_ws.removeMiddleware(&_simpleDigestAuth);

auto const& config = Configuration.get();

if (config.Security.AllowReadonly) { return; }

_simpleDigestAuth.setPassword(config.Security.Password);
_ws.addMiddleware(&_simpleDigestAuth);
}

void WebApiWsLiveClass::wsCleanupTaskCb()
{
// see: https://github.com/me-no-dev/ESPAsyncWebServer#limiting-the-number-of-web-socket-clients
_ws.cleanupClients();

if (Configuration.get().Security.AllowReadonly) {
_ws.setAuthentication("", "");
} else {
_ws.setAuthentication(AUTH_USERNAME, Configuration.get().Security.Password);
}
}

void WebApiWsLiveClass::sendDataTaskCb()
Expand Down

0 comments on commit ebb225f

Please sign in to comment.