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 23, 2024
1 parent 3982958 commit 9d1d579
Show file tree
Hide file tree
Showing 8 changed files with 24 additions and 36 deletions.
11 changes: 9 additions & 2 deletions src/api/auth.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ struct AuthData {
using ExpectedAuthData = expected::expected<AuthData, error::Error>;

using AuthenticatedAction = function<void(ExpectedAuthData)>;
using ReAuthenticatedAction = function<void()>;

class Authenticator {
public:
Expand All @@ -78,9 +79,15 @@ class Authenticator {
}

void ExpireToken();

error::Error WithToken(AuthenticatedAction action);

// Register a callback to be called on re-authentication. Will overwrite the
// stored callback with the new one.
void RegisterTokenReceivedCallback(ReAuthenticatedAction action) {
action_ = action;
}


protected:
enum class NoTokenAction {
Finish,
Expand All @@ -97,11 +104,11 @@ class Authenticator {
void HandleReceivedToken(common::ExpectedStringPair ex_auth_dbus_data, NoTokenAction no_token);

events::EventLoop &loop_;

bool token_fetch_in_progress_ = false;
vector<AuthenticatedAction> pending_actions_;
chrono::seconds auth_timeout_;
events::Timer auth_timeout_timer_;
ReAuthenticatedAction action_ {nullptr};
};

#ifdef MENDER_USE_DBUS
Expand Down
5 changes: 3 additions & 2 deletions src/api/auth/auth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,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 @@ -151,7 +150,9 @@ void Authenticator::HandleReceivedToken(
return;
}
}

if (no_token == NoTokenAction::Finish && action_ != nullptr) {
action_();
}
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
9 changes: 0 additions & 9 deletions src/api/client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,19 +79,10 @@ 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_;
auth::Authenticator &authenticator_;
bool reauthenticated_ {false};
};

} // namespace api
Expand Down
3 changes: 0 additions & 3 deletions src/mender-update/daemon/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,6 @@ class Context {
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,8 +174,6 @@ class Context {
shared_ptr<deployments::DeploymentAPI> deployment_client;
shared_ptr<inventory::InventoryAPI> inventory_client;

bool has_submitted_inventory {false};

struct {
unique_ptr<StateData> state_data;
io::ReaderPtr artifact_reader;
Expand Down
8 changes: 7 additions & 1 deletion src/mender-update/daemon/state_machine/state_machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,14 @@ StateMachine::StateMachine(Context &ctx, events::EventLoop &event_loop) :
runner_(ctx) {
runner_.AddStateMachine(deployment_tracking_.states_);
runner_.AddStateMachine(main_states_);

runner_.AttachToEventLoop(event_loop_);
ctx.authenticator.RegisterTokenReceivedCallback([&ctx]() {
if (ctx.inventory_client->has_submitted_inventory) {
log::Debug("Client has re-authenticated - clear inventory data cache");
ctx.inventory_client->ClearDataCache();
ctx.inventory_client->has_submitted_inventory = false;
}
});

using se = StateEvent;
using tf = sm::TransitionFlag;
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 9d1d579

Please sign in to comment.