diff --git a/README.md b/README.md index e4cf269..74ef956 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,15 @@ Here is a visual of this auth flow copied from the [Docker docs](https://docs.do ![](./v2-registry-auth.png) +#### Custom Auth Scope + + It may be necessary to override the `scope` obtained from the `Www-Authenticate` header in the registry's response. This can be done on the client level: + + ``` +client, err := reggie.NewClient("http://localhost:5000", + reggie.WithAuthScope("repository:mystuff/myrepo:pull,push")) + ``` + ## Other Features ### Method Chaining diff --git a/auth.go b/auth.go index bca93eb..7579b4a 100644 --- a/auth.go +++ b/auth.go @@ -44,9 +44,12 @@ func (client *Client) retryRequestWithAuth(originalRequest *Request, originalRes SetHeader("Accept", "application/json"). SetHeader("User-Agent", client.Config.UserAgent). SetBasicAuth(client.Config.Username, client.Config.Password) - if h.Scope != "" { + if s := client.Config.AuthScope; s != "" { + req.SetQueryParam("scope", s) + } else if h.Scope != "" { req.SetQueryParam("scope", h.Scope) } + authResp, err := req.Execute(GET, h.Realm) if err != nil { return nil, err diff --git a/client.go b/client.go index 897cd45..85bf4de 100644 --- a/client.go +++ b/client.go @@ -24,6 +24,7 @@ type ( clientConfig struct { Address string + AuthScope string Username string Password string Debug bool @@ -65,6 +66,13 @@ func WithUsernamePassword(username string, password string) clientOption { } } +// WithAuthScope overrides the scope provided by the authorization server. +func WithAuthScope(authScope string) clientOption { + return func(c *clientConfig) { + c.AuthScope = authScope + } +} + // WithDefaultName sets the default registry namespace configuration setting. func WithDefaultName(namespace string) clientOption { return func(c *clientConfig) { diff --git a/client_test.go b/client_test.go index 697a73b..e51d9e2 100644 --- a/client_test.go +++ b/client_test.go @@ -79,6 +79,17 @@ func TestClient(t *testing.T) { t.Errorf("Setting the debug flag didn't work") } + // test setting auth scope + testScope := `realm="https://silly.com/v2/auth",service="testservice",scope="pull,push"` + client3, err := NewClient(registryTestServer.URL, WithAuthScope(testScope)) + if err != nil { + t.Fatalf("Errors creating client: %s", err) + } + + if s := client3.Config.AuthScope; s != testScope { + t.Errorf("Setting the auth scope didn't work: %s", s) + } + // test default name req := client.NewRequest(GET, "/v2//tags/list") if !strings.HasSuffix(req.URL, "/v2/testname/tags/list") { @@ -99,8 +110,6 @@ func TestClient(t *testing.T) { t.Fatalf("Expected response code 200 but was %d", status) } - - // test default name reset client.SetDefaultName("othername") req = client.NewRequest(GET, "/v2//tags/list")