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
|
### 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
|
### Breaking Changes
|
||||||
|
|
||||||
### Bugs Fixed
|
### Bugs Fixed
|
||||||
|
|||||||
@ -168,6 +168,18 @@ namespace Azure { namespace Identity {
|
|||||||
* it was configured.
|
* it was configured.
|
||||||
*/
|
*/
|
||||||
ManagedIdentityId IdentityId;
|
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:
|
private:
|
||||||
std::unique_ptr<_detail::ManagedIdentitySource> m_managedIdentitySource;
|
std::unique_ptr<_detail::ManagedIdentitySource> m_managedIdentitySource;
|
||||||
|
|
||||||
|
explicit ManagedIdentityCredential(
|
||||||
|
std::string const& clientId,
|
||||||
|
bool useProbeRequest,
|
||||||
|
Core::Credentials::TokenCredentialOptions const& options);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Destructs `%TokenCredential`.
|
* @brief Destructs `%TokenCredential`.
|
||||||
@ -196,8 +213,8 @@ namespace Azure { namespace Identity {
|
|||||||
*/
|
*/
|
||||||
explicit ManagedIdentityCredential(
|
explicit ManagedIdentityCredential(
|
||||||
std::string const& clientId = std::string(),
|
std::string const& clientId = std::string(),
|
||||||
Azure::Core::Credentials::TokenCredentialOptions const& options
|
Core::Credentials::TokenCredentialOptions const& options
|
||||||
= Azure::Core::Credentials::TokenCredentialOptions());
|
= Core::Credentials::TokenCredentialOptions());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Constructs a Managed Identity Credential.
|
* @brief Constructs a Managed Identity Credential.
|
||||||
@ -212,8 +229,7 @@ namespace Azure { namespace Identity {
|
|||||||
*
|
*
|
||||||
* @param options Options for token retrieval.
|
* @param options Options for token retrieval.
|
||||||
*/
|
*/
|
||||||
explicit ManagedIdentityCredential(
|
explicit ManagedIdentityCredential(Core::Credentials::TokenCredentialOptions const& options);
|
||||||
Azure::Core::Credentials::TokenCredentialOptions const& options);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets an authentication token.
|
* @brief Gets an authentication token.
|
||||||
|
|||||||
@ -69,25 +69,6 @@ DefaultAzureCredential::DefaultAzureCredential(
|
|||||||
Create;
|
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 envVarValue = Environment::GetVariable(CredentialSpecifierEnvVarName);
|
||||||
const auto trimmedEnvVarValue = StringExtensions::Trim(envVarValue);
|
const auto trimmedEnvVarValue = StringExtensions::Trim(envVarValue);
|
||||||
|
|
||||||
@ -99,6 +80,35 @@ DefaultAzureCredential::DefaultAzureCredential(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool specificCred = false;
|
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())
|
if (!trimmedEnvVarValue.empty())
|
||||||
{
|
{
|
||||||
for (const auto& cred : credentials)
|
for (const auto& cred : credentials)
|
||||||
|
|||||||
@ -14,6 +14,7 @@ std::unique_ptr<_detail::ManagedIdentitySource> CreateManagedIdentitySource(
|
|||||||
std::string const& clientId,
|
std::string const& clientId,
|
||||||
std::string const& objectId,
|
std::string const& objectId,
|
||||||
std::string const& resourceId,
|
std::string const& resourceId,
|
||||||
|
bool useProbeRequest,
|
||||||
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
||||||
{
|
{
|
||||||
using namespace Azure::Core::Credentials;
|
using namespace Azure::Core::Credentials;
|
||||||
@ -23,6 +24,7 @@ std::unique_ptr<_detail::ManagedIdentitySource> CreateManagedIdentitySource(
|
|||||||
std::string const& clientId,
|
std::string const& clientId,
|
||||||
std::string const& objectId,
|
std::string const& objectId,
|
||||||
std::string const& resourceId,
|
std::string const& resourceId,
|
||||||
|
bool useProbeRequest,
|
||||||
TokenCredentialOptions const& options)
|
TokenCredentialOptions const& options)
|
||||||
= {AppServiceV2019ManagedIdentitySource::Create,
|
= {AppServiceV2019ManagedIdentitySource::Create,
|
||||||
AppServiceV2017ManagedIdentitySource::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 that reason, it is not possible to cover that execution branch in tests.
|
||||||
for (auto create : managedIdentitySourceCreate)
|
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;
|
return source;
|
||||||
}
|
}
|
||||||
@ -49,11 +52,19 @@ ManagedIdentityCredential::~ManagedIdentityCredential() = default;
|
|||||||
|
|
||||||
ManagedIdentityCredential::ManagedIdentityCredential(
|
ManagedIdentityCredential::ManagedIdentityCredential(
|
||||||
std::string const& clientId,
|
std::string const& clientId,
|
||||||
|
bool useProbeRequest,
|
||||||
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
||||||
: TokenCredential("ManagedIdentityCredential")
|
: TokenCredential("ManagedIdentityCredential")
|
||||||
{
|
{
|
||||||
m_managedIdentitySource
|
m_managedIdentitySource = CreateManagedIdentitySource(
|
||||||
= CreateManagedIdentitySource(GetCredentialName(), clientId, {}, {}, options);
|
GetCredentialName(), clientId, {}, {}, useProbeRequest, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
ManagedIdentityCredential::ManagedIdentityCredential(
|
||||||
|
std::string const& clientId,
|
||||||
|
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
||||||
|
: ManagedIdentityCredential(clientId, false, options)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ManagedIdentityCredential::ManagedIdentityCredential(
|
ManagedIdentityCredential::ManagedIdentityCredential(
|
||||||
@ -64,20 +75,35 @@ ManagedIdentityCredential::ManagedIdentityCredential(
|
|||||||
switch (idType)
|
switch (idType)
|
||||||
{
|
{
|
||||||
case ManagedIdentityIdKind::SystemAssigned:
|
case ManagedIdentityIdKind::SystemAssigned:
|
||||||
m_managedIdentitySource
|
m_managedIdentitySource = CreateManagedIdentitySource(
|
||||||
= CreateManagedIdentitySource(GetCredentialName(), {}, {}, {}, options);
|
GetCredentialName(), {}, {}, {}, options.UseProbeRequest, options);
|
||||||
break;
|
break;
|
||||||
case ManagedIdentityIdKind::ClientId:
|
case ManagedIdentityIdKind::ClientId:
|
||||||
m_managedIdentitySource = CreateManagedIdentitySource(
|
m_managedIdentitySource = CreateManagedIdentitySource(
|
||||||
GetCredentialName(), options.IdentityId.GetId(), {}, {}, options);
|
GetCredentialName(),
|
||||||
|
options.IdentityId.GetId(),
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
options.UseProbeRequest,
|
||||||
|
options);
|
||||||
break;
|
break;
|
||||||
case ManagedIdentityIdKind::ObjectId:
|
case ManagedIdentityIdKind::ObjectId:
|
||||||
m_managedIdentitySource = CreateManagedIdentitySource(
|
m_managedIdentitySource = CreateManagedIdentitySource(
|
||||||
GetCredentialName(), {}, options.IdentityId.GetId(), {}, options);
|
GetCredentialName(),
|
||||||
|
{},
|
||||||
|
options.IdentityId.GetId(),
|
||||||
|
{},
|
||||||
|
options.UseProbeRequest,
|
||||||
|
options);
|
||||||
break;
|
break;
|
||||||
case ManagedIdentityIdKind::ResourceId:
|
case ManagedIdentityIdKind::ResourceId:
|
||||||
m_managedIdentitySource = CreateManagedIdentitySource(
|
m_managedIdentitySource = CreateManagedIdentitySource(
|
||||||
GetCredentialName(), {}, {}, options.IdentityId.GetId(), options);
|
GetCredentialName(),
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
options.IdentityId.GetId(),
|
||||||
|
options.UseProbeRequest,
|
||||||
|
options);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw std::invalid_argument(
|
throw std::invalid_argument(
|
||||||
@ -88,7 +114,7 @@ ManagedIdentityCredential::ManagedIdentityCredential(
|
|||||||
|
|
||||||
ManagedIdentityCredential::ManagedIdentityCredential(
|
ManagedIdentityCredential::ManagedIdentityCredential(
|
||||||
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
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& clientId,
|
||||||
std::string const& objectId,
|
std::string const& objectId,
|
||||||
std::string const& resourceId,
|
std::string const& resourceId,
|
||||||
|
bool useProbeRequest,
|
||||||
Core::Credentials::TokenCredentialOptions const& options)
|
Core::Credentials::TokenCredentialOptions const& options)
|
||||||
{
|
{
|
||||||
|
static_cast<void>(useProbeRequest);
|
||||||
return AppServiceManagedIdentitySource::Create<AppServiceV2017ManagedIdentitySource>(
|
return AppServiceManagedIdentitySource::Create<AppServiceV2017ManagedIdentitySource>(
|
||||||
credName, clientId, objectId, resourceId, options, "MSI_ENDPOINT", "MSI_SECRET", "2017");
|
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& clientId,
|
||||||
std::string const& objectId,
|
std::string const& objectId,
|
||||||
std::string const& resourceId,
|
std::string const& resourceId,
|
||||||
|
bool useProbeRequest,
|
||||||
Core::Credentials::TokenCredentialOptions const& options)
|
Core::Credentials::TokenCredentialOptions const& options)
|
||||||
{
|
{
|
||||||
|
static_cast<void>(useProbeRequest);
|
||||||
return AppServiceManagedIdentitySource::Create<AppServiceV2019ManagedIdentitySource>(
|
return AppServiceManagedIdentitySource::Create<AppServiceV2019ManagedIdentitySource>(
|
||||||
credName,
|
credName,
|
||||||
clientId,
|
clientId,
|
||||||
@ -292,8 +296,10 @@ std::unique_ptr<ManagedIdentitySource> CloudShellManagedIdentitySource::Create(
|
|||||||
std::string const& clientId,
|
std::string const& clientId,
|
||||||
std::string const& objectId,
|
std::string const& objectId,
|
||||||
std::string const& resourceId,
|
std::string const& resourceId,
|
||||||
|
bool useProbeRequest,
|
||||||
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
||||||
{
|
{
|
||||||
|
static_cast<void>(useProbeRequest);
|
||||||
using Azure::Core::Credentials::AuthenticationException;
|
using Azure::Core::Credentials::AuthenticationException;
|
||||||
|
|
||||||
constexpr auto EndpointVarName = "MSI_ENDPOINT";
|
constexpr auto EndpointVarName = "MSI_ENDPOINT";
|
||||||
@ -370,8 +376,10 @@ std::unique_ptr<ManagedIdentitySource> AzureArcManagedIdentitySource::Create(
|
|||||||
std::string const& clientId,
|
std::string const& clientId,
|
||||||
std::string const& objectId,
|
std::string const& objectId,
|
||||||
std::string const& resourceId,
|
std::string const& resourceId,
|
||||||
|
bool useProbeRequest,
|
||||||
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
||||||
{
|
{
|
||||||
|
static_cast<void>(useProbeRequest);
|
||||||
using Azure::Core::Credentials::AuthenticationException;
|
using Azure::Core::Credentials::AuthenticationException;
|
||||||
|
|
||||||
constexpr auto EndpointVarName = "IDENTITY_ENDPOINT";
|
constexpr auto EndpointVarName = "IDENTITY_ENDPOINT";
|
||||||
@ -499,6 +507,7 @@ std::unique_ptr<ManagedIdentitySource> ImdsManagedIdentitySource::Create(
|
|||||||
std::string const& clientId,
|
std::string const& clientId,
|
||||||
std::string const& objectId,
|
std::string const& objectId,
|
||||||
std::string const& resourceId,
|
std::string const& resourceId,
|
||||||
|
bool useProbeRequest,
|
||||||
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
||||||
{
|
{
|
||||||
const std::string ImdsName = "Azure Instance Metadata Service";
|
const std::string ImdsName = "Azure Instance Metadata Service";
|
||||||
@ -529,8 +538,8 @@ std::unique_ptr<ManagedIdentitySource> ImdsManagedIdentitySource::Create(
|
|||||||
}
|
}
|
||||||
imdsUrl.SetPath("metadata/identity/oauth2/token");
|
imdsUrl.SetPath("metadata/identity/oauth2/token");
|
||||||
|
|
||||||
return std::unique_ptr<ManagedIdentitySource>(
|
return std::unique_ptr<ManagedIdentitySource>(new ImdsManagedIdentitySource(
|
||||||
new ImdsManagedIdentitySource(clientId, objectId, resourceId, imdsUrl, options));
|
clientId, objectId, resourceId, imdsUrl, useProbeRequest, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImdsManagedIdentitySource::ImdsManagedIdentitySource(
|
ImdsManagedIdentitySource::ImdsManagedIdentitySource(
|
||||||
@ -538,6 +547,7 @@ ImdsManagedIdentitySource::ImdsManagedIdentitySource(
|
|||||||
std::string const& objectId,
|
std::string const& objectId,
|
||||||
std::string const& resourceId,
|
std::string const& resourceId,
|
||||||
Azure::Core::Url const& imdsUrl,
|
Azure::Core::Url const& imdsUrl,
|
||||||
|
bool useProbeRequest,
|
||||||
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
Azure::Core::Credentials::TokenCredentialOptions const& options)
|
||||||
: ManagedIdentitySource(clientId, std::string(), options),
|
: ManagedIdentitySource(clientId, std::string(), options),
|
||||||
m_request(Azure::Core::Http::HttpMethod::Get, imdsUrl)
|
m_request(Azure::Core::Http::HttpMethod::Get, imdsUrl)
|
||||||
@ -569,7 +579,7 @@ ImdsManagedIdentitySource::ImdsManagedIdentitySource(
|
|||||||
Core::Credentials::TokenCredentialOptions firstRequestOptions = options;
|
Core::Credentials::TokenCredentialOptions firstRequestOptions = options;
|
||||||
firstRequestOptions.Retry.MaxRetries = 0;
|
firstRequestOptions.Retry.MaxRetries = 0;
|
||||||
m_firstRequestPipeline = std::make_unique<TokenCredentialImpl>(firstRequestOptions);
|
m_firstRequestPipeline = std::make_unique<TokenCredentialImpl>(firstRequestOptions);
|
||||||
m_firstRequestSucceeded = false;
|
m_firstRequestSucceeded = !useProbeRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
Azure::Core::Credentials::AccessToken ImdsManagedIdentitySource::GetToken(
|
Azure::Core::Credentials::AccessToken ImdsManagedIdentitySource::GetToken(
|
||||||
|
|||||||
@ -113,6 +113,7 @@ namespace Azure { namespace Identity { namespace _detail {
|
|||||||
std::string const& clientId,
|
std::string const& clientId,
|
||||||
std::string const& objectId,
|
std::string const& objectId,
|
||||||
std::string const& resourceId,
|
std::string const& resourceId,
|
||||||
|
bool useProbeRequest,
|
||||||
Core::Credentials::TokenCredentialOptions const& options);
|
Core::Credentials::TokenCredentialOptions const& options);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -146,6 +147,7 @@ namespace Azure { namespace Identity { namespace _detail {
|
|||||||
std::string const& clientId,
|
std::string const& clientId,
|
||||||
std::string const& objectId,
|
std::string const& objectId,
|
||||||
std::string const& resourceId,
|
std::string const& resourceId,
|
||||||
|
bool useProbeRequest,
|
||||||
Core::Credentials::TokenCredentialOptions const& options);
|
Core::Credentials::TokenCredentialOptions const& options);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -164,6 +166,7 @@ namespace Azure { namespace Identity { namespace _detail {
|
|||||||
std::string const& clientId,
|
std::string const& clientId,
|
||||||
std::string const& objectId,
|
std::string const& objectId,
|
||||||
std::string const& resourceId,
|
std::string const& resourceId,
|
||||||
|
bool useProbeRequest,
|
||||||
Core::Credentials::TokenCredentialOptions const& options);
|
Core::Credentials::TokenCredentialOptions const& options);
|
||||||
|
|
||||||
Core::Credentials::AccessToken GetToken(
|
Core::Credentials::AccessToken GetToken(
|
||||||
@ -185,6 +188,7 @@ namespace Azure { namespace Identity { namespace _detail {
|
|||||||
std::string const& clientId,
|
std::string const& clientId,
|
||||||
std::string const& objectId,
|
std::string const& objectId,
|
||||||
std::string const& resourceId,
|
std::string const& resourceId,
|
||||||
|
bool useProbeRequest,
|
||||||
Core::Credentials::TokenCredentialOptions const& options);
|
Core::Credentials::TokenCredentialOptions const& options);
|
||||||
|
|
||||||
Core::Credentials::AccessToken GetToken(
|
Core::Credentials::AccessToken GetToken(
|
||||||
@ -204,6 +208,7 @@ namespace Azure { namespace Identity { namespace _detail {
|
|||||||
std::string const& objectId,
|
std::string const& objectId,
|
||||||
std::string const& resourceId,
|
std::string const& resourceId,
|
||||||
Core::Url const& imdsUrl,
|
Core::Url const& imdsUrl,
|
||||||
|
bool useProbeRequest,
|
||||||
Core::Credentials::TokenCredentialOptions const& options);
|
Core::Credentials::TokenCredentialOptions const& options);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -212,6 +217,7 @@ namespace Azure { namespace Identity { namespace _detail {
|
|||||||
std::string const& clientId,
|
std::string const& clientId,
|
||||||
std::string const& objectId,
|
std::string const& objectId,
|
||||||
std::string const& resourceId,
|
std::string const& resourceId,
|
||||||
|
bool useProbeRequest,
|
||||||
Core::Credentials::TokenCredentialOptions const& options);
|
Core::Credentials::TokenCredentialOptions const& options);
|
||||||
|
|
||||||
Core::Credentials::AccessToken GetToken(
|
Core::Credentials::AccessToken GetToken(
|
||||||
|
|||||||
@ -528,3 +528,96 @@ TEST(DefaultAzureCredential, RequireCredentialSpecifierEnvVarValue)
|
|||||||
EXPECT_THROW(
|
EXPECT_THROW(
|
||||||
static_cast<void>(std::make_unique<DefaultAzureCredential>(true)), AuthenticationException);
|
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);
|
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
|
}}} // namespace Azure::Identity::Test
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user