@@ -47,6 +47,10 @@ internal class ContainerRegistryServerAPICalls : ServerApiCall
47
47
const string containerRegistryStartUploadTemplate = "https://{0}/v2/{1}/blobs/uploads/" ; // 0 - registry, 1 - packagename
48
48
const string containerRegistryEndUploadTemplate = "https://{0}{1}&digest=sha256:{2}" ; // 0 - registry, 1 - location, 2 - digest
49
49
const string defaultScope = "&scope=repository:*:*&scope=registry:catalog:*" ;
50
+ const string catalogScope = "&scope=registry:catalog:*" ;
51
+ const string grantTypeTemplate = "grant_type=access_token&service={0}{1}" ; // 0 - registry, 1 - scope
52
+ const string authUrlTemplate = "{0}?service={1}{2}" ; // 0 - realm, 1 - service, 2 - scope
53
+
50
54
const string containerRegistryRepositoryListTemplate = "https://{0}/v2/_catalog" ; // 0 - registry
51
55
52
56
#endregion
@@ -323,7 +327,7 @@ private Stream InstallVersion(
323
327
return null ;
324
328
}
325
329
326
- string containerRegistryAccessToken = GetContainerRegistryAccessToken ( out errRecord ) ;
330
+ string containerRegistryAccessToken = GetContainerRegistryAccessToken ( needCatalogAccess : false , out errRecord ) ;
327
331
if ( errRecord != null )
328
332
{
329
333
return null ;
@@ -371,7 +375,7 @@ private Stream InstallVersion(
371
375
/// 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.
372
376
/// Note: Access token can be empty if the repository is unauthenticated
373
377
/// </summary>
374
- internal string GetContainerRegistryAccessToken ( out ErrorRecord errRecord )
378
+ internal string GetContainerRegistryAccessToken ( bool needCatalogAccess , out ErrorRecord errRecord )
375
379
{
376
380
_cmdletPassedIn . WriteDebug ( "In ContainerRegistryServerAPICalls::GetContainerRegistryAccessToken()" ) ;
377
381
string accessToken = string . Empty ;
@@ -393,7 +397,7 @@ internal string GetContainerRegistryAccessToken(out ErrorRecord errRecord)
393
397
}
394
398
else
395
399
{
396
- bool isRepositoryUnauthenticated = IsContainerRegistryUnauthenticated ( Repository . Uri . ToString ( ) , out errRecord , out accessToken ) ;
400
+ bool isRepositoryUnauthenticated = IsContainerRegistryUnauthenticated ( Repository . Uri . ToString ( ) , needCatalogAccess , out errRecord , out accessToken ) ;
397
401
_cmdletPassedIn . WriteDebug ( $ "Is repository unauthenticated: { isRepositoryUnauthenticated } ") ;
398
402
399
403
if ( errRecord != null )
@@ -446,7 +450,7 @@ internal string GetContainerRegistryAccessToken(out ErrorRecord errRecord)
446
450
/// <summary>
447
451
/// Checks if container registry repository is unauthenticated.
448
452
/// </summary>
449
- internal bool IsContainerRegistryUnauthenticated ( string containerRegistyUrl , out ErrorRecord errRecord , out string anonymousAccessToken )
453
+ internal bool IsContainerRegistryUnauthenticated ( string containerRegistyUrl , bool needCatalogAccess , out ErrorRecord errRecord , out string anonymousAccessToken )
450
454
{
451
455
_cmdletPassedIn . WriteDebug ( "In ContainerRegistryServerAPICalls::IsContainerRegistryUnauthenticated()" ) ;
452
456
errRecord = null ;
@@ -484,20 +488,24 @@ internal bool IsContainerRegistryUnauthenticated(string containerRegistyUrl, out
484
488
return false ;
485
489
}
486
490
487
- string content = "grant_type=access_token&service=" + service + defaultScope ;
491
+ string content = needCatalogAccess ? String . Format ( grantTypeTemplate , service , catalogScope ) : String . Format ( grantTypeTemplate , service , defaultScope ) ;
492
+
488
493
var contentHeaders = new Collection < KeyValuePair < string , string > > { new KeyValuePair < string , string > ( "Content-Type" , "application/x-www-form-urlencoded" ) } ;
489
494
490
- // get the anonymous access token
491
- var url = $ "{ realm } ?service={ service } { defaultScope } ";
495
+ string url = needCatalogAccess ? String . Format ( authUrlTemplate , realm , service , catalogScope ) : String . Format ( authUrlTemplate , realm , service , defaultScope ) ;
492
496
493
497
_cmdletPassedIn . WriteDebug ( $ "Getting anonymous access token from the realm: { url } ") ;
494
498
495
499
// we dont check the errorrecord here because we want to return false if we get a 401 and not throw an error
496
- var results = GetHttpResponseJObjectUsingContentHeaders ( url , HttpMethod . Get , content , contentHeaders , out _ ) ;
500
+ _cmdletPassedIn . WriteDebug ( $ "Getting anonymous access token from the realm: { url } ") ;
501
+ ErrorRecord errRecordTemp = null ;
502
+
503
+ var results = GetHttpResponseJObjectUsingContentHeaders ( url , HttpMethod . Get , content , contentHeaders , out errRecordTemp ) ;
497
504
498
505
if ( results == null )
499
506
{
500
507
_cmdletPassedIn . WriteDebug ( "Failed to get access token from the realm. results is null." ) ;
508
+ _cmdletPassedIn . WriteDebug ( $ "ErrorRecord: { errRecordTemp } ") ;
501
509
return false ;
502
510
}
503
511
@@ -508,7 +516,6 @@ internal bool IsContainerRegistryUnauthenticated(string containerRegistyUrl, out
508
516
}
509
517
510
518
anonymousAccessToken = results [ "access_token" ] . ToString ( ) ;
511
- _cmdletPassedIn . WriteDebug ( "Anonymous access token retrieved" ) ;
512
519
return true ;
513
520
}
514
521
}
@@ -761,7 +768,7 @@ internal Hashtable GetContainerRegistryMetadata(string packageName, string exact
761
768
if ( ! NuGetVersion . TryParse ( pkgVersionString , out NuGetVersion pkgVersion ) )
762
769
{
763
770
errRecord = new ErrorRecord (
764
- new ArgumentException ( $ "Version { pkgVersionString } to be parsed from metadata is not a valid NuGet version.") ,
771
+ new ArgumentException ( $ "Version { pkgVersionString } to be parsed from metadata is not a valid NuGet version for package ' { packageName } ' .") ,
765
772
"ParseMetadataFailure" ,
766
773
ErrorCategory . InvalidArgument ,
767
774
this ) ;
@@ -988,24 +995,29 @@ internal JObject GetHttpResponseJObjectUsingContentHeaders(string url, HttpMetho
988
995
{
989
996
HttpRequestMessage request = new HttpRequestMessage ( method , url ) ;
990
997
991
- if ( string . IsNullOrEmpty ( content ) )
998
+ // HTTP GET does not expect a body / content.
999
+ if ( method != HttpMethod . Get )
992
1000
{
993
- errRecord = new ErrorRecord (
994
- exception : new ArgumentNullException ( $ "Content is null or empty and cannot be used to make a request as its content headers.") ,
995
- "RequestContentHeadersNullOrEmpty" ,
996
- ErrorCategory . InvalidData ,
997
- _cmdletPassedIn ) ;
998
1001
999
- return null ;
1000
- }
1002
+ if ( string . IsNullOrEmpty ( content ) )
1003
+ {
1004
+ errRecord = new ErrorRecord (
1005
+ exception : new ArgumentNullException ( $ "Content is null or empty and cannot be used to make a request as its content headers.") ,
1006
+ "RequestContentHeadersNullOrEmpty" ,
1007
+ ErrorCategory . InvalidData ,
1008
+ _cmdletPassedIn ) ;
1001
1009
1002
- request . Content = new StringContent ( content ) ;
1003
- request . Content . Headers . Clear ( ) ;
1004
- if ( contentHeaders != null )
1005
- {
1006
- foreach ( var header in contentHeaders )
1010
+ return null ;
1011
+ }
1012
+
1013
+ request . Content = new StringContent ( content ) ;
1014
+ request . Content . Headers . Clear ( ) ;
1015
+ if ( contentHeaders != null )
1007
1016
{
1008
- request . Content . Headers . Add ( header . Key , header . Value ) ;
1017
+ foreach ( var header in contentHeaders )
1018
+ {
1019
+ request . Content . Headers . Add ( header . Key , header . Value ) ;
1020
+ }
1009
1021
}
1010
1022
}
1011
1023
@@ -1234,7 +1246,7 @@ internal bool PushNupkgContainerRegistry(
1234
1246
1235
1247
// Get access token (includes refresh tokens)
1236
1248
_cmdletPassedIn . WriteVerbose ( $ "Get access token for container registry server.") ;
1237
- var containerRegistryAccessToken = GetContainerRegistryAccessToken ( out errRecord ) ;
1249
+ var containerRegistryAccessToken = GetContainerRegistryAccessToken ( needCatalogAccess : false , out errRecord ) ;
1238
1250
if ( errRecord != null )
1239
1251
{
1240
1252
return false ;
@@ -1699,7 +1711,7 @@ private Hashtable[] FindPackagesWithVersionHelper(string packageName, VersionTyp
1699
1711
string packageNameLowercase = packageName . ToLower ( ) ;
1700
1712
1701
1713
string packageNameForFind = PrependMARPrefix ( packageNameLowercase ) ;
1702
- string containerRegistryAccessToken = GetContainerRegistryAccessToken ( out errRecord ) ;
1714
+ string containerRegistryAccessToken = GetContainerRegistryAccessToken ( needCatalogAccess : false , out errRecord ) ;
1703
1715
if ( errRecord != null )
1704
1716
{
1705
1717
return emptyHashResponses ;
@@ -1715,8 +1727,9 @@ private Hashtable[] FindPackagesWithVersionHelper(string packageName, VersionTyp
1715
1727
List < JToken > allVersionsList = foundTags [ "tags" ] . ToList ( ) ;
1716
1728
1717
1729
SortedDictionary < NuGet . Versioning . SemanticVersion , string > sortedQualifyingPkgs = GetPackagesWithRequiredVersion ( allVersionsList , versionType , versionRange , requiredVersion , packageNameForFind , includePrerelease , out errRecord ) ;
1718
- if ( errRecord != null )
1730
+ if ( errRecord != null && sortedQualifyingPkgs ? . Count == 0 )
1719
1731
{
1732
+ _cmdletPassedIn . WriteDebug ( "No qualifying packages found for the specified criteria." ) ;
1720
1733
return emptyHashResponses ;
1721
1734
}
1722
1735
@@ -1760,12 +1773,14 @@ private Hashtable[] FindPackagesWithVersionHelper(string packageName, VersionTyp
1760
1773
if ( ! NuGetVersion . TryParse ( pkgVersionString , out NuGetVersion pkgVersion ) )
1761
1774
{
1762
1775
errRecord = new ErrorRecord (
1763
- new ArgumentException ( $ "Version { pkgVersionString } to be parsed from metadata is not a valid NuGet version.") ,
1776
+ new ArgumentException ( $ "Version { pkgVersionString } to be parsed from metadata is not a valid NuGet version for package ' { packageName } ' .") ,
1764
1777
"FindNameFailure" ,
1765
1778
ErrorCategory . InvalidArgument ,
1766
1779
this ) ;
1767
1780
1768
- return null ;
1781
+ _cmdletPassedIn . WriteError ( errRecord ) ;
1782
+ _cmdletPassedIn . WriteDebug ( $ "Skipping package '{ packageName } ' with version '{ pkgVersionString } ' as it is not a valid NuGet version.") ;
1783
+ continue ; // skip this version and continue with the next one
1769
1784
}
1770
1785
1771
1786
_cmdletPassedIn . WriteDebug ( $ "'{ packageName } ' version parsed as '{ pkgVersion } '") ;
@@ -1808,7 +1823,7 @@ private FindResults FindPackages(string packageName, bool includePrerelease, out
1808
1823
{
1809
1824
_cmdletPassedIn . WriteDebug ( "In ContainerRegistryServerAPICalls::FindPackages()" ) ;
1810
1825
errRecord = null ;
1811
- string containerRegistryAccessToken = GetContainerRegistryAccessToken ( out errRecord ) ;
1826
+ string containerRegistryAccessToken = GetContainerRegistryAccessToken ( needCatalogAccess : true , out errRecord ) ;
1812
1827
if ( errRecord != null )
1813
1828
{
1814
1829
return emptyResponseResults ;
0 commit comments