@@ -7,6 +7,7 @@ package api
77import (
88 "bytes"
99 "context"
10+ "fmt"
1011 "io/ioutil"
1112 "strings"
1213 "time"
@@ -94,7 +95,9 @@ func newAcrCLIClientWithBasicAuth(loginURL string, username string, password str
9495func newAcrCLIClientWithBearerAuth (loginURL string , refreshToken string ) (AcrCLIClient , error ) {
9596 newAcrCLIClient := newAcrCLIClient (loginURL )
9697 ctx := context .Background ()
97- accessTokenResponse , err := newAcrCLIClient .AutorestClient .GetAcrAccessToken (ctx , loginURL , "registry:catalog:* repository:*:*" , refreshToken )
98+ // For ABAC-enabled registries, only request catalog scope initially
99+ // Repository-specific scopes will be requested when needed
100+ accessTokenResponse , err := newAcrCLIClient .AutorestClient .GetAcrAccessToken (ctx , loginURL , "registry:catalog:*" , refreshToken )
98101 if err != nil {
99102 return newAcrCLIClient , err
100103 }
@@ -153,9 +156,9 @@ func GetAcrCLIClientWithAuth(loginURL string, username string, password string,
153156 return & acrClient , nil
154157}
155158
156- // refreshAcrCLIClientToken obtains a new token and gets its expiration time.
157- func refreshAcrCLIClientToken (ctx context.Context , c * AcrCLIClient ) error {
158- accessTokenResponse , err := c .AutorestClient .GetAcrAccessToken (ctx , c .loginURL , "repository:*:*" , c .token .RefreshToken )
159+ // refreshAcrCLIClientToken obtains a new token with the specified scope and gets its expiration time.
160+ func refreshAcrCLIClientToken (ctx context.Context , c * AcrCLIClient , scope string ) error {
161+ accessTokenResponse , err := c .AutorestClient .GetAcrAccessToken (ctx , c .loginURL , scope , c .token .RefreshToken )
159162 if err != nil {
160163 return err
161164 }
@@ -173,6 +176,19 @@ func refreshAcrCLIClientToken(ctx context.Context, c *AcrCLIClient) error {
173176 return nil
174177}
175178
179+ // refreshTokenForRepository obtains a new token scoped to a specific repository with all permissions.
180+ // This supports both ABAC and non-ABAC registries.
181+ func refreshTokenForRepository (ctx context.Context , c * AcrCLIClient , repoName string ) error {
182+ // For specific repository operations, request full permissions on that repository
183+ scope := fmt .Sprintf ("repository:%s:*" , repoName )
184+ return refreshAcrCLIClientToken (ctx , c , scope )
185+ }
186+
187+ // refreshTokenForCatalog obtains a new token with catalog access only.
188+ func refreshTokenForCatalog (ctx context.Context , c * AcrCLIClient ) error {
189+ return refreshAcrCLIClientToken (ctx , c , "registry:catalog:*" )
190+ }
191+
176192// getExpiration is used to obtain the expiration out of a jwt token.
177193func getExpiration (token string ) (int64 , error ) {
178194 parser := jwt.Parser {SkipClaimsValidation : true }
@@ -201,7 +217,7 @@ func (c *AcrCLIClient) isExpired() bool {
201217// GetAcrTags list the tags of a repository with their attributes.
202218func (c * AcrCLIClient ) GetAcrTags (ctx context.Context , repoName string , orderBy string , last string ) (* acrapi.RepositoryTagsType , error ) {
203219 if c .isExpired () {
204- if err := refreshAcrCLIClientToken (ctx , c ); err != nil {
220+ if err := refreshTokenForRepository (ctx , c , repoName ); err != nil {
205221 return nil , err
206222 }
207223 }
@@ -216,7 +232,7 @@ func (c *AcrCLIClient) GetAcrTags(ctx context.Context, repoName string, orderBy
216232// DeleteAcrTag deletes the tag by reference.
217233func (c * AcrCLIClient ) DeleteAcrTag (ctx context.Context , repoName string , reference string ) (* autorest.Response , error ) {
218234 if c .isExpired () {
219- if err := refreshAcrCLIClientToken (ctx , c ); err != nil {
235+ if err := refreshTokenForRepository (ctx , c , repoName ); err != nil {
220236 return nil , err
221237 }
222238 }
@@ -230,7 +246,7 @@ func (c *AcrCLIClient) DeleteAcrTag(ctx context.Context, repoName string, refere
230246// GetAcrManifests list all the manifest in a repository with their attributes.
231247func (c * AcrCLIClient ) GetAcrManifests (ctx context.Context , repoName string , orderBy string , last string ) (* acrapi.Manifests , error ) {
232248 if c .isExpired () {
233- if err := refreshAcrCLIClientToken (ctx , c ); err != nil {
249+ if err := refreshTokenForRepository (ctx , c , repoName ); err != nil {
234250 return nil , err
235251 }
236252 }
@@ -244,7 +260,7 @@ func (c *AcrCLIClient) GetAcrManifests(ctx context.Context, repoName string, ord
244260// DeleteManifest deletes a manifest using the digest as a reference.
245261func (c * AcrCLIClient ) DeleteManifest (ctx context.Context , repoName string , reference string ) (* autorest.Response , error ) {
246262 if c .isExpired () {
247- if err := refreshAcrCLIClientToken (ctx , c ); err != nil {
263+ if err := refreshTokenForRepository (ctx , c , repoName ); err != nil {
248264 return nil , err
249265 }
250266 }
@@ -259,7 +275,7 @@ func (c *AcrCLIClient) DeleteManifest(ctx context.Context, repoName string, refe
259275// This is used when a manifest list is wanted, first the bytes are obtained and then unmarshalled into a new struct.
260276func (c * AcrCLIClient ) GetManifest (ctx context.Context , repoName string , reference string ) ([]byte , error ) {
261277 if c .isExpired () {
262- if err := refreshAcrCLIClientToken (ctx , c ); err != nil {
278+ if err := refreshTokenForRepository (ctx , c , repoName ); err != nil {
263279 return nil , err
264280 }
265281 }
@@ -299,7 +315,7 @@ func (c *AcrCLIClient) GetManifest(ctx context.Context, repoName string, referen
299315// GetAcrManifestAttributes gets the attributes of a manifest.
300316func (c * AcrCLIClient ) GetAcrManifestAttributes (ctx context.Context , repoName string , reference string ) (* acrapi.ManifestAttributes , error ) {
301317 if c .isExpired () {
302- if err := refreshAcrCLIClientToken (ctx , c ); err != nil {
318+ if err := refreshTokenForRepository (ctx , c , repoName ); err != nil {
303319 return nil , err
304320 }
305321 }
@@ -313,7 +329,7 @@ func (c *AcrCLIClient) GetAcrManifestAttributes(ctx context.Context, repoName st
313329// UpdateAcrTagAttributes updates tag attributes to enable/disable deletion and writing.
314330func (c * AcrCLIClient ) UpdateAcrTagAttributes (ctx context.Context , repoName string , reference string , value * acrapi.ChangeableAttributes ) (* autorest.Response , error ) {
315331 if c .isExpired () {
316- if err := refreshAcrCLIClientToken (ctx , c ); err != nil {
332+ if err := refreshTokenForRepository (ctx , c , repoName ); err != nil {
317333 return nil , err
318334 }
319335 }
@@ -327,7 +343,7 @@ func (c *AcrCLIClient) UpdateAcrTagAttributes(ctx context.Context, repoName stri
327343// UpdateAcrManifestAttributes updates manifest attributes to enable/disable deletion and writing.
328344func (c * AcrCLIClient ) UpdateAcrManifestAttributes (ctx context.Context , repoName string , reference string , value * acrapi.ChangeableAttributes ) (* autorest.Response , error ) {
329345 if c .isExpired () {
330- if err := refreshAcrCLIClientToken (ctx , c ); err != nil {
346+ if err := refreshTokenForRepository (ctx , c , repoName ); err != nil {
331347 return nil , err
332348 }
333349 }
0 commit comments