Skip to content

Commit

Permalink
fix: Clear the inventory data hash on re-authentication
Browse files Browse the repository at this point in the history
This fixes the case where e.g. a third party tool re-authenticates by
using the D-Bus API while mender-update is waiting for the next poll
interval to expire. The inventory will now be resubmitted when the
poll triggers.

Ticket: MEN-7873
Changelog: Title

Signed-off-by: John Olav Lund <[email protected]>
  • Loading branch information
John Olav Lund committed Dec 18, 2024
1 parent 3982958 commit 2aa058e
Show file tree
Hide file tree
Showing 9 changed files with 44 additions and 47 deletions.
19 changes: 16 additions & 3 deletions src/api/auth.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
#include <common/optional.hpp>

namespace mender {
namespace update {
namespace inventory {
class InventoryAPI;
}
} // namespace update
namespace api {
namespace auth {

Expand Down Expand Up @@ -71,8 +76,12 @@ using AuthenticatedAction = function<void(ExpectedAuthData)>;

class Authenticator {
public:
Authenticator(events::EventLoop &loop, chrono::seconds auth_timeout = chrono::minutes {1}) :
Authenticator(
events::EventLoop &loop,
std::shared_ptr<mender::update::inventory::InventoryAPI> inventory,
chrono::seconds auth_timeout = chrono::minutes {1}) :
loop_ {loop},
inventory_ {inventory},
auth_timeout_ {auth_timeout},
auth_timeout_timer_ {loop} {
}
Expand All @@ -98,6 +107,7 @@ class Authenticator {

events::EventLoop &loop_;

std::shared_ptr<mender::update::inventory::InventoryAPI> inventory_;
bool token_fetch_in_progress_ = false;
vector<AuthenticatedAction> pending_actions_;
chrono::seconds auth_timeout_;
Expand All @@ -107,8 +117,11 @@ class Authenticator {
#ifdef MENDER_USE_DBUS
class AuthenticatorDBus : public Authenticator {
public:
AuthenticatorDBus(events::EventLoop &loop, chrono::seconds auth_timeout = chrono::minutes {1}) :
Authenticator(loop, auth_timeout),
AuthenticatorDBus(
events::EventLoop &loop,
std::shared_ptr<mender::update::inventory::InventoryAPI> inventory,
chrono::seconds auth_timeout = chrono::minutes {1}) :
Authenticator(loop, inventory, auth_timeout),
dbus_client_ {loop} {
}

Expand Down
11 changes: 9 additions & 2 deletions src/api/auth/auth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

#include <common/log.hpp>

#include <mender-update/inventory.hpp>

namespace mender {
namespace api {
namespace auth {
Expand Down Expand Up @@ -80,7 +82,6 @@ error::Error Authenticator::WithToken(AuthenticatedAction action) {
}
// else record that token is already being fetched (by GetJwtToken()).
token_fetch_in_progress_ = true;

return error::NoError;
}

Expand Down Expand Up @@ -123,13 +124,15 @@ error::Error Authenticator::RequestNewToken() {
PostPendingActions(ex_auth_data);
}
});

return error::NoError;
}

void Authenticator::HandleReceivedToken(
common::ExpectedStringPair ex_auth_dbus_data, NoTokenAction no_token) {
auth_timeout_timer_.Cancel();
ExpectedAuthData ex_auth_data;

if (!ex_auth_dbus_data) {
mlog::Error("Error receiving the JWT token: " + ex_auth_dbus_data.error().String());
ex_auth_data = expected::unexpected(ex_auth_dbus_data.error());
Expand All @@ -151,7 +154,11 @@ void Authenticator::HandleReceivedToken(
return;
}
}

if (no_token == NoTokenAction::Finish && inventory_->has_submitted_inventory) {
mlog::Debug("Client has reauthenticated, clear inventory data cache");
inventory_->ClearDataCache();
inventory_->has_submitted_inventory = false;
}
PostPendingActions(ex_auth_data);
}

Expand Down
1 change: 0 additions & 1 deletion src/api/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ error::Error HTTPClient::AsyncCall(
});
return;
}
reauthenticated_ = true;
};

return authenticator_.WithToken(
Expand Down
8 changes: 0 additions & 8 deletions src/api/client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,6 @@ class HTTPClient : public Client {
authenticator_.ExpireToken();
}

bool HasReauthenticated() {
return reauthenticated_;
}

void SetReauthenticated(bool reauthenticated) {
reauthenticated_ = reauthenticated;
}

private:
events::EventLoop &event_loop_;
http::Client http_client_;
Expand Down
3 changes: 2 additions & 1 deletion src/mender-auth/api/auth.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@ class AuthenticatorHttp : public mender::api::auth::Authenticator {
AuthenticatorHttp(
events::EventLoop &loop,
const conf::MenderConfig &config,
std::shared_ptr<mender::update::inventory::InventoryAPI> inventory,
chrono::seconds auth_timeout = chrono::minutes {1}) :
Authenticator {loop, auth_timeout},
Authenticator {loop, inventory, auth_timeout},
config_ {config},
client_ {config.GetHttpClientConfig(), loop} {
}
Expand Down
13 changes: 7 additions & 6 deletions src/mender-update/daemon/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,16 +151,17 @@ Context::Context(
mender::update::context::MenderContext &mender_context, events::EventLoop &event_loop) :
mender_context(mender_context),
event_loop(event_loop),
#ifdef MENDER_USE_DBUS
authenticator(event_loop),
#elif defined(MENDER_EMBED_MENDER_AUTH)
authenticator(event_loop, mender_context.GetConfig()),
#endif
http_client(mender_context.GetConfig().GetHttpClientConfig(), event_loop, authenticator),
download_client(make_shared<http_resumer::DownloadResumerClient>(
mender_context.GetConfig().GetHttpClientConfig(), event_loop)),
deployment_client(make_shared<deployments::DeploymentClient>()),
inventory_client(make_shared<inventory::InventoryClient>()) {
inventory_client(make_shared<inventory::InventoryClient>()),
#ifdef MENDER_USE_DBUS
authenticator(event_loop, inventory_client)
#elif defined(MENDER_EMBED_MENDER_AUTH)
authenticator(event_loop, mender_context.GetConfig(), inventory_client)
#endif
{
}

///////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
13 changes: 5 additions & 8 deletions src/mender-update/daemon/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,13 +160,6 @@ class Context {
mender::update::context::MenderContext &mender_context;
events::EventLoop &event_loop;

#ifdef MENDER_USE_DBUS
auth::AuthenticatorDBus authenticator;
#elif defined(MENDER_EMBED_MENDER_AUTH)
mender::auth::api::auth::AuthenticatorHttp authenticator;
#endif

public:
// For polling, and for making status updates.
api::HTTPClient http_client;
// For the artifact download.
Expand All @@ -175,7 +168,11 @@ class Context {
shared_ptr<deployments::DeploymentAPI> deployment_client;
shared_ptr<inventory::InventoryAPI> inventory_client;

bool has_submitted_inventory {false};
#ifdef MENDER_USE_DBUS
auth::AuthenticatorDBus authenticator;
#elif defined(MENDER_EMBED_MENDER_AUTH)
mender::auth::api::auth::AuthenticatorHttp authenticator;
#endif

struct {
unique_ptr<StateData> state_data;
Expand Down
21 changes: 3 additions & 18 deletions src/mender-update/daemon/states.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ void SubmitInventoryState::DoSubmitInventory(Context &ctx, sm::EventPoster<State
return;
}
retry_.backoff.Reset();
ctx.has_submitted_inventory = true;
ctx.inventory_client->has_submitted_inventory = true;
poster.PostEvent(StateEvent::Success);
};

Expand Down Expand Up @@ -261,16 +261,7 @@ void PollForDeploymentState::OnEnter(Context &ctx, sm::EventPoster<StateEvent> &
[this, &ctx, &poster](mender::update::deployments::CheckUpdatesAPIResponse response) {
if (!response) {
log::Error("Error while polling for deployment: " + response.error().String());

// When unauthenticated,
// invalidate the cached inventory data so that it can be sent again
// and set clear the context flag so that it is triggered on re-authorization
if (response.error().code == auth::MakeError(auth::UnauthorizedError, "").code) {
if (ctx.has_submitted_inventory) {
ctx.inventory_client->ClearDataCache();
ctx.has_submitted_inventory = false;
}
} else {
if (response.error().code != auth::MakeError(auth::UnauthorizedError, "").code) {
// Replace the update poll timer with a backoff
HandlePollingError(ctx, poster);
}
Expand All @@ -279,13 +270,7 @@ void PollForDeploymentState::OnEnter(Context &ctx, sm::EventPoster<StateEvent> &
} else if (!response.value()) {
log::Info("No update available");
poster.PostEvent(StateEvent::NothingToDo);
if (ctx.http_client.HasReauthenticated()) {
log::Debug("Client has reauthenticated, clear inventory data cache");
ctx.inventory_client->ClearDataCache();
ctx.has_submitted_inventory = false;
ctx.http_client.SetReauthenticated(false);
}
if (not ctx.has_submitted_inventory) {
if (not ctx.inventory_client->has_submitted_inventory) {
// If we have not submitted inventory successfully at least
// once, schedule this after receiving a successful response
// with no update. This enables inventory to be submitted
Expand Down
2 changes: 2 additions & 0 deletions src/mender-update/inventory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ class InventoryAPI {
APIResponseHandler api_handler) = 0;

virtual void ClearDataCache() = 0;

bool has_submitted_inventory {false};
};

class InventoryClient : public InventoryAPI {
Expand Down

0 comments on commit 2aa058e

Please sign in to comment.