Add live tests for AzurePipelinesCredential. (#5734)
* Add AzurePipelinesCredential for authenticating an Azure Pipelines service connection with workload identity federation. * Add unit tests. * Add comment about not throwing in the ctor, but rather deferring it. * Order field in order of initialization and fix cspell. * Fix ambiguous call to EnvironmentOverride in tests. * Add a live test to AzurePipelinesCredential. * Add invalid test cases and output response. * Add access token env var in ci.yml. * Add identity yml files and EnvVars. * Fix merge conflicts and print out the oidc response. * Remove duplicate definition of ServiceDirectory and remove env. * Revert CI/infra changes. * Include engsys changes to add federated auth support. * Update environment variables used. * Sync recent engsys changes. * Add invalid tenant id test and re-order them. * Fail the live test pipeline if a test fails. * Update tests and revert source changes. * Debug failing TokenCredentialTest in new live test environment. * Dont fail test on missing env var. * Disable federated auth in ci.yml and add back client secret env var. * Remove test application secret. * Revert other changes related to infra.
This commit is contained in:
Родитель
e488093c19
Коммит
3e5b7064ec
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using Azure::Core::_internal::Environment;
|
||||
using Azure::Core::Credentials::AccessToken;
|
||||
using Azure::Core::Credentials::AuthenticationException;
|
||||
using Azure::Core::Credentials::TokenRequestContext;
|
||||
using Azure::Core::Http::HttpMethod;
|
||||
|
@ -492,3 +494,185 @@ TEST(AzurePipelinesCredential, InvalidOidcResponse)
|
|||
std::vector<std::string>{"{\"oidcToken\":5}", ""}),
|
||||
AuthenticationException);
|
||||
}
|
||||
|
||||
constexpr auto TenantIdEnvVar = "AZURESUBSCRIPTION_TENANT_ID";
|
||||
constexpr auto ClientIdEnvVar = "AZURESUBSCRIPTION_CLIENT_ID";
|
||||
constexpr auto ServiceConnectionIdEnvVar = "AZURESUBSCRIPTION_SERVICE_CONNECTION_ID";
|
||||
constexpr auto SystemAccessTokenEnv = "SYSTEM_ACCESSTOKEN";
|
||||
|
||||
static std::string GetSkipTestMessage(
|
||||
std::string tenantId,
|
||||
std::string clientId,
|
||||
std::string serviceConnectionId,
|
||||
std::string systemAccessToken)
|
||||
{
|
||||
std::string message = "Set " + std::string(TenantIdEnvVar) + ", " + ClientIdEnvVar + ", "
|
||||
+ ServiceConnectionIdEnvVar + ", and " + SystemAccessTokenEnv
|
||||
+ " to run this AzurePipelinesCredential test. Tenant ID - '" + tenantId + "', Client ID - '"
|
||||
+ clientId + "', Service Connection ID - '" + serviceConnectionId
|
||||
+ "', and System Access Token size : " + std::to_string(systemAccessToken.size()) + ".";
|
||||
return message;
|
||||
}
|
||||
|
||||
TEST(AzurePipelinesCredential, RegularLive_LIVEONLY_)
|
||||
{
|
||||
std::string tenantId = Environment::GetVariable("AZURESUBSCRIPTION_TENANT_ID");
|
||||
std::string clientId = Environment::GetVariable("AZURESUBSCRIPTION_CLIENT_ID");
|
||||
std::string serviceConnectionId
|
||||
= Environment::GetVariable("AZURESUBSCRIPTION_SERVICE_CONNECTION_ID");
|
||||
std::string systemAccessToken = Environment::GetVariable("SYSTEM_ACCESSTOKEN");
|
||||
|
||||
if (tenantId.empty() || clientId.empty() || serviceConnectionId.empty()
|
||||
|| systemAccessToken.empty())
|
||||
{
|
||||
std::string message
|
||||
= GetSkipTestMessage(tenantId, clientId, serviceConnectionId, systemAccessToken);
|
||||
GTEST_SKIP_(message.c_str());
|
||||
}
|
||||
|
||||
AzurePipelinesCredential const cred(tenantId, clientId, serviceConnectionId, systemAccessToken);
|
||||
|
||||
TokenRequestContext trc;
|
||||
trc.Scopes.push_back("https://vault.azure.net/.default");
|
||||
|
||||
AccessToken token = cred.GetToken(trc, {});
|
||||
EXPECT_NE(token.Token, "") << "GetToken returned an invalid token.";
|
||||
|
||||
EXPECT_TRUE(token.ExpiresOn >= std::chrono::system_clock::now())
|
||||
<< "GetToken returned an invalid expiration time.";
|
||||
|
||||
AccessToken token2 = cred.GetToken(trc, {});
|
||||
EXPECT_TRUE(token.Token == token2.Token && token.ExpiresOn == token2.ExpiresOn)
|
||||
<< "Expected a cached token.";
|
||||
}
|
||||
|
||||
TEST(AzurePipelinesCredential, InvalidTenantId_LIVEONLY_)
|
||||
{
|
||||
std::string clientId = Environment::GetVariable("AZURESUBSCRIPTION_CLIENT_ID");
|
||||
std::string serviceConnectionId
|
||||
= Environment::GetVariable("AZURESUBSCRIPTION_SERVICE_CONNECTION_ID");
|
||||
std::string systemAccessToken = Environment::GetVariable("SYSTEM_ACCESSTOKEN");
|
||||
|
||||
const std::string tenantId = "invalidtenantId";
|
||||
|
||||
if (clientId.empty() || serviceConnectionId.empty() || systemAccessToken.empty())
|
||||
{
|
||||
std::string message
|
||||
= GetSkipTestMessage(tenantId, clientId, serviceConnectionId, systemAccessToken);
|
||||
GTEST_SKIP_(message.c_str());
|
||||
}
|
||||
|
||||
AzurePipelinesCredential const cred(tenantId, clientId, serviceConnectionId, systemAccessToken);
|
||||
|
||||
TokenRequestContext trc;
|
||||
trc.Scopes.push_back("https://vault.azure.net/.default");
|
||||
|
||||
try
|
||||
{
|
||||
AccessToken token = cred.GetToken(trc, {});
|
||||
GTEST_FAIL() << "GetToken should have thrown an exception due to an invalid tenant ID.";
|
||||
}
|
||||
catch (AuthenticationException const& ex)
|
||||
{
|
||||
EXPECT_TRUE(std::string(ex.what()).find("400 Bad Request") != std::string::npos) << ex.what();
|
||||
EXPECT_TRUE(std::string(ex.what()).find("AADSTS900023") != std::string::npos) << ex.what();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AzurePipelinesCredential, InvalidClientId_LIVEONLY_)
|
||||
{
|
||||
std::string tenantId = Environment::GetVariable("AZURESUBSCRIPTION_TENANT_ID");
|
||||
std::string serviceConnectionId
|
||||
= Environment::GetVariable("AZURESUBSCRIPTION_SERVICE_CONNECTION_ID");
|
||||
std::string systemAccessToken = Environment::GetVariable("SYSTEM_ACCESSTOKEN");
|
||||
|
||||
const std::string clientId = "invalidClientId";
|
||||
|
||||
if (tenantId.empty() || serviceConnectionId.empty() || systemAccessToken.empty())
|
||||
{
|
||||
std::string message
|
||||
= GetSkipTestMessage(tenantId, clientId, serviceConnectionId, systemAccessToken);
|
||||
GTEST_SKIP_(message.c_str());
|
||||
}
|
||||
|
||||
AzurePipelinesCredential const cred(tenantId, clientId, serviceConnectionId, systemAccessToken);
|
||||
|
||||
TokenRequestContext trc;
|
||||
trc.Scopes.push_back("https://vault.azure.net/.default");
|
||||
|
||||
try
|
||||
{
|
||||
AccessToken token = cred.GetToken(trc, {});
|
||||
GTEST_FAIL() << "GetToken should have thrown an exception due to an invalid client ID.";
|
||||
}
|
||||
catch (AuthenticationException const& ex)
|
||||
{
|
||||
EXPECT_TRUE(std::string(ex.what()).find("400 Bad Request") != std::string::npos) << ex.what();
|
||||
EXPECT_TRUE(std::string(ex.what()).find("AADSTS700016") != std::string::npos) << ex.what();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AzurePipelinesCredential, InvalidServiceConnectionId_LIVEONLY_)
|
||||
{
|
||||
std::string tenantId = Environment::GetVariable("AZURESUBSCRIPTION_TENANT_ID");
|
||||
std::string clientId = Environment::GetVariable("AZURESUBSCRIPTION_CLIENT_ID");
|
||||
std::string systemAccessToken = Environment::GetVariable("SYSTEM_ACCESSTOKEN");
|
||||
|
||||
const std::string serviceConnectionId = "invalidServiceConnectionId";
|
||||
|
||||
if (tenantId.empty() || clientId.empty() || systemAccessToken.empty())
|
||||
{
|
||||
std::string message
|
||||
= GetSkipTestMessage(tenantId, clientId, serviceConnectionId, systemAccessToken);
|
||||
GTEST_SKIP_(message.c_str());
|
||||
}
|
||||
|
||||
AzurePipelinesCredential const cred(tenantId, clientId, serviceConnectionId, systemAccessToken);
|
||||
|
||||
TokenRequestContext trc;
|
||||
trc.Scopes.push_back("https://vault.azure.net/.default");
|
||||
|
||||
try
|
||||
{
|
||||
AccessToken token = cred.GetToken(trc, {});
|
||||
GTEST_FAIL()
|
||||
<< "GetToken should have thrown an exception due to an invalid service connection ID.";
|
||||
}
|
||||
catch (AuthenticationException const& ex)
|
||||
{
|
||||
EXPECT_TRUE(std::string(ex.what()).find("404 (Not Found)") != std::string::npos) << ex.what();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AzurePipelinesCredential, InvalidSystemAccessToken_LIVEONLY_)
|
||||
{
|
||||
std::string tenantId = Environment::GetVariable("AZURESUBSCRIPTION_TENANT_ID");
|
||||
std::string clientId = Environment::GetVariable("AZURESUBSCRIPTION_CLIENT_ID");
|
||||
std::string serviceConnectionId
|
||||
= Environment::GetVariable("AZURESUBSCRIPTION_SERVICE_CONNECTION_ID");
|
||||
|
||||
const std::string systemAccessToken = "invalidSystemAccessToken";
|
||||
|
||||
if (tenantId.empty() || clientId.empty() || serviceConnectionId.empty())
|
||||
{
|
||||
std::string message
|
||||
= GetSkipTestMessage(tenantId, clientId, serviceConnectionId, systemAccessToken);
|
||||
GTEST_SKIP_(message.c_str());
|
||||
}
|
||||
|
||||
AzurePipelinesCredential const cred(tenantId, clientId, serviceConnectionId, systemAccessToken);
|
||||
|
||||
TokenRequestContext trc;
|
||||
trc.Scopes.push_back("https://vault.azure.net/.default");
|
||||
|
||||
try
|
||||
{
|
||||
AccessToken token = cred.GetToken(trc, {});
|
||||
GTEST_FAIL()
|
||||
<< "GetToken should have thrown an exception due to an invalid system access token.";
|
||||
}
|
||||
catch (AuthenticationException const& ex)
|
||||
{
|
||||
EXPECT_TRUE(std::string(ex.what()).find("302 (Found)") != std::string::npos) << ex.what();
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче