Skip to content

Commit

Permalink
feat: support per-host scope hints (#604)
Browse files Browse the repository at this point in the history
The purpose of this PR is to fix the bug, but new APIs are needed to
avoid breaking changes.
1. Introduce `auth.WithScopesForHost`
2. Introduce `auth.AppendScopesForHost`
3. Introduce `auth.GetScopesForHost` and `auth.GetAllScopesForHost`
4. Introduce `auth.AppendRepositoryScope`

Resolves: #581
Signed-off-by: Lixia (Sylvia) Lei <lixlei@microsoft.com>
  • Loading branch information
Wwwsylvia authored Sep 27, 2023
1 parent 2d371a0 commit a428ca6
Show file tree
Hide file tree
Showing 8 changed files with 2,207 additions and 195 deletions.
5 changes: 2 additions & 3 deletions content.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"oras.land/oras-go/v2/internal/docker"
"oras.land/oras-go/v2/internal/interfaces"
"oras.land/oras-go/v2/internal/platform"
"oras.land/oras-go/v2/internal/registryutil"
"oras.land/oras-go/v2/internal/syncutil"
"oras.land/oras-go/v2/registry"
"oras.land/oras-go/v2/registry/remote/auth"
Expand Down Expand Up @@ -91,7 +90,7 @@ func TagN(ctx context.Context, target Target, srcReference string, dstReferences
if err != nil {
return ocispec.Descriptor{}, err
}
ctx = registryutil.WithScopeHint(ctx, ref, auth.ActionPull, auth.ActionPush)
ctx = auth.AppendRepositoryScope(ctx, ref, auth.ActionPull, auth.ActionPush)
}

desc, contentBytes, err := FetchBytes(ctx, target, srcReference, FetchBytesOptions{
Expand Down Expand Up @@ -149,7 +148,7 @@ func Tag(ctx context.Context, target Target, src, dst string) (ocispec.Descripto
if err != nil {
return ocispec.Descriptor{}, err
}
ctx = registryutil.WithScopeHint(ctx, ref, auth.ActionPull, auth.ActionPush)
ctx = auth.AppendRepositoryScope(ctx, ref, auth.ActionPull, auth.ActionPush)
}
desc, rc, err := refFetcher.FetchReference(ctx, src)
if err != nil {
Expand Down
29 changes: 0 additions & 29 deletions internal/registryutil/auth.go

This file was deleted.

28 changes: 14 additions & 14 deletions registry/remote/auth/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,19 +177,19 @@ func (c *Client) Do(originalReq *http.Request) (*http.Response, error) {
// attempt cached auth token
var attemptedKey string
cache := c.cache()
registry := originalReq.Host
scheme, err := cache.GetScheme(ctx, registry)
host := originalReq.Host
scheme, err := cache.GetScheme(ctx, host)
if err == nil {
switch scheme {
case SchemeBasic:
token, err := cache.GetToken(ctx, registry, SchemeBasic, "")
token, err := cache.GetToken(ctx, host, SchemeBasic, "")
if err == nil {
req.Header.Set("Authorization", "Basic "+token)
}
case SchemeBearer:
scopes := GetScopes(ctx)
scopes := GetAllScopesForHost(ctx, host)
attemptedKey = strings.Join(scopes, " ")
token, err := cache.GetToken(ctx, registry, SchemeBearer, attemptedKey)
token, err := cache.GetToken(ctx, host, SchemeBearer, attemptedKey)
if err == nil {
req.Header.Set("Authorization", "Bearer "+token)
}
Expand All @@ -211,8 +211,8 @@ func (c *Client) Do(originalReq *http.Request) (*http.Response, error) {
case SchemeBasic:
resp.Body.Close()

token, err := cache.Set(ctx, registry, SchemeBasic, "", func(ctx context.Context) (string, error) {
return c.fetchBasicAuth(ctx, registry)
token, err := cache.Set(ctx, host, SchemeBasic, "", func(ctx context.Context) (string, error) {
return c.fetchBasicAuth(ctx, host)
})
if err != nil {
return nil, fmt.Errorf("%s %q: %w", resp.Request.Method, resp.Request.URL, err)
Expand All @@ -223,17 +223,17 @@ func (c *Client) Do(originalReq *http.Request) (*http.Response, error) {
case SchemeBearer:
resp.Body.Close()

// merge hinted scopes with challenged scopes
scopes := GetScopes(ctx)
if scope := params["scope"]; scope != "" {
scopes = append(scopes, strings.Split(scope, " ")...)
scopes := GetAllScopesForHost(ctx, host)
if paramScope := params["scope"]; paramScope != "" {
// merge hinted scopes with challenged scopes
scopes = append(scopes, strings.Split(paramScope, " ")...)
scopes = CleanScopes(scopes)
}
key := strings.Join(scopes, " ")

// attempt the cache again if there is a scope change
if key != attemptedKey {
if token, err := cache.GetToken(ctx, registry, SchemeBearer, key); err == nil {
if token, err := cache.GetToken(ctx, host, SchemeBearer, key); err == nil {
req = originalReq.Clone(ctx)
req.Header.Set("Authorization", "Bearer "+token)
if err := rewindRequestBody(req); err != nil {
Expand All @@ -254,8 +254,8 @@ func (c *Client) Do(originalReq *http.Request) (*http.Response, error) {
// attempt with credentials
realm := params["realm"]
service := params["service"]
token, err := cache.Set(ctx, registry, SchemeBearer, key, func(ctx context.Context) (string, error) {
return c.fetchBearerToken(ctx, registry, realm, service, scopes)
token, err := cache.Set(ctx, host, SchemeBearer, key, func(ctx context.Context) (string, error) {
return c.fetchBearerToken(ctx, host, realm, service, scopes)
})
if err != nil {
return nil, fmt.Errorf("%s %q: %w", resp.Request.Method, resp.Request.URL, err)
Expand Down
Loading

0 comments on commit a428ca6

Please sign in to comment.