33
44#include " azure/identity/azure_pipelines_credential.hpp"
55
6+ #include " private/client_assertion_credential_impl.hpp"
67#include " private/identity_log.hpp"
78#include " private/package_version.hpp"
89#include " private/tenant_id_resolver.hpp"
9- #include " private/token_credential_impl.hpp"
1010
1111#include < azure/core/internal/json/json.hpp>
1212
@@ -28,30 +28,6 @@ using Azure::Core::Json::_internal::json;
2828using Azure::Identity::_detail::IdentityLog;
2929using Azure::Identity::_detail::PackageVersion;
3030using Azure::Identity::_detail::TenantIdResolver;
31- using Azure::Identity::_detail::TokenCredentialImpl;
32-
33- namespace {
34- bool IsValidTenantId (std::string const & tenantId)
35- {
36- const std::string allowedChars = " .-" ;
37- if (tenantId.empty ())
38- {
39- return false ;
40- }
41- for (auto const c : tenantId)
42- {
43- if (allowedChars.find (c) != std::string::npos)
44- {
45- continue ;
46- }
47- if (!StringExtensions::IsAlphaNumeric (c))
48- {
49- return false ;
50- }
51- }
52- return true ;
53- }
54- } // namespace
5531
5632AzurePipelinesCredential::AzurePipelinesCredential (
5733 std::string tenantId,
@@ -61,26 +37,10 @@ AzurePipelinesCredential::AzurePipelinesCredential(
6137 AzurePipelinesCredentialOptions const & options)
6238 : TokenCredential(" AzurePipelinesCredential" ), m_serviceConnectionId(serviceConnectionId),
6339 m_systemAccessToken(systemAccessToken),
64- m_clientCredentialCore(tenantId, options.AuthorityHost, options.AdditionallyAllowedTenants),
6540 m_httpPipeline(HttpPipeline(options, " identity" , PackageVersion::ToString(), {}, {}))
6641{
6742 m_oidcRequestUrl = _detail::DefaultOptionValues::GetOidcRequestUrl ();
6843
69- bool isTenantIdValid = IsValidTenantId (tenantId);
70- if (!isTenantIdValid)
71- {
72- IdentityLog::Write (
73- IdentityLog::Level::Warning,
74- " Invalid tenant ID provided for " + GetCredentialName ()
75- + " . The tenant ID must be a non-empty string containing only alphanumeric characters, "
76- " periods, or hyphens. You can locate your tenant ID by following the instructions "
77- " listed here: https://learn.microsoft.com/partner-center/find-ids-and-domain-names" );
78- }
79- if (clientId.empty ())
80- {
81- IdentityLog::Write (
82- IdentityLog::Level::Warning, " No client ID specified for " + GetCredentialName () + " ." );
83- }
8444 if (serviceConnectionId.empty ())
8545 {
8646 IdentityLog::Write (
@@ -101,20 +61,24 @@ AzurePipelinesCredential::AzurePipelinesCredential(
10161 + " ' needed by " + GetCredentialName () + " . This should be set by Azure Pipelines." );
10262 }
10363
104- if (isTenantIdValid && !clientId. empty ( ) && !serviceConnectionId .empty ()
105- && !systemAccessToken.empty () && !m_oidcRequestUrl.empty ())
64+ if (TenantIdResolver::IsValidTenantId (tenantId ) && !clientId .empty ()
65+ && !serviceConnectionId. empty () && ! systemAccessToken.empty () && !m_oidcRequestUrl.empty ())
10666 {
107- m_tokenCredentialImpl = std::make_unique<TokenCredentialImpl>(options);
108- m_requestBody
109- = std::string (
110- " grant_type=client_credentials"
111- " &client_assertion_type="
112- " urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer" // cspell:disable-line
113- " &client_id=" )
114- + Url::Encode (clientId);
115-
116- IdentityLog::Write (
117- IdentityLog::Level::Informational, GetCredentialName () + " was created successfully." );
67+ ClientAssertionCredentialOptions clientAssertionCredentialOptions{};
68+ // Get the options from the base class (including ClientOptions).
69+ static_cast <Core::Credentials::TokenCredentialOptions&>(clientAssertionCredentialOptions)
70+ = options;
71+ clientAssertionCredentialOptions.AuthorityHost = options.AuthorityHost ;
72+ clientAssertionCredentialOptions.AdditionallyAllowedTenants
73+ = options.AdditionallyAllowedTenants ;
74+
75+ std::function<std::string (Context const &)> callback
76+ = [this ](Context const & context) { return GetAssertion (context); };
77+
78+ // ClientAssertionCredential validates the tenant ID, client ID, and assertion callback and logs
79+ // warning messages otherwise.
80+ m_clientAssertionCredentialImpl = std::make_unique<_detail::ClientAssertionCredentialImpl>(
81+ GetCredentialName (), tenantId, clientId, callback, clientAssertionCredentialOptions);
11882 }
11983 else
12084 {
@@ -214,7 +178,7 @@ AccessToken AzurePipelinesCredential::GetToken(
214178 TokenRequestContext const & tokenRequestContext,
215179 Context const & context) const
216180{
217- if (!m_tokenCredentialImpl )
181+ if (!m_clientAssertionCredentialImpl )
218182 {
219183 auto const AuthUnavailable = GetCredentialName () + " authentication unavailable. " ;
220184
@@ -226,41 +190,6 @@ AccessToken AzurePipelinesCredential::GetToken(
226190 AuthUnavailable + " Azure Pipelines environment is not set up correctly." );
227191 }
228192
229- auto const tenantId = TenantIdResolver::Resolve (
230- m_clientCredentialCore.GetTenantId (),
231- tokenRequestContext,
232- m_clientCredentialCore.GetAdditionallyAllowedTenants ());
233-
234- auto const scopesStr
235- = m_clientCredentialCore.GetScopesString (tenantId, tokenRequestContext.Scopes );
236-
237- // TokenCache::GetToken() and m_tokenCredentialImpl->GetToken() can only use the lambda
238- // argument when they are being executed. They are not supposed to keep a reference to lambda
239- // argument to call it later. Therefore, any capture made here will outlive the possible time
240- // frame when the lambda might get called.
241- return m_tokenCache.GetToken (scopesStr, tenantId, tokenRequestContext.MinimumExpiration , [&]() {
242- return m_tokenCredentialImpl->GetToken (context, false , [&]() {
243- auto body = m_requestBody;
244- if (!scopesStr.empty ())
245- {
246- body += " &scope=" + scopesStr;
247- }
248-
249- // Get the request url before calling GetAssertion to validate the authority host scheme.
250- // This is to avoid making a request to the OIDC endpoint if the authority host scheme is
251- // invalid.
252- auto const requestUrl = m_clientCredentialCore.GetRequestUrl (tenantId);
253-
254- const std::string assertion = GetAssertion (context);
255-
256- body += " &client_assertion=" + Azure::Core::Url::Encode (assertion);
257-
258- auto request
259- = std::make_unique<TokenCredentialImpl::TokenRequest>(HttpMethod::Post, requestUrl, body);
260-
261- request->HttpRequest .SetHeader (" Host" , requestUrl.GetHost ());
262-
263- return request;
264- });
265- });
193+ return m_clientAssertionCredentialImpl->GetToken (
194+ GetCredentialName (), tokenRequestContext, context);
266195}
0 commit comments