Skip to content
Merged
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b683ebf
Add AzurePipelinesCredential for authenticating an Azure Pipelines se…
ahsonkhan Jun 20, 2024
d39a861
Add unit tests.
ahsonkhan Jun 20, 2024
19581b3
Add comment about not throwing in the ctor, but rather deferring it.
ahsonkhan Jun 20, 2024
010e46e
Order field in order of initialization and fix cspell.
ahsonkhan Jun 20, 2024
deb7549
Fix ambiguous call to EnvironmentOverride in tests.
ahsonkhan Jun 20, 2024
0c1579b
Add a live test to AzurePipelinesCredential.
ahsonkhan Jun 20, 2024
04462a5
Add invalid test cases and output response.
ahsonkhan Jun 20, 2024
bbfd830
Add access token env var in ci.yml.
ahsonkhan Jun 21, 2024
ee6ca43
Add identity yml files and EnvVars.
ahsonkhan Jun 21, 2024
94c7cff
Merge branch 'main' of https://github.com/Azure/azure-sdk-for-cpp int…
ahsonkhan Jun 21, 2024
34a9798
Fix merge conflicts and print out the oidc response.
ahsonkhan Jun 21, 2024
ef32990
Remove duplicate definition of ServiceDirectory and remove env.
ahsonkhan Jun 21, 2024
44914b4
Revert CI/infra changes.
ahsonkhan Jun 21, 2024
dc61ad5
Include engsys changes to add federated auth support.
ahsonkhan Jun 21, 2024
ad3a175
Update environment variables used.
ahsonkhan Jun 21, 2024
dbd5497
Sync recent engsys changes.
ahsonkhan Jun 21, 2024
bea1ac4
Add invalid tenant id test and re-order them.
ahsonkhan Jun 21, 2024
cd403ae
Merge branch 'main' of https://github.com/Azure/azure-sdk-for-cpp int…
ahsonkhan Jun 21, 2024
2b57ba5
Fail the live test pipeline if a test fails.
ahsonkhan Jun 25, 2024
1811b65
Update tests and revert source changes.
ahsonkhan Jun 26, 2024
eba669c
Debug failing TokenCredentialTest in new live test environment.
ahsonkhan Jun 26, 2024
fa3250c
Dont fail test on missing env var.
ahsonkhan Jun 26, 2024
a834ce9
Disable federated auth in ci.yml and add back client secret env var.
ahsonkhan Jun 26, 2024
d31ffb0
Remove test application secret.
ahsonkhan Jun 26, 2024
5472162
Revert other changes related to infra.
ahsonkhan Jun 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}
}