From e84a84a5a969b396c012c3942b0d7654851ee310 Mon Sep 17 00:00:00 2001 From: Brian Goff Date: Wed, 18 Sep 2019 10:40:50 -0700 Subject: [PATCH] Add function to set custom auth scope in context Currently auth.docker.io uses a custom auth scope for (docker) plugins `repository(plugin)::`. This makes it impossible to use containerd distribution tooling to fetch plugins without also supplying a totally custom authorizer. This changes allows clients to set the correct scope on the context. It's a little bit nasty but "works". I'm also a bit suspect of some a couple of these unexported context functrions. Before the primary one used `contextWithRepositoryScope` overwrites any scope value and there is another one that appends the scope value. With this change they both append... Signed-off-by: Brian Goff --- remotes/docker/scope.go | 22 ++++++++++++++-------- remotes/docker/scope_test.go | 12 ++++++++++++ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/remotes/docker/scope.go b/remotes/docker/scope.go index 86bd81bf5..fa8401433 100644 --- a/remotes/docker/scope.go +++ b/remotes/docker/scope.go @@ -51,19 +51,25 @@ func contextWithRepositoryScope(ctx context.Context, refspec reference.Spec, pus if err != nil { return nil, err } - return context.WithValue(ctx, tokenScopesKey{}, []string{s}), nil + return WithScope(ctx, s), nil +} + +// WithScope appends a custom registry auth scope to the context. +func WithScope(ctx context.Context, scope string) context.Context { + var scopes []string + if v := ctx.Value(tokenScopesKey{}); v != nil { + scopes = v.([]string) + scopes = append(scopes, scope) + } else { + scopes = []string{scope} + } + return context.WithValue(ctx, tokenScopesKey{}, scopes) } // contextWithAppendPullRepositoryScope is used to append repository pull // scope into existing scopes indexed by the tokenScopesKey{}. func contextWithAppendPullRepositoryScope(ctx context.Context, repo string) context.Context { - var scopes []string - - if v := ctx.Value(tokenScopesKey{}); v != nil { - scopes = append(scopes, v.([]string)...) - } - scopes = append(scopes, fmt.Sprintf("repository:%s:pull", repo)) - return context.WithValue(ctx, tokenScopesKey{}, scopes) + return WithScope(ctx, fmt.Sprintf("repository:%s:pull", repo)) } // getTokenScopes returns deduplicated and sorted scopes from ctx.Value(tokenScopesKey{}) and common scopes. diff --git a/remotes/docker/scope_test.go b/remotes/docker/scope_test.go index 938129f46..2ec0feebd 100644 --- a/remotes/docker/scope_test.go +++ b/remotes/docker/scope_test.go @@ -22,6 +22,7 @@ import ( "github.com/containerd/containerd/reference" "gotest.tools/assert" + "gotest.tools/assert/cmp" ) func TestRepositoryScope(t *testing.T) { @@ -94,3 +95,14 @@ func TestGetTokenScopes(t *testing.T) { assert.DeepEqual(t, tc.expected, actual) } } + +func TestCustomScope(t *testing.T) { + scope := "whatever:foo/bar:pull" + ctx := WithScope(context.Background(), scope) + ctx = contextWithAppendPullRepositoryScope(ctx, "foo/bar") + + scopes := getTokenScopes(ctx, []string{}) + assert.Assert(t, cmp.Len(scopes, 2)) + assert.Check(t, cmp.Equal(scopes[0], "repository:foo/bar:pull")) + assert.Check(t, cmp.Equal(scopes[1], scope)) +}