DAC: Disable probe when MIC is selected via env var (#6755)
* DAC: Disable probe when MIC is selected via env var * Fix missing newline at end of default_azure_credential_test.cpp * Update sdk/identity/azure-identity/test/ut/managed_identity_credential_test.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update sdk/identity/azure-identity/test/ut/default_azure_credential_test.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Clang fix * Make options always the last parameter * Clang-format * Add const char overload * MIC: do not send probe request by default, unless it is used in DAC, unless DAC has MIC only selected via env var * Rename isProbeEnabled to useProbeRequest, make options the last arg even in internal APIs * Include the rest of the files * Fix * only expose UseProbeRequest in options * Clang-format --------- Co-authored-by: Anton Kolesnyk <antkmsft@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
313a43af4f
commit
ead279936d
@ -4,6 +4,10 @@
|
||||
|
||||
### Features Added
|
||||
|
||||
- Added `UseProbeRequest` option for `ManagedIdentityCredential`.
|
||||
- By default, `ManagedIdentityCredential` does not send a probe request, unless it is a part of credential chain in `DefaultAzureCredential`.
|
||||
- When `AZURE_TOKEN_CREDENTIALS` environment variable is configured to `ManagedIdentityCredential`, the `DefaultAzureCredential` does not issue a probe request and performs retries with exponential backoff.
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
@ -168,6 +168,18 @@ namespace Azure { namespace Identity {
|
||||
* it was configured.
|
||||
*/
|
||||
ManagedIdentityId IdentityId;
|
||||
|
||||
/**
|
||||
* @brief If Azure Instance Metadata Service (IMDS) gets selected as managed identity source,
|
||||
* specifies whether the first request should be a short probe request (`true`), instead of a
|
||||
* normal request with retries and exponential backoff (`false`). Default is `false`.
|
||||
*
|
||||
* @note When `true`, there's a potential that the credential would not detect IMDS being
|
||||
* available on a machine, if the response was not received fast enough. When `false` and IMDS
|
||||
* is not available, credential creation may take tens of seconds until multiple attempts to get
|
||||
* a response from IMDS would fail.
|
||||
*/
|
||||
bool UseProbeRequest = false;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -181,6 +193,11 @@ namespace Azure { namespace Identity {
|
||||
private:
|
||||
std::unique_ptr<_detail::ManagedIdentitySource> m_managedIdentitySource;
|
||||
|
||||
explicit ManagedIdentityCredential(
|
||||
std::string const& clientId,
|
||||
bool useProbeRequest,
|
||||
Core::Credentials::TokenCredentialOptions const& options);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Destructs `%TokenCredential`.
|
||||
@ -196,8 +213,8 @@ namespace Azure { namespace Identity {
|
||||
*/
|
||||
explicit ManagedIdentityCredential(
|
||||
std::string const& clientId = std::string(),
|
||||
Azure::Core::Credentials::TokenCredentialOptions const& options
|
||||
= Azure::Core::Credentials::TokenCredentialOptions());
|
||||
Core::Credentials::TokenCredentialOptions const& options
|
||||
= Core::Credentials::TokenCredentialOptions());
|
||||
|
||||
/**
|
||||
* @brief Constructs a Managed Identity Credential.
|
||||
@ -212,8 +229,7 @@ namespace Azure { namespace Identity {
|
||||
*
|
||||
* @param options Options for token retrieval.
|
||||
*/
|
||||
explicit ManagedIdentityCredential(
|
||||
Azure::Core::Credentials::TokenCredentialOptions const& options);
|
||||
explicit ManagedIdentityCredential(Core::Credentials::TokenCredentialOptions const& options);
|
||||
|
||||
/**
|
||||
* @brief Gets an authentication token.
|
||||
|
||||
@ -69,25 +69,6 @@ DefaultAzureCredential::DefaultAzureCredential(
|
||||
Create;
|
||||
};
|
||||
|
||||
static const std::array<CredentialInfo, 4> credentials = {
|
||||
CredentialInfo{
|
||||
true,
|
||||
"EnvironmentCredential",
|
||||
[](auto options) { return std::make_shared<EnvironmentCredential>(options); }},
|
||||
CredentialInfo{
|
||||
true,
|
||||
"WorkloadIdentityCredential",
|
||||
[](auto options) { return std::make_shared<WorkloadIdentityCredential>(options); }},
|
||||
CredentialInfo{
|
||||
true,
|
||||
"ManagedIdentityCredential",
|
||||
[](auto options) { return std::make_shared<ManagedIdentityCredential>(options); }},
|
||||
CredentialInfo{
|
||||
false,
|
||||
"AzureCliCredential",
|
||||
[](auto options) { return std::make_shared<AzureCliCredential>(options); }},
|
||||
};
|
||||
|
||||
const auto envVarValue = Environment::GetVariable(CredentialSpecifierEnvVarName);
|
||||
const auto trimmedEnvVarValue = StringExtensions::Trim(envVarValue);
|
||||
|
||||
@ -99,6 +80,35 @@ DefaultAzureCredential::DefaultAzureCredential(
|
||||
}
|
||||
|
||||
bool specificCred = false;
|
||||
const std::array<CredentialInfo, 4> credentials = {
|
||||
CredentialInfo{
|
||||
true,
|
||||
"EnvironmentCredential",
|
||||
[](auto options) { return std::make_shared<EnvironmentCredential>(options); }},
|
||||
CredentialInfo{
|
||||
true,
|
||||
"WorkloadIdentityCredential",
|
||||
[](auto options) { return std::make_shared<WorkloadIdentityCredential>(options); }},
|
||||
CredentialInfo{
|
||||
true,
|
||||
"ManagedIdentityCredential",
|
||||
[&](auto options) {
|
||||
// If specifically 'ManagedIdentityCredential' is used, do not perform a probe
|
||||
// request, going for the full retry with exponential backoffs instead.
|
||||
ManagedIdentityCredentialOptions managedIdentityCredentialOptions;
|
||||
static_cast<Core::Credentials::TokenCredentialOptions&>(
|
||||
managedIdentityCredentialOptions)
|
||||
= options;
|
||||
|
||||
managedIdentityCredentialOptions.UseProbeRequest = !specificCred;
|
||||
return std::make_shared<ManagedIdentityCredential>(managedIdentityCredentialOptions);
|
||||
}},
|
||||
CredentialInfo{
|
||||
false,
|
||||
"AzureCliCredential",
|
||||
[](auto options) { return std::make_shared<AzureCliCredential>(options); }},
|
||||
};
|
||||
|
||||
if (!trimmedEnvVarValue.empty())
|
||||
{
|
||||
for (const auto& cred : credentials)
|
||||
|
||||
@ -14,6 +14,7 @@ std::unique_ptr<_detail::ManagedIdentitySource> CreateManagedIdentitySource(
|
||||
std::string const& clientId,
|
||||
std::string const& objectId,
|
||||
std::string const& resourceId,
|
||||
bool useProbeRequest,
|
||||
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
||||
{
|
||||
using namespace Azure::Core::Credentials;
|
||||
@ -23,6 +24,7 @@ std::unique_ptr<_detail::ManagedIdentitySource> CreateManagedIdentitySource(
|
||||
std::string const& clientId,
|
||||
std::string const& objectId,
|
||||
std::string const& resourceId,
|
||||
bool useProbeRequest,
|
||||
TokenCredentialOptions const& options)
|
||||
= {AppServiceV2019ManagedIdentitySource::Create,
|
||||
AppServiceV2017ManagedIdentitySource::Create,
|
||||
@ -34,7 +36,8 @@ std::unique_ptr<_detail::ManagedIdentitySource> CreateManagedIdentitySource(
|
||||
// For that reason, it is not possible to cover that execution branch in tests.
|
||||
for (auto create : managedIdentitySourceCreate)
|
||||
{
|
||||
if (auto source = create(credentialName, clientId, objectId, resourceId, options))
|
||||
if (auto source
|
||||
= create(credentialName, clientId, objectId, resourceId, useProbeRequest, options))
|
||||
{
|
||||
return source;
|
||||
}
|
||||
@ -49,11 +52,19 @@ ManagedIdentityCredential::~ManagedIdentityCredential() = default;
|
||||
|
||||
ManagedIdentityCredential::ManagedIdentityCredential(
|
||||
std::string const& clientId,
|
||||
bool useProbeRequest,
|
||||
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
||||
: TokenCredential("ManagedIdentityCredential")
|
||||
{
|
||||
m_managedIdentitySource
|
||||
= CreateManagedIdentitySource(GetCredentialName(), clientId, {}, {}, options);
|
||||
m_managedIdentitySource = CreateManagedIdentitySource(
|
||||
GetCredentialName(), clientId, {}, {}, useProbeRequest, options);
|
||||
}
|
||||
|
||||
ManagedIdentityCredential::ManagedIdentityCredential(
|
||||
std::string const& clientId,
|
||||
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
||||
: ManagedIdentityCredential(clientId, false, options)
|
||||
{
|
||||
}
|
||||
|
||||
ManagedIdentityCredential::ManagedIdentityCredential(
|
||||
@ -64,20 +75,35 @@ ManagedIdentityCredential::ManagedIdentityCredential(
|
||||
switch (idType)
|
||||
{
|
||||
case ManagedIdentityIdKind::SystemAssigned:
|
||||
m_managedIdentitySource
|
||||
= CreateManagedIdentitySource(GetCredentialName(), {}, {}, {}, options);
|
||||
m_managedIdentitySource = CreateManagedIdentitySource(
|
||||
GetCredentialName(), {}, {}, {}, options.UseProbeRequest, options);
|
||||
break;
|
||||
case ManagedIdentityIdKind::ClientId:
|
||||
m_managedIdentitySource = CreateManagedIdentitySource(
|
||||
GetCredentialName(), options.IdentityId.GetId(), {}, {}, options);
|
||||
GetCredentialName(),
|
||||
options.IdentityId.GetId(),
|
||||
{},
|
||||
{},
|
||||
options.UseProbeRequest,
|
||||
options);
|
||||
break;
|
||||
case ManagedIdentityIdKind::ObjectId:
|
||||
m_managedIdentitySource = CreateManagedIdentitySource(
|
||||
GetCredentialName(), {}, options.IdentityId.GetId(), {}, options);
|
||||
GetCredentialName(),
|
||||
{},
|
||||
options.IdentityId.GetId(),
|
||||
{},
|
||||
options.UseProbeRequest,
|
||||
options);
|
||||
break;
|
||||
case ManagedIdentityIdKind::ResourceId:
|
||||
m_managedIdentitySource = CreateManagedIdentitySource(
|
||||
GetCredentialName(), {}, {}, options.IdentityId.GetId(), options);
|
||||
GetCredentialName(),
|
||||
{},
|
||||
{},
|
||||
options.IdentityId.GetId(),
|
||||
options.UseProbeRequest,
|
||||
options);
|
||||
break;
|
||||
default:
|
||||
throw std::invalid_argument(
|
||||
@ -88,7 +114,7 @@ ManagedIdentityCredential::ManagedIdentityCredential(
|
||||
|
||||
ManagedIdentityCredential::ManagedIdentityCredential(
|
||||
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
||||
: ManagedIdentityCredential(std::string(), options)
|
||||
: ManagedIdentityCredential({}, false, options)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@ -263,8 +263,10 @@ std::unique_ptr<ManagedIdentitySource> AppServiceV2017ManagedIdentitySource::Cre
|
||||
std::string const& clientId,
|
||||
std::string const& objectId,
|
||||
std::string const& resourceId,
|
||||
bool useProbeRequest,
|
||||
Core::Credentials::TokenCredentialOptions const& options)
|
||||
{
|
||||
static_cast<void>(useProbeRequest);
|
||||
return AppServiceManagedIdentitySource::Create<AppServiceV2017ManagedIdentitySource>(
|
||||
credName, clientId, objectId, resourceId, options, "MSI_ENDPOINT", "MSI_SECRET", "2017");
|
||||
}
|
||||
@ -274,8 +276,10 @@ std::unique_ptr<ManagedIdentitySource> AppServiceV2019ManagedIdentitySource::Cre
|
||||
std::string const& clientId,
|
||||
std::string const& objectId,
|
||||
std::string const& resourceId,
|
||||
bool useProbeRequest,
|
||||
Core::Credentials::TokenCredentialOptions const& options)
|
||||
{
|
||||
static_cast<void>(useProbeRequest);
|
||||
return AppServiceManagedIdentitySource::Create<AppServiceV2019ManagedIdentitySource>(
|
||||
credName,
|
||||
clientId,
|
||||
@ -292,8 +296,10 @@ std::unique_ptr<ManagedIdentitySource> CloudShellManagedIdentitySource::Create(
|
||||
std::string const& clientId,
|
||||
std::string const& objectId,
|
||||
std::string const& resourceId,
|
||||
bool useProbeRequest,
|
||||
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
||||
{
|
||||
static_cast<void>(useProbeRequest);
|
||||
using Azure::Core::Credentials::AuthenticationException;
|
||||
|
||||
constexpr auto EndpointVarName = "MSI_ENDPOINT";
|
||||
@ -370,8 +376,10 @@ std::unique_ptr<ManagedIdentitySource> AzureArcManagedIdentitySource::Create(
|
||||
std::string const& clientId,
|
||||
std::string const& objectId,
|
||||
std::string const& resourceId,
|
||||
bool useProbeRequest,
|
||||
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
||||
{
|
||||
static_cast<void>(useProbeRequest);
|
||||
using Azure::Core::Credentials::AuthenticationException;
|
||||
|
||||
constexpr auto EndpointVarName = "IDENTITY_ENDPOINT";
|
||||
@ -499,6 +507,7 @@ std::unique_ptr<ManagedIdentitySource> ImdsManagedIdentitySource::Create(
|
||||
std::string const& clientId,
|
||||
std::string const& objectId,
|
||||
std::string const& resourceId,
|
||||
bool useProbeRequest,
|
||||
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
||||
{
|
||||
const std::string ImdsName = "Azure Instance Metadata Service";
|
||||
@ -529,8 +538,8 @@ std::unique_ptr<ManagedIdentitySource> ImdsManagedIdentitySource::Create(
|
||||
}
|
||||
imdsUrl.SetPath("metadata/identity/oauth2/token");
|
||||
|
||||
return std::unique_ptr<ManagedIdentitySource>(
|
||||
new ImdsManagedIdentitySource(clientId, objectId, resourceId, imdsUrl, options));
|
||||
return std::unique_ptr<ManagedIdentitySource>(new ImdsManagedIdentitySource(
|
||||
clientId, objectId, resourceId, imdsUrl, useProbeRequest, options));
|
||||
}
|
||||
|
||||
ImdsManagedIdentitySource::ImdsManagedIdentitySource(
|
||||
@ -538,6 +547,7 @@ ImdsManagedIdentitySource::ImdsManagedIdentitySource(
|
||||
std::string const& objectId,
|
||||
std::string const& resourceId,
|
||||
Azure::Core::Url const& imdsUrl,
|
||||
bool useProbeRequest,
|
||||
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
||||
: ManagedIdentitySource(clientId, std::string(), options),
|
||||
m_request(Azure::Core::Http::HttpMethod::Get, imdsUrl)
|
||||
@ -569,7 +579,7 @@ ImdsManagedIdentitySource::ImdsManagedIdentitySource(
|
||||
Core::Credentials::TokenCredentialOptions firstRequestOptions = options;
|
||||
firstRequestOptions.Retry.MaxRetries = 0;
|
||||
m_firstRequestPipeline = std::make_unique<TokenCredentialImpl>(firstRequestOptions);
|
||||
m_firstRequestSucceeded = false;
|
||||
m_firstRequestSucceeded = !useProbeRequest;
|
||||
}
|
||||
|
||||
Azure::Core::Credentials::AccessToken ImdsManagedIdentitySource::GetToken(
|
||||
|
||||
@ -113,6 +113,7 @@ namespace Azure { namespace Identity { namespace _detail {
|
||||
std::string const& clientId,
|
||||
std::string const& objectId,
|
||||
std::string const& resourceId,
|
||||
bool useProbeRequest,
|
||||
Core::Credentials::TokenCredentialOptions const& options);
|
||||
};
|
||||
|
||||
@ -146,6 +147,7 @@ namespace Azure { namespace Identity { namespace _detail {
|
||||
std::string const& clientId,
|
||||
std::string const& objectId,
|
||||
std::string const& resourceId,
|
||||
bool useProbeRequest,
|
||||
Core::Credentials::TokenCredentialOptions const& options);
|
||||
};
|
||||
|
||||
@ -164,6 +166,7 @@ namespace Azure { namespace Identity { namespace _detail {
|
||||
std::string const& clientId,
|
||||
std::string const& objectId,
|
||||
std::string const& resourceId,
|
||||
bool useProbeRequest,
|
||||
Core::Credentials::TokenCredentialOptions const& options);
|
||||
|
||||
Core::Credentials::AccessToken GetToken(
|
||||
@ -185,6 +188,7 @@ namespace Azure { namespace Identity { namespace _detail {
|
||||
std::string const& clientId,
|
||||
std::string const& objectId,
|
||||
std::string const& resourceId,
|
||||
bool useProbeRequest,
|
||||
Core::Credentials::TokenCredentialOptions const& options);
|
||||
|
||||
Core::Credentials::AccessToken GetToken(
|
||||
@ -204,6 +208,7 @@ namespace Azure { namespace Identity { namespace _detail {
|
||||
std::string const& objectId,
|
||||
std::string const& resourceId,
|
||||
Core::Url const& imdsUrl,
|
||||
bool useProbeRequest,
|
||||
Core::Credentials::TokenCredentialOptions const& options);
|
||||
|
||||
public:
|
||||
@ -212,6 +217,7 @@ namespace Azure { namespace Identity { namespace _detail {
|
||||
std::string const& clientId,
|
||||
std::string const& objectId,
|
||||
std::string const& resourceId,
|
||||
bool useProbeRequest,
|
||||
Core::Credentials::TokenCredentialOptions const& options);
|
||||
|
||||
Core::Credentials::AccessToken GetToken(
|
||||
|
||||
@ -528,3 +528,96 @@ TEST(DefaultAzureCredential, RequireCredentialSpecifierEnvVarValue)
|
||||
EXPECT_THROW(
|
||||
static_cast<void>(std::make_unique<DefaultAzureCredential>(true)), AuthenticationException);
|
||||
}
|
||||
|
||||
TEST(DefaultAzureCredential, ImdsProbe)
|
||||
{
|
||||
using Azure::Core::Http::HttpStatusCode;
|
||||
using Azure::Identity::Test::_detail::CredentialTestHelper;
|
||||
|
||||
constexpr auto ImATeapot = static_cast<HttpStatusCode>(418);
|
||||
|
||||
// AZURE_TOKEN_CREDENTIALS is set to "prod", which should result in ManagedIdentityCredential
|
||||
// using useProbeRequest = true.
|
||||
EXPECT_THROW(
|
||||
static_cast<void>(CredentialTestHelper::SimulateTokenRequest(
|
||||
[&ImATeapot](auto transport) {
|
||||
TokenCredentialOptions options;
|
||||
options.Transport.Transport = transport;
|
||||
|
||||
options.Retry.MaxRetries = 3;
|
||||
options.Retry.RetryDelay = std::chrono::milliseconds(1);
|
||||
options.Retry.StatusCodes.insert(ImATeapot);
|
||||
|
||||
CredentialTestHelper::EnvironmentOverride const env({
|
||||
// Env vars are set to ensure that all the credential chain is inactive all the way
|
||||
// up to ManagedIdentityCredential with IMDS source.
|
||||
{"MSI_ENDPOINT", ""},
|
||||
{"MSI_SECRET", ""},
|
||||
{"IDENTITY_ENDPOINT", "https://visualstudio.com/"},
|
||||
{"IMDS_ENDPOINT", ""},
|
||||
{"IDENTITY_HEADER", ""},
|
||||
{"IDENTITY_SERVER_THUMBPRINT", ""},
|
||||
{"AZURE_POD_IDENTITY_AUTHORITY_HOST", ""},
|
||||
{"AZURE_AUTHORITY_HOST", ""},
|
||||
{"AZURE_TENANT_ID", ""},
|
||||
{"AZURE_CLIENT_ID", ""},
|
||||
{"AZURE_CLIENT_SECRET", ""},
|
||||
{"AZURE_CLIENT_CERTIFICATE_PATH", ""},
|
||||
{"AZURE_FEDERATED_TOKEN_FILE", ""},
|
||||
{"SYSTEM_OIDCREQUESTURI", ""},
|
||||
{"AZURE_TOKEN_CREDENTIALS",
|
||||
"prod"}, // <- should result in MIC with useProbeRequest = true
|
||||
});
|
||||
|
||||
return std::make_unique<DefaultAzureCredential>(options);
|
||||
},
|
||||
{{"https://azure.com/.default"}},
|
||||
{{ImATeapot, "{\"expires_in\":3600, \"access_token\":\"ACCESSTOKEN1\"}", {}},
|
||||
// Given there aren't going to be any retries due to probe request, the credential
|
||||
// should never get to make a second request to receive the successful response below.
|
||||
{HttpStatusCode::Ok, "{\"expires_in\":3600, \"access_token\":\"ACCESSTOKEN2\"}", {}}})),
|
||||
Azure::Core::Credentials::AuthenticationException);
|
||||
|
||||
// Everything is the same, including the retry policy, but this time AZURE_TOKEN_CREDENTIALS is
|
||||
// set to "ManagedIdentityCredential", which should result in ManagedIdentityCredential using
|
||||
// useProbeRequest = false.
|
||||
auto const whenProbeDisabled = CredentialTestHelper::SimulateTokenRequest(
|
||||
[&ImATeapot](auto transport) {
|
||||
TokenCredentialOptions options;
|
||||
options.Transport.Transport = transport;
|
||||
|
||||
options.Retry.MaxRetries = 3;
|
||||
options.Retry.RetryDelay = std::chrono::milliseconds(1);
|
||||
options.Retry.StatusCodes.insert(ImATeapot);
|
||||
|
||||
CredentialTestHelper::EnvironmentOverride const env({
|
||||
// Env vars are set to ensure that all the credential chain is inactive all the way
|
||||
// up to ManagedIdentityCredential with IMDS source.
|
||||
{"MSI_ENDPOINT", ""},
|
||||
{"MSI_SECRET", ""},
|
||||
{"IDENTITY_ENDPOINT", "https://visualstudio.com/"},
|
||||
{"IMDS_ENDPOINT", ""},
|
||||
{"IDENTITY_HEADER", ""},
|
||||
{"IDENTITY_SERVER_THUMBPRINT", ""},
|
||||
{"AZURE_POD_IDENTITY_AUTHORITY_HOST", ""},
|
||||
{"AZURE_AUTHORITY_HOST", ""},
|
||||
{"AZURE_TENANT_ID", ""},
|
||||
{"AZURE_CLIENT_ID", ""},
|
||||
{"AZURE_CLIENT_SECRET", ""},
|
||||
{"AZURE_CLIENT_CERTIFICATE_PATH", ""},
|
||||
{"AZURE_FEDERATED_TOKEN_FILE", ""},
|
||||
{"SYSTEM_OIDCREQUESTURI", ""},
|
||||
{"AZURE_TOKEN_CREDENTIALS",
|
||||
"ManagedIdentityCredential"}, // <- should result in MIC with useProbeRequest = false
|
||||
});
|
||||
|
||||
return std::make_unique<DefaultAzureCredential>(options);
|
||||
},
|
||||
{{"https://azure.com/.default"}},
|
||||
{{ImATeapot, "{\"expires_in\":3600, \"access_token\":\"ACCESSTOKEN1\"}", {}},
|
||||
{HttpStatusCode::Ok, "{\"expires_in\":3600, \"access_token\":\"ACCESSTOKEN2\"}", {}}});
|
||||
|
||||
EXPECT_EQ(whenProbeDisabled.Requests.size(), 2U);
|
||||
EXPECT_EQ(whenProbeDisabled.Responses.size(), 1U);
|
||||
EXPECT_EQ(whenProbeDisabled.Responses.at(0).AccessToken.Token, "ACCESSTOKEN2");
|
||||
}
|
||||
|
||||
@ -3193,4 +3193,72 @@ namespace Azure { namespace Identity { namespace Test {
|
||||
Logger::SetListener(nullptr);
|
||||
}
|
||||
|
||||
TEST(ManagedIdentityCredential, ImdsProbe)
|
||||
{
|
||||
constexpr auto ImATeapot = static_cast<HttpStatusCode>(418);
|
||||
|
||||
EXPECT_THROW(
|
||||
static_cast<void>(CredentialTestHelper::SimulateTokenRequest(
|
||||
[&ImATeapot](auto transport) {
|
||||
ManagedIdentityCredentialOptions options;
|
||||
options.Transport.Transport = transport;
|
||||
|
||||
options.Retry.MaxRetries = 3;
|
||||
options.Retry.RetryDelay = std::chrono::milliseconds(1);
|
||||
options.Retry.StatusCodes.insert(ImATeapot);
|
||||
|
||||
CredentialTestHelper::EnvironmentOverride const env({
|
||||
{"MSI_ENDPOINT", ""},
|
||||
{"MSI_SECRET", ""},
|
||||
{"IDENTITY_ENDPOINT", "https://visualstudio.com/"},
|
||||
{"IMDS_ENDPOINT", ""},
|
||||
{"IDENTITY_HEADER", ""},
|
||||
{"IDENTITY_SERVER_THUMBPRINT", ""},
|
||||
{"AZURE_POD_IDENTITY_AUTHORITY_HOST", ""},
|
||||
});
|
||||
|
||||
options.UseProbeRequest = true;
|
||||
return std::make_unique<ManagedIdentityCredential>(options);
|
||||
},
|
||||
{{"https://azure.com/.default"}},
|
||||
{{ImATeapot, "{\"expires_in\":3600, \"access_token\":\"ACCESSTOKEN1\"}", {}},
|
||||
// Given there aren't going to be any retries due to probe request, the credential
|
||||
// should never get to make a second request to receive the successful response below.
|
||||
{HttpStatusCode::Ok,
|
||||
"{\"expires_in\":3600, \"access_token\":\"ACCESSTOKEN2\"}",
|
||||
{}}})),
|
||||
Azure::Core::Credentials::AuthenticationException);
|
||||
|
||||
// Everything is the same, including the retry policy, but this time useProbeRequest = false.
|
||||
auto const whenProbeDisabled = CredentialTestHelper::SimulateTokenRequest(
|
||||
[&ImATeapot](auto transport) {
|
||||
TokenCredentialOptions options;
|
||||
options.Transport.Transport = transport;
|
||||
|
||||
options.Retry.MaxRetries = 3;
|
||||
options.Retry.RetryDelay = std::chrono::milliseconds(1);
|
||||
options.Retry.StatusCodes.insert(ImATeapot);
|
||||
|
||||
CredentialTestHelper::EnvironmentOverride const env({
|
||||
{"MSI_ENDPOINT", ""},
|
||||
{"MSI_SECRET", ""},
|
||||
{"IDENTITY_ENDPOINT", "https://visualstudio.com/"},
|
||||
{"IMDS_ENDPOINT", ""},
|
||||
{"IDENTITY_HEADER", ""},
|
||||
{"IDENTITY_SERVER_THUMBPRINT", ""},
|
||||
{"AZURE_POD_IDENTITY_AUTHORITY_HOST", ""},
|
||||
});
|
||||
|
||||
return std::make_unique<ManagedIdentityCredential>(
|
||||
options); // <-- useProbeRequest = false (default)
|
||||
},
|
||||
{{"https://azure.com/.default"}},
|
||||
{{ImATeapot, "{\"expires_in\":3600, \"access_token\":\"ACCESSTOKEN1\"}", {}},
|
||||
{HttpStatusCode::Ok, "{\"expires_in\":3600, \"access_token\":\"ACCESSTOKEN2\"}", {}}});
|
||||
|
||||
EXPECT_EQ(whenProbeDisabled.Requests.size(), 2U);
|
||||
EXPECT_EQ(whenProbeDisabled.Responses.size(), 1U);
|
||||
EXPECT_EQ(whenProbeDisabled.Responses.at(0).AccessToken.Token, "ACCESSTOKEN2");
|
||||
}
|
||||
|
||||
}}} // namespace Azure::Identity::Test
|
||||
|
||||
Loading…
Reference in New Issue
Block a user