1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
|
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/base/instance_identity_token_getter_impl.h"
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include "base/functional/callback.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "base/values.h"
#include "net/base/net_errors.h"
#include "remoting/base/http_status.h"
#include "remoting/base/instance_identity_token.h"
#include "remoting/base/logging.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace remoting {
InstanceIdentityTokenGetterImpl::InstanceIdentityTokenGetterImpl(
std::string_view audience,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
: audience_(audience), compute_engine_service_client_(url_loader_factory) {}
InstanceIdentityTokenGetterImpl::~InstanceIdentityTokenGetterImpl() = default;
void InstanceIdentityTokenGetterImpl::RetrieveToken(TokenCallback on_token) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Check expiration, clear token if no longer valid. Reduce the expiration by
// a small amount to ensure the token provided will remain valid in cases
// where its usage may be delayed a bit.
if ((token_expiration_time_ - base::Minutes(5)) < base::Time::Now()) {
identity_token_.clear();
}
if (!identity_token_.empty()) {
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(on_token), identity_token_));
return;
}
queued_callbacks_.emplace_back(std::move(on_token));
// Only make a service request for the first caller, the rest will be queued
// and provided with the token when the request completes.
if (queued_callbacks_.size() == 1) {
compute_engine_service_client_.GetInstanceIdentityToken(
audience_,
base::BindOnce(&InstanceIdentityTokenGetterImpl::OnTokenRetrieved,
weak_ptr_factory_.GetWeakPtr()));
}
}
void InstanceIdentityTokenGetterImpl::OnTokenRetrieved(
const HttpStatus& response) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (response.ok()) {
auto jwt = response.response_body();
auto validated_token = InstanceIdentityToken::Create(jwt);
if (validated_token.has_value()) {
HOST_LOG << "Retrieved fresh instance identity token";
if (identity_token_.empty()) {
// Log the token retrieved if this is the first successful fetch.
HOST_LOG << "Instance identity token contents:\n" << *validated_token;
}
identity_token_ = std::move(jwt);
auto token_exp_value = validated_token->payload().FindInt("exp");
auto now = base::Time::Now();
if (token_exp_value.has_value()) {
token_expiration_time_ =
base::Time::FromSecondsSinceUnixEpoch(*token_exp_value);
LOG_IF(WARNING, token_expiration_time_ < now + base::Minutes(30) ||
token_expiration_time_ > now + base::Minutes(90))
<< "Token expiration is outside of the expected lifetime window "
<< "which is ~60 minutes.";
} else {
LOG(WARNING) << "Token payload missing valid 'exp' integer value which "
<< "may mean other fields are also invalid: "
<< validated_token->payload();
token_expiration_time_ = now;
}
}
} else {
int error_code = static_cast<int>(response.error_code());
LOG(WARNING) << "Failed to retrieve an Instance Identity token.\n"
<< " Error code: " << error_code << "\n"
<< " Message: " << response.error_message() << "\n"
<< " Body: " << response.response_body();
}
auto callbacks = std::move(queued_callbacks_);
for (auto& callback : callbacks) {
std::move(callback).Run(identity_token_);
}
}
} // namespace remoting
|