From 3c546651754fe76ab6a5ba7bfaab8c0a74d4f026 Mon Sep 17 00:00:00 2001 From: wangxiaoxuan273 Date: Fri, 7 Apr 2023 05:46:56 +0000 Subject: [PATCH 01/11] feat: support credential function Signed-off-by: wangxiaoxuan273 --- credential.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 credential.go diff --git a/credential.go b/credential.go new file mode 100644 index 0000000..416f3be --- /dev/null +++ b/credential.go @@ -0,0 +1,31 @@ +/* +Copyright The ORAS Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package credentials + +import ( + "context" + + "oras.land/oras-go/v2/registry/remote/auth" +) + +func Credential(store Store) func(context.Context, string) (auth.Credential, error) { + return func(ctx context.Context, registry string) (auth.Credential, error) { + if registry == "" { + return auth.EmptyCredential, nil + } + return store.Get(ctx, registry) + } +} From a07546c1352b2b9dfd3ebe08acd105c7bd697e7c Mon Sep 17 00:00:00 2001 From: wangxiaoxuan273 Date: Thu, 13 Apr 2023 08:51:50 +0000 Subject: [PATCH 02/11] rebased Signed-off-by: wangxiaoxuan273 --- credential.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/credential.go b/credential.go index 416f3be..c5e2486 100644 --- a/credential.go +++ b/credential.go @@ -21,11 +21,13 @@ import ( "oras.land/oras-go/v2/registry/remote/auth" ) +// Credential returns a Credential() function that can be used by auth.Client. func Credential(store Store) func(context.Context, string) (auth.Credential, error) { - return func(ctx context.Context, registry string) (auth.Credential, error) { - if registry == "" { + return func(ctx context.Context, reg string) (auth.Credential, error) { + reg = mapHostname(reg) + if reg == "" { return auth.EmptyCredential, nil } - return store.Get(ctx, registry) + return store.Get(ctx, reg) } } From e9bc229a2611f06edf0a13c35eb275ccb92f7343 Mon Sep 17 00:00:00 2001 From: wangxiaoxuan273 Date: Fri, 14 Apr 2023 11:30:22 +0800 Subject: [PATCH 03/11] rebased and added unit tests Signed-off-by: wangxiaoxuan273 --- credential.go | 33 ---------------------------- registry.go | 11 ++++++++++ registry_test.go | 56 ++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 61 insertions(+), 39 deletions(-) delete mode 100644 credential.go diff --git a/credential.go b/credential.go deleted file mode 100644 index c5e2486..0000000 --- a/credential.go +++ /dev/null @@ -1,33 +0,0 @@ -/* -Copyright The ORAS Authors. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package credentials - -import ( - "context" - - "oras.land/oras-go/v2/registry/remote/auth" -) - -// Credential returns a Credential() function that can be used by auth.Client. -func Credential(store Store) func(context.Context, string) (auth.Credential, error) { - return func(ctx context.Context, reg string) (auth.Credential, error) { - reg = mapHostname(reg) - if reg == "" { - return auth.EmptyCredential, nil - } - return store.Get(ctx, reg) - } -} diff --git a/registry.go b/registry.go index f369579..2194154 100644 --- a/registry.go +++ b/registry.go @@ -64,6 +64,17 @@ func Logout(ctx context.Context, store Store, registryName string) error { return nil } +// Credential returns a Credential() function that can be used by auth.Client. +func Credential(store Store) func(context.Context, string) (auth.Credential, error) { + return func(ctx context.Context, reg string) (auth.Credential, error) { + reg = mapHostname(reg) + if reg == "" { + return auth.EmptyCredential, nil + } + return store.Get(ctx, reg) + } +} + func mapHostname(hostname string) string { // The Docker CLI expects that the 'docker.io' credential // will be added under the key "https://index.docker.io/v1/" diff --git a/registry_test.go b/registry_test.go index cd7a0cb..312d597 100644 --- a/registry_test.go +++ b/registry_test.go @@ -159,14 +159,14 @@ func Test_mapHostname(t *testing.T) { want string }{ { - "map docker.io to https://index.docker.io/v1/", - "docker.io", - "https://index.docker.io/v1/", + name: "map docker.io to https://index.docker.io/v1/", + host: "docker.io", + want: "https://index.docker.io/v1/", }, { - "do not map other host names", - "localhost:2333", - "localhost:2333", + name: "do not map other host names", + host: "localhost:2333", + want: "localhost:2333", }, } for _, tt := range tests { @@ -177,3 +177,47 @@ func Test_mapHostname(t *testing.T) { }) } } + +func TestCredential(t *testing.T) { + // create a test store + s := &testStore{} + s.storage = map[string]auth.Credential{ + "localhost:2333": {Username: "test_user", Password: "test_word"}, + "https://index.docker.io/v1/": {Username: "user", Password: "word"}, + } + // create a test client using Credential + testClient := &auth.Client{} + testClient.Credential = Credential(s) + tests := []struct { + name string + registry string + wantCredential auth.Credential + }{ + { + name: "get credentials for localhost:2333", + registry: "localhost:2333", + wantCredential: auth.Credential{Username: "test_user", Password: "test_word"}, + }, + { + name: "get credentials for docker.io", + registry: "docker.io", + wantCredential: auth.Credential{Username: "user", Password: "word"}, + }, + { + name: "get credentials for a registry not stored", + registry: "localhost:6666", + wantCredential: auth.EmptyCredential, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := testClient.Credential(context.Background(), tt.registry) + if err != nil { + t.Fatalf("could not get credential: %v", err) + } + if !reflect.DeepEqual(got, tt.wantCredential) { + t.Errorf("Credential() = %v, want %v", got, tt.wantCredential) + } + }) + } +} From 72b2cf1cc1539fcaaa330c7aad1871291ae0f5ff Mon Sep 17 00:00:00 2001 From: wangxiaoxuan273 Date: Fri, 14 Apr 2023 11:38:07 +0800 Subject: [PATCH 04/11] minor change Signed-off-by: wangxiaoxuan273 --- registry_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry_test.go b/registry_test.go index 312d597..ab0e973 100644 --- a/registry_test.go +++ b/registry_test.go @@ -213,7 +213,7 @@ func TestCredential(t *testing.T) { t.Run(tt.name, func(t *testing.T) { got, err := testClient.Credential(context.Background(), tt.registry) if err != nil { - t.Fatalf("could not get credential: %v", err) + t.Errorf("could not get credential: %v", err) } if !reflect.DeepEqual(got, tt.wantCredential) { t.Errorf("Credential() = %v, want %v", got, tt.wantCredential) From 518f6ca47d115c650c50291732d5b6bcc6f8b4f5 Mon Sep 17 00:00:00 2001 From: wangxiaoxuan273 Date: Fri, 14 Apr 2023 16:39:17 +0800 Subject: [PATCH 05/11] refined redirect Signed-off-by: wangxiaoxuan273 --- registry.go | 7 ++++--- registry_test.go | 5 +++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/registry.go b/registry.go index 2194154..91499a4 100644 --- a/registry.go +++ b/registry.go @@ -76,9 +76,10 @@ func Credential(store Store) func(context.Context, string) (auth.Credential, err } func mapHostname(hostname string) string { - // The Docker CLI expects that the 'docker.io' credential - // will be added under the key "https://index.docker.io/v1/" - if hostname == "docker.io" { + // The Docker CLI expects that the 'docker.io' and + // registry-1.docker.io credential will be added + // under the key "https://index.docker.io/v1/" + if hostname == "docker.io" || hostname == "registry-1.docker.io" { return "https://index.docker.io/v1/" } return hostname diff --git a/registry_test.go b/registry_test.go index ab0e973..514162e 100644 --- a/registry_test.go +++ b/registry_test.go @@ -203,6 +203,11 @@ func TestCredential(t *testing.T) { registry: "docker.io", wantCredential: auth.Credential{Username: "user", Password: "word"}, }, + { + name: "get credentials for registry-1.docker.io", + registry: "registry-1.docker.io", + wantCredential: auth.Credential{Username: "user", Password: "word"}, + }, { name: "get credentials for a registry not stored", registry: "localhost:6666", From 9becb4c156b312b693e140f48d84aa6ee25da988 Mon Sep 17 00:00:00 2001 From: wangxiaoxuan273 Date: Mon, 17 Apr 2023 19:15:03 +0800 Subject: [PATCH 06/11] added another map function, need refinement Signed-off-by: wangxiaoxuan273 --- registry.go | 25 ++++++++++++++++--------- registry_test.go | 2 +- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/registry.go b/registry.go index 91499a4..67b3f43 100644 --- a/registry.go +++ b/registry.go @@ -48,7 +48,7 @@ func Login(ctx context.Context, store Store, reg *remote.Registry, cred auth.Cre if err := regClone.Ping(ctx); err != nil { return fmt.Errorf("unable to ping the registry %s: %w", regClone.Reference.Registry, err) } - hostname := mapHostname(regClone.Reference.Registry) + hostname := getLoginRegistry(regClone.Reference.Registry) if err := store.Put(ctx, hostname, cred); err != nil { return fmt.Errorf("unable to store the credential for %s: %w", hostname, err) } @@ -57,7 +57,7 @@ func Login(ctx context.Context, store Store, reg *remote.Registry, cred auth.Cre // Logout provides the logout functionality given the registry name. func Logout(ctx context.Context, store Store, registryName string) error { - registryName = mapHostname(registryName) + registryName = getLoginRegistry(registryName) if err := store.Delete(ctx, registryName); err != nil { return fmt.Errorf("unable to delete the credential for %s: %w", registryName, err) } @@ -67,7 +67,7 @@ func Logout(ctx context.Context, store Store, registryName string) error { // Credential returns a Credential() function that can be used by auth.Client. func Credential(store Store) func(context.Context, string) (auth.Credential, error) { return func(ctx context.Context, reg string) (auth.Credential, error) { - reg = mapHostname(reg) + reg = getTargetRegistry(reg) if reg == "" { return auth.EmptyCredential, nil } @@ -75,12 +75,19 @@ func Credential(store Store) func(context.Context, string) (auth.Credential, err } } -func mapHostname(hostname string) string { - // The Docker CLI expects that the 'docker.io' and - // registry-1.docker.io credential will be added - // under the key "https://index.docker.io/v1/" - if hostname == "docker.io" || hostname == "registry-1.docker.io" { - return "https://index.docker.io/v1/" +// The Docker CLI expects that the 'docker.io' credential +// will be added under the key "https://index.docker.io/v1/" +func getLoginRegistry(hostname string) string { + if hostname == "docker.io" { + return "https://index.docker.io/v1/" // Login用的 } return hostname } + +// The behavior +func getTargetRegistry(target string) string { + if target == "registry-1.docker.io" { + return "https://index.docker.io/v1/" // Credential用的 + } + return target +} diff --git a/registry_test.go b/registry_test.go index 514162e..a2f5f68 100644 --- a/registry_test.go +++ b/registry_test.go @@ -171,7 +171,7 @@ func Test_mapHostname(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := mapHostname(tt.host); got != tt.want { + if got := getLoginRegistry(tt.host); got != tt.want { t.Errorf("mapHostname() = %v, want %v", got, tt.want) } }) From 0897940eb11a7370eaaa40ca63d3e60310c735e9 Mon Sep 17 00:00:00 2001 From: wangxiaoxuan273 Date: Tue, 18 Apr 2023 08:18:06 +0000 Subject: [PATCH 07/11] refined Signed-off-by: wangxiaoxuan273 --- registry.go | 7 ++++--- registry_test.go | 5 ----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/registry.go b/registry.go index 67b3f43..0a6efdd 100644 --- a/registry.go +++ b/registry.go @@ -79,15 +79,16 @@ func Credential(store Store) func(context.Context, string) (auth.Credential, err // will be added under the key "https://index.docker.io/v1/" func getLoginRegistry(hostname string) string { if hostname == "docker.io" { - return "https://index.docker.io/v1/" // Login用的 + return "https://index.docker.io/v1/" } return hostname } -// The behavior +// It is expected that the traffic targetting "registry-1.docker.io" +// will be redirected to "https://index.docker.io/v1/" func getTargetRegistry(target string) string { if target == "registry-1.docker.io" { - return "https://index.docker.io/v1/" // Credential用的 + return "https://index.docker.io/v1/" } return target } diff --git a/registry_test.go b/registry_test.go index a2f5f68..fe5bc82 100644 --- a/registry_test.go +++ b/registry_test.go @@ -198,11 +198,6 @@ func TestCredential(t *testing.T) { registry: "localhost:2333", wantCredential: auth.Credential{Username: "test_user", Password: "test_word"}, }, - { - name: "get credentials for docker.io", - registry: "docker.io", - wantCredential: auth.Credential{Username: "user", Password: "word"}, - }, { name: "get credentials for registry-1.docker.io", registry: "registry-1.docker.io", From c97288d7b7fd078baa417da7a41413d09c876733 Mon Sep 17 00:00:00 2001 From: wangxiaoxuan273 Date: Wed, 19 Apr 2023 16:08:54 +0800 Subject: [PATCH 08/11] renamed the functions Signed-off-by: wangxiaoxuan273 --- registry.go | 14 +++++++------- registry_test.go | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/registry.go b/registry.go index 0a6efdd..234af80 100644 --- a/registry.go +++ b/registry.go @@ -48,7 +48,7 @@ func Login(ctx context.Context, store Store, reg *remote.Registry, cred auth.Cre if err := regClone.Ping(ctx); err != nil { return fmt.Errorf("unable to ping the registry %s: %w", regClone.Reference.Registry, err) } - hostname := getLoginRegistry(regClone.Reference.Registry) + hostname := mapStoreRegistryName(regClone.Reference.Registry) if err := store.Put(ctx, hostname, cred); err != nil { return fmt.Errorf("unable to store the credential for %s: %w", hostname, err) } @@ -57,7 +57,7 @@ func Login(ctx context.Context, store Store, reg *remote.Registry, cred auth.Cre // Logout provides the logout functionality given the registry name. func Logout(ctx context.Context, store Store, registryName string) error { - registryName = getLoginRegistry(registryName) + registryName = mapStoreRegistryName(registryName) if err := store.Delete(ctx, registryName); err != nil { return fmt.Errorf("unable to delete the credential for %s: %w", registryName, err) } @@ -67,7 +67,7 @@ func Logout(ctx context.Context, store Store, registryName string) error { // Credential returns a Credential() function that can be used by auth.Client. func Credential(store Store) func(context.Context, string) (auth.Credential, error) { return func(ctx context.Context, reg string) (auth.Credential, error) { - reg = getTargetRegistry(reg) + reg = mapAuthenticationRegistryName(reg) if reg == "" { return auth.EmptyCredential, nil } @@ -77,16 +77,16 @@ func Credential(store Store) func(context.Context, string) (auth.Credential, err // The Docker CLI expects that the 'docker.io' credential // will be added under the key "https://index.docker.io/v1/" -func getLoginRegistry(hostname string) string { - if hostname == "docker.io" { +func mapStoreRegistryName(registry string) string { + if registry == "docker.io" { return "https://index.docker.io/v1/" } - return hostname + return registry } // It is expected that the traffic targetting "registry-1.docker.io" // will be redirected to "https://index.docker.io/v1/" -func getTargetRegistry(target string) string { +func mapAuthenticationRegistryName(target string) string { if target == "registry-1.docker.io" { return "https://index.docker.io/v1/" } diff --git a/registry_test.go b/registry_test.go index fe5bc82..aaaf807 100644 --- a/registry_test.go +++ b/registry_test.go @@ -171,7 +171,7 @@ func Test_mapHostname(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := getLoginRegistry(tt.host); got != tt.want { + if got := mapStoreRegistryName(tt.host); got != tt.want { t.Errorf("mapHostname() = %v, want %v", got, tt.want) } }) From 2a558c2082601892953fc214c578f7d47565dcc9 Mon Sep 17 00:00:00 2001 From: wangxiaoxuan273 Date: Thu, 20 Apr 2023 02:40:25 +0000 Subject: [PATCH 09/11] resolved comments Signed-off-by: wangxiaoxuan273 --- registry.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/registry.go b/registry.go index 234af80..392dcfc 100644 --- a/registry.go +++ b/registry.go @@ -75,20 +75,20 @@ func Credential(store Store) func(context.Context, string) (auth.Credential, err } } -// The Docker CLI expects that the 'docker.io' credential -// will be added under the key "https://index.docker.io/v1/" func mapStoreRegistryName(registry string) string { + // The Docker CLI expects that the 'docker.io' credential + // will be added under the key "https://index.docker.io/v1/" if registry == "docker.io" { return "https://index.docker.io/v1/" } return registry } -// It is expected that the traffic targetting "registry-1.docker.io" -// will be redirected to "https://index.docker.io/v1/" -func mapAuthenticationRegistryName(target string) string { - if target == "registry-1.docker.io" { +func mapAuthenticationRegistryName(hostname string) string { + // It is expected that the traffic targetting "registry-1.docker.io" + // will be redirected to "https://index.docker.io/v1/" + if hostname == "registry-1.docker.io" { return "https://index.docker.io/v1/" } - return target + return hostname } From 4a7bf460cde1de47c5715e7899bb189e97878a5d Mon Sep 17 00:00:00 2001 From: wangxiaoxuan273 Date: Thu, 20 Apr 2023 07:08:42 +0000 Subject: [PATCH 10/11] resolved comments Signed-off-by: wangxiaoxuan273 --- registry.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/registry.go b/registry.go index 392dcfc..2ba405a 100644 --- a/registry.go +++ b/registry.go @@ -78,6 +78,7 @@ func Credential(store Store) func(context.Context, string) (auth.Credential, err func mapStoreRegistryName(registry string) string { // The Docker CLI expects that the 'docker.io' credential // will be added under the key "https://index.docker.io/v1/" + // See: https://github.com/moby/moby/blob/master/registry/config.go#L25-L48 if registry == "docker.io" { return "https://index.docker.io/v1/" } @@ -87,6 +88,7 @@ func mapStoreRegistryName(registry string) string { func mapAuthenticationRegistryName(hostname string) string { // It is expected that the traffic targetting "registry-1.docker.io" // will be redirected to "https://index.docker.io/v1/" + // See: https://github.com/moby/moby/blob/master/registry/config.go#L25-L48 if hostname == "registry-1.docker.io" { return "https://index.docker.io/v1/" } From 086f9b2c5827ea8a27b3a46c0e2e689085fc0a57 Mon Sep 17 00:00:00 2001 From: wangxiaoxuan273 Date: Thu, 20 Apr 2023 09:07:12 +0000 Subject: [PATCH 11/11] updated reference link Signed-off-by: wangxiaoxuan273 --- registry.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry.go b/registry.go index 2ba405a..0f6b5bb 100644 --- a/registry.go +++ b/registry.go @@ -78,7 +78,7 @@ func Credential(store Store) func(context.Context, string) (auth.Credential, err func mapStoreRegistryName(registry string) string { // The Docker CLI expects that the 'docker.io' credential // will be added under the key "https://index.docker.io/v1/" - // See: https://github.com/moby/moby/blob/master/registry/config.go#L25-L48 + // See: https://github.com/moby/moby/blob/v24.0.0-beta.2/registry/config.go#L25-L48 if registry == "docker.io" { return "https://index.docker.io/v1/" } @@ -88,7 +88,7 @@ func mapStoreRegistryName(registry string) string { func mapAuthenticationRegistryName(hostname string) string { // It is expected that the traffic targetting "registry-1.docker.io" // will be redirected to "https://index.docker.io/v1/" - // See: https://github.com/moby/moby/blob/master/registry/config.go#L25-L48 + // See: https://github.com/moby/moby/blob/v24.0.0-beta.2/registry/config.go#L25-L48 if hostname == "registry-1.docker.io" { return "https://index.docker.io/v1/" }