fix(main): fix basic auth for helm pull or push

Signed-off-by: cuisongliu <cuisongliu@qq.com>
pull/12237/head
cuisongliu 2 years ago
parent 32c7e37e32
commit 4a27baaffc

@ -59,7 +59,7 @@ type (
out io.Writer out io.Writer
authorizer auth.Client authorizer auth.Client
registryAuthorizer *registryauth.Client registryAuthorizer *registryauth.Client
resolver remotes.Resolver resolver func(ref registry.Reference) (remotes.Resolver, error)
httpClient *http.Client httpClient *http.Client
} }
@ -86,9 +86,23 @@ func NewClient(options ...ClientOption) (*Client, error) {
} }
client.authorizer = authClient client.authorizer = authClient
} }
if client.resolver == nil { client.resolver = func(ref registry.Reference) (remotes.Resolver, error) {
headers := http.Header{} headers := http.Header{}
headers.Set("User-Agent", version.GetUserAgent()) headers.Set("User-Agent", version.GetUserAgent())
dockerClient, ok := client.authorizer.(*dockerauth.Client)
if ok {
username, password, err := dockerClient.Credential(ref.Registry)
if err != nil {
return nil, errors.New("unable to retrieve credentials")
}
// A blank returned username and password value is a bearer token
if username == "" && password != "" {
headers.Set("Authorization", fmt.Sprintf("Bearer %s", password))
} else {
headers.Set("Authorization", fmt.Sprintf("Basic %s", basicAuth(username, password)))
}
}
opts := []auth.ResolverOption{auth.WithResolverHeaders(headers)} opts := []auth.ResolverOption{auth.WithResolverHeaders(headers)}
if client.httpClient != nil { if client.httpClient != nil {
opts = append(opts, auth.WithResolverClient(client.httpClient)) opts = append(opts, auth.WithResolverClient(client.httpClient))
@ -97,9 +111,8 @@ func NewClient(options ...ClientOption) (*Client, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
client.resolver = resolver return resolver, nil
} }
// allocate a cache if option is set // allocate a cache if option is set
var cache registryauth.Cache var cache registryauth.Cache
if client.enableCache { if client.enableCache {
@ -117,7 +130,6 @@ func NewClient(options ...ClientOption) (*Client, error) {
if !ok { if !ok {
return registryauth.EmptyCredential, errors.New("unable to obtain docker client") return registryauth.EmptyCredential, errors.New("unable to obtain docker client")
} }
username, password, err := dockerClient.Credential(reg) username, password, err := dockerClient.Credential(reg)
if err != nil { if err != nil {
return registryauth.EmptyCredential, errors.New("unable to retrieve credentials") return registryauth.EmptyCredential, errors.New("unable to retrieve credentials")
@ -324,7 +336,11 @@ func (c *Client) Pull(ref string, options ...PullOption) (*PullResult, error) {
} }
var descriptors, layers []ocispec.Descriptor var descriptors, layers []ocispec.Descriptor
registryStore := content.Registry{Resolver: c.resolver} remotesResolver, err := c.resolver(parsedRef)
if err != nil {
return nil, err
}
registryStore := content.Registry{Resolver: remotesResolver}
manifest, err := oras.Copy(ctx(c.out, c.debug), registryStore, parsedRef.String(), memoryStore, "", manifest, err := oras.Copy(ctx(c.out, c.debug), registryStore, parsedRef.String(), memoryStore, "",
oras.WithPullEmptyNameAllowed(), oras.WithPullEmptyNameAllowed(),
@ -562,8 +578,11 @@ func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResu
if err := memoryStore.StoreManifest(parsedRef.String(), manifest, manifestData); err != nil { if err := memoryStore.StoreManifest(parsedRef.String(), manifest, manifestData); err != nil {
return nil, err return nil, err
} }
remotesResolver, err := c.resolver(parsedRef)
registryStore := content.Registry{Resolver: c.resolver} if err != nil {
return nil, err
}
registryStore := content.Registry{Resolver: remotesResolver}
_, err = oras.Copy(ctx(c.out, c.debug), memoryStore, parsedRef.String(), registryStore, "", _, err = oras.Copy(ctx(c.out, c.debug), memoryStore, parsedRef.String(), registryStore, "",
oras.WithNameValidation(nil)) oras.WithNameValidation(nil))
if err != nil { if err != nil {

@ -19,6 +19,7 @@ package registry // import "helm.sh/helm/v3/pkg/registry"
import ( import (
"bytes" "bytes"
"context" "context"
"encoding/base64"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
@ -245,3 +246,13 @@ func addToMap(inputMap map[string]string, newKey string, newValue string) map[st
return inputMap return inputMap
} }
// See 2 (end of page 4) https://www.ietf.org/rfc/rfc2617.txt
// "To receive authorization, the client sends the userid and password,
// separated by a single colon (":") character, within a base64
// encoded string in the credentials."
// It is not meant to be urlencoded.
func basicAuth(username, password string) string {
auth := username + ":" + password
return base64.StdEncoding.EncodeToString([]byte(auth))
}

@ -238,3 +238,31 @@ func TestGenerateOCICreatedAnnotations(t *testing.T) {
} }
} }
func Test_basicAuth(t *testing.T) {
type args struct {
username string
password string
}
tests := []struct {
name string
args args
want string
}{
{
name: "Basic Auth",
args: args{
username: "admin",
password: "passw0rd",
},
want: "YWRtaW46cGFzc3cwcmQ=",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := basicAuth(tt.args.username, tt.args.password); got != tt.want {
t.Errorf("basicAuth() = %v, want %v", got, tt.want)
}
})
}
}

Loading…
Cancel
Save