From fa5435b40cacd3b2f18209eac0268b44b93ba424 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 22 May 2025 12:57:21 -0700 Subject: [PATCH] Request for catalog listing access for finding packages --- src/code/ContainerRegistryServerAPICalls.cs | 25 ++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/code/ContainerRegistryServerAPICalls.cs b/src/code/ContainerRegistryServerAPICalls.cs index 785c7aeae..4158bc61f 100644 --- a/src/code/ContainerRegistryServerAPICalls.cs +++ b/src/code/ContainerRegistryServerAPICalls.cs @@ -47,6 +47,10 @@ internal class ContainerRegistryServerAPICalls : ServerApiCall const string containerRegistryStartUploadTemplate = "https://{0}/v2/{1}/blobs/uploads/"; // 0 - registry, 1 - packagename const string containerRegistryEndUploadTemplate = "https://{0}{1}&digest=sha256:{2}"; // 0 - registry, 1 - location, 2 - digest const string defaultScope = "&scope=repository:*:*&scope=registry:catalog:*"; + const string catalogScope = "&scope=registry:catalog:*"; + const string grantTypeTemplate = "grant_type=access_token&service={0}{1}"; // 0 - registry, 1 - scope + const string authUrlTemplate = "{0}?service={1}{2}"; // 0 - realm, 1 - service, 2 - scope + const string containerRegistryRepositoryListTemplate = "https://{0}/v2/_catalog"; // 0 - registry #endregion @@ -323,7 +327,7 @@ private Stream InstallVersion( return null; } - string containerRegistryAccessToken = GetContainerRegistryAccessToken(out errRecord); + string containerRegistryAccessToken = GetContainerRegistryAccessToken(needCatalogAccess: false, out errRecord); if (errRecord != null) { return null; @@ -371,7 +375,7 @@ private Stream InstallVersion( /// If no credential provided at registration then, check if the ACR endpoint can be accessed without a token. If not, try using Azure.Identity to get the az access token, then ACR refresh token and then ACR access token. /// Note: Access token can be empty if the repository is unauthenticated /// - internal string GetContainerRegistryAccessToken(out ErrorRecord errRecord) + internal string GetContainerRegistryAccessToken(bool needCatalogAccess, out ErrorRecord errRecord) { _cmdletPassedIn.WriteDebug("In ContainerRegistryServerAPICalls::GetContainerRegistryAccessToken()"); string accessToken = string.Empty; @@ -393,7 +397,7 @@ internal string GetContainerRegistryAccessToken(out ErrorRecord errRecord) } else { - bool isRepositoryUnauthenticated = IsContainerRegistryUnauthenticated(Repository.Uri.ToString(), out errRecord, out accessToken); + bool isRepositoryUnauthenticated = IsContainerRegistryUnauthenticated(Repository.Uri.ToString(), needCatalogAccess, out errRecord, out accessToken); if (errRecord != null) { return null; @@ -444,7 +448,7 @@ internal string GetContainerRegistryAccessToken(out ErrorRecord errRecord) /// /// Checks if container registry repository is unauthenticated. /// - internal bool IsContainerRegistryUnauthenticated(string containerRegistyUrl, out ErrorRecord errRecord, out string anonymousAccessToken) + internal bool IsContainerRegistryUnauthenticated(string containerRegistyUrl, bool needCatalogAccess, out ErrorRecord errRecord, out string anonymousAccessToken) { _cmdletPassedIn.WriteDebug("In ContainerRegistryServerAPICalls::IsContainerRegistryUnauthenticated()"); errRecord = null; @@ -482,11 +486,11 @@ internal bool IsContainerRegistryUnauthenticated(string containerRegistyUrl, out return false; } - string content = "grant_type=access_token&service=" + service + defaultScope; + string content = needCatalogAccess ? String.Format(grantTypeTemplate, service, catalogScope) : String.Format(grantTypeTemplate, service, defaultScope); + var contentHeaders = new Collection> { new KeyValuePair("Content-Type", "application/x-www-form-urlencoded") }; - // get the anonymous access token - var url = $"{realm}?service={service}{defaultScope}"; + string url = needCatalogAccess ? String.Format(authUrlTemplate, realm, service, catalogScope) : String.Format(authUrlTemplate, realm, service, defaultScope); // we dont check the errorrecord here because we want to return false if we get a 401 and not throw an error var results = GetHttpResponseJObjectUsingContentHeaders(url, HttpMethod.Get, content, contentHeaders, out _); @@ -504,6 +508,7 @@ internal bool IsContainerRegistryUnauthenticated(string containerRegistyUrl, out } anonymousAccessToken = results["access_token"].ToString(); + _cmdletPassedIn.WriteDebug("Anonymous access token retrieved"); return true; } @@ -1230,7 +1235,7 @@ internal bool PushNupkgContainerRegistry( // Get access token (includes refresh tokens) _cmdletPassedIn.WriteVerbose($"Get access token for container registry server."); - var containerRegistryAccessToken = GetContainerRegistryAccessToken(out errRecord); + var containerRegistryAccessToken = GetContainerRegistryAccessToken(needCatalogAccess: false, out errRecord); if (errRecord != null) { return false; @@ -1695,7 +1700,7 @@ private Hashtable[] FindPackagesWithVersionHelper(string packageName, VersionTyp string packageNameLowercase = packageName.ToLower(); string packageNameForFind = PrependMARPrefix(packageNameLowercase); - string containerRegistryAccessToken = GetContainerRegistryAccessToken(out errRecord); + string containerRegistryAccessToken = GetContainerRegistryAccessToken(needCatalogAccess: false, out errRecord); if (errRecord != null) { return emptyHashResponses; @@ -1804,7 +1809,7 @@ private FindResults FindPackages(string packageName, bool includePrerelease, out { _cmdletPassedIn.WriteDebug("In ContainerRegistryServerAPICalls::FindPackages()"); errRecord = null; - string containerRegistryAccessToken = GetContainerRegistryAccessToken(out errRecord); + string containerRegistryAccessToken = GetContainerRegistryAccessToken(needCatalogAccess: true, out errRecord); if (errRecord != null) { return emptyResponseResults;