feat(helm): Support Bearer token auth when get chart

Signed-off-by: lemonli <liwenjun0323@gmail.com>
pull/10848/head
lemonli 5 years ago committed by Zack Brown
parent cba3b1eed4
commit d78b81e295

@ -60,7 +60,7 @@ func addChartPathOptionsFlags(f *pflag.FlagSet, c *action.ChartPathOptions) {
f.StringVar(&c.KeyFile, "key-file", "", "identify HTTPS client using this SSL key file") f.StringVar(&c.KeyFile, "key-file", "", "identify HTTPS client using this SSL key file")
f.BoolVar(&c.InsecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart download") f.BoolVar(&c.InsecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart download")
f.StringVar(&c.CaFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.StringVar(&c.CaFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
f.BoolVar(&c.PassCredentialsAll, "pass-credentials", false, "pass credentials to all domains") f.StringVar(&c.Token, "token", "", "chart repository bearer token where to locate the requested chart")
} }
// bindOutputFlag will add the output flag to the given command and bind the // bindOutputFlag will add the output flag to the given command and bind the

@ -63,6 +63,8 @@ type repoAddOptions struct {
// Deprecated, but cannot be removed until Helm 4 // Deprecated, but cannot be removed until Helm 4
deprecatedNoUpdate bool deprecatedNoUpdate bool
tokenFromStdin bool
} }
func newRepoAddCmd(out io.Writer) *cobra.Command { func newRepoAddCmd(out io.Writer) *cobra.Command {
@ -78,7 +80,6 @@ func newRepoAddCmd(out io.Writer) *cobra.Command {
o.url = args[1] o.url = args[1]
o.repoFile = settings.RepositoryConfig o.repoFile = settings.RepositoryConfig
o.repoCache = settings.RepositoryCache o.repoCache = settings.RepositoryCache
return o.run(out) return o.run(out)
}, },
} }
@ -94,7 +95,7 @@ func newRepoAddCmd(out io.Writer) *cobra.Command {
f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
f.BoolVar(&o.insecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the repository") f.BoolVar(&o.insecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the repository")
f.BoolVar(&o.allowDeprecatedRepos, "allow-deprecated-repos", false, "by default, this command will not allow adding official repos that have been permanently deleted. This disables that behavior") f.BoolVar(&o.allowDeprecatedRepos, "allow-deprecated-repos", false, "by default, this command will not allow adding official repos that have been permanently deleted. This disables that behavior")
f.BoolVar(&o.passCredentialsAll, "pass-credentials", false, "pass credentials to all domains") f.BoolVar(&o.tokenFromStdin, "token-stdin", false, "read chart repository bearer token from stdin")
return cmd return cmd
} }
@ -165,6 +166,16 @@ func (o *repoAddOptions) run(out io.Writer) error {
} }
} }
var token string
if o.tokenFromStdin {
tokenStdin, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return err
}
token = strings.TrimSuffix(string(tokenStdin), "\n")
token = strings.TrimSuffix(token, "\r")
}
c := repo.Entry{ c := repo.Entry{
Name: o.name, Name: o.name,
URL: o.url, URL: o.url,
@ -175,6 +186,7 @@ func (o *repoAddOptions) run(out io.Writer) error {
KeyFile: o.keyFile, KeyFile: o.keyFile,
CAFile: o.caFile, CAFile: o.caFile,
InsecureSkipTLSverify: o.insecureSkipTLSverify, InsecureSkipTLSverify: o.insecureSkipTLSverify,
Token: token,
} }
// Check if the repo name is legal // Check if the repo name is legal

@ -117,10 +117,7 @@ type ChartPathOptions struct {
Username string // --username Username string // --username
Verify bool // --verify Verify bool // --verify
Version string // --version Version string // --version
Token string // --token
// registryClient provides a registry client but is not added with
// options from a flag
registryClient *registry.Client
} }
// NewInstall creates a new Install object with the given configuration. // NewInstall creates a new Install object with the given configuration.
@ -706,6 +703,7 @@ func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) (
getter.WithPassCredentialsAll(c.PassCredentialsAll), getter.WithPassCredentialsAll(c.PassCredentialsAll),
getter.WithTLSClientConfig(c.CertFile, c.KeyFile, c.CaFile), getter.WithTLSClientConfig(c.CertFile, c.KeyFile, c.CaFile),
getter.WithInsecureSkipVerifyTLS(c.InsecureSkipTLSverify), getter.WithInsecureSkipVerifyTLS(c.InsecureSkipTLSverify),
getter.WithBearerToken(c.Token),
}, },
RepositoryConfig: settings.RepositoryConfig, RepositoryConfig: settings.RepositoryConfig,
RepositoryCache: settings.RepositoryCache, RepositoryCache: settings.RepositoryCache,
@ -716,8 +714,15 @@ func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) (
dl.Verify = downloader.VerifyAlways dl.Verify = downloader.VerifyAlways
} }
if c.RepoURL != "" { if c.RepoURL != "" {
chartURL, err := repo.FindChartInAuthAndTLSAndPassRepoURL(c.RepoURL, c.Username, c.Password, name, version, chartURL, err := repo.FindChartInRepoURLWithAuth(
c.CertFile, c.KeyFile, c.CaFile, c.InsecureSkipTLSverify, c.PassCredentialsAll, getter.All(settings)) getter.All(settings),
repo.WithRepoURL(c.RepoURL),
repo.WithChartInfo(name, version),
repo.WithTLSClientConfig(c.CertFile, c.KeyFile, c.CaFile),
repo.WithBasicAuth(c.Username, c.Password),
repo.WithBearerToken(c.Token),
repo.WithInsecureSkipVerifyTLS(c.InsecureSkipTLSverify),
)
if err != nil { if err != nil {
return "", err return "", err
} }

@ -86,6 +86,7 @@ func (p *Pull) Run(chartRef string) (string, error) {
getter.WithPassCredentialsAll(p.PassCredentialsAll), getter.WithPassCredentialsAll(p.PassCredentialsAll),
getter.WithTLSClientConfig(p.CertFile, p.KeyFile, p.CaFile), getter.WithTLSClientConfig(p.CertFile, p.KeyFile, p.CaFile),
getter.WithInsecureSkipVerifyTLS(p.InsecureSkipTLSverify), getter.WithInsecureSkipVerifyTLS(p.InsecureSkipTLSverify),
getter.WithBearerToken(p.Token),
}, },
RegistryClient: p.cfg.RegistryClient, RegistryClient: p.cfg.RegistryClient,
RepositoryConfig: p.Settings.RepositoryConfig, RepositoryConfig: p.Settings.RepositoryConfig,
@ -116,7 +117,15 @@ func (p *Pull) Run(chartRef string) (string, error) {
} }
if p.RepoURL != "" { if p.RepoURL != "" {
chartURL, err := repo.FindChartInAuthAndTLSAndPassRepoURL(p.RepoURL, p.Username, p.Password, chartRef, p.Version, p.CertFile, p.KeyFile, p.CaFile, p.InsecureSkipTLSverify, p.PassCredentialsAll, getter.All(p.Settings)) chartURL, err := repo.FindChartInRepoURLWithAuth(
getter.All(p.Settings),
repo.WithRepoURL(p.RepoURL),
repo.WithChartInfo(chartRef, p.Version),
repo.WithTLSClientConfig(p.CertFile, p.KeyFile, p.CaFile),
repo.WithBasicAuth(p.Username, p.Password),
repo.WithBearerToken(p.Token),
repo.WithInsecureSkipVerifyTLS(p.InsecureSkipTLSverify),
)
if err != nil { if err != nil {
return out.String(), err return out.String(), err
} }

@ -239,6 +239,13 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er
getter.WithPassCredentialsAll(rc.PassCredentialsAll), getter.WithPassCredentialsAll(rc.PassCredentialsAll),
) )
} }
if rc.Token != "" {
c.Options = append(
c.Options,
getter.WithBearerToken(rc.Token),
)
}
return u, nil return u, nil
} }
@ -275,6 +282,9 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er
getter.WithPassCredentialsAll(r.Config.PassCredentialsAll), getter.WithPassCredentialsAll(r.Config.PassCredentialsAll),
) )
} }
if r.Config.Token != "" {
c.Options = append(c.Options, getter.WithBearerToken(r.Config.Token))
}
} }
// Next, we need to load the index, and actually look up the chart. // Next, we need to load the index, and actually look up the chart.

@ -18,6 +18,7 @@ package downloader
import ( import (
"os" "os"
"path/filepath" "path/filepath"
"strings"
"testing" "testing"
"helm.sh/helm/v3/internal/test/ensure" "helm.sh/helm/v3/internal/test/ensure"
@ -311,6 +312,63 @@ func TestDownloadTo_VerifyLater(t *testing.T) {
} }
} }
func TestDownloadTo_Token(t *testing.T) {
// Set up a fake repo with bearer auth enabled
srv, err := repotest.NewTempServerWithCleanup(t, "testdata/*.tgz*")
srv.Stop()
if err != nil {
t.Fatal(err)
}
srv.WithMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := strings.Split(r.Header.Get("Authorization"), "Bearer ")
if len(token) != 2 || strings.TrimSpace(token[1]) != "JWT" {
t.Errorf("Expected request to use bearer token and for token == 'JWT' got '%s'", token)
}
}))
srv.Start()
defer srv.Stop()
if err := srv.CreateIndex(); err != nil {
t.Fatal(err)
}
if err := srv.LinkIndices(); err != nil {
t.Fatal(err)
}
c := ChartDownloader{
Out: os.Stderr,
Verify: VerifyAlways,
Keyring: "testdata/helm-test-key.pub",
RepositoryConfig: repoConfig,
RepositoryCache: repoCache,
Getters: getter.All(&cli.EnvSettings{
RepositoryConfig: repoConfig,
RepositoryCache: repoCache,
}),
Options: []getter.Option{
getter.WithBearerToken("JWT"),
},
}
cname := "/signtest-0.1.0.tgz"
dest := srv.Root()
where, v, err := c.DownloadTo(srv.URL()+cname, "", dest)
if err != nil {
t.Fatal(err)
}
if expect := filepath.Join(dest, cname); where != expect {
t.Errorf("Expected download to %s, got %s", expect, where)
}
if v.FileHash == "" {
t.Error("File hash was empty, but verification is required.")
}
if _, err := os.Stat(filepath.Join(dest, cname)); err != nil {
t.Error(err)
}
}
func TestScanReposForURL(t *testing.T) { func TestScanReposForURL(t *testing.T) {
c := ChartDownloader{ c := ChartDownloader{
Out: os.Stderr, Out: os.Stderr,

@ -313,7 +313,7 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error {
// Any failure to resolve/download a chart should fail: // Any failure to resolve/download a chart should fail:
// https://github.com/helm/helm/issues/1439 // https://github.com/helm/helm/issues/1439
churl, username, password, insecureskiptlsverify, passcredentialsall, caFile, certFile, keyFile, err := m.findChartURL(dep.Name, dep.Version, dep.Repository, repos) churl, username, password, token, err := m.findChartURL(dep.Name, dep.Version, dep.Repository, repos)
if err != nil { if err != nil {
saveError = errors.Wrapf(err, "could not find %s", churl) saveError = errors.Wrapf(err, "could not find %s", churl)
break break
@ -336,9 +336,7 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error {
Getters: m.Getters, Getters: m.Getters,
Options: []getter.Option{ Options: []getter.Option{
getter.WithBasicAuth(username, password), getter.WithBasicAuth(username, password),
getter.WithPassCredentialsAll(passcredentialsall), getter.WithBearerToken(token),
getter.WithInsecureSkipVerifyTLS(insecureskiptlsverify),
getter.WithTLSClientConfig(certFile, keyFile, caFile),
}, },
} }
@ -703,11 +701,7 @@ func (m *Manager) parallelRepoUpdate(repos []*repo.Entry) error {
// repoURL is the repository to search // repoURL is the repository to search
// //
// If it finds a URL that is "relative", it will prepend the repoURL. // If it finds a URL that is "relative", it will prepend the repoURL.
func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRepository) (url, username, password string, insecureskiptlsverify, passcredentialsall bool, caFile, certFile, keyFile string, err error) { func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRepository) (url, username, password, token string, err error) {
if registry.IsOCI(repoURL) {
return fmt.Sprintf("%s/%s:%s", repoURL, name, version), "", "", false, false, "", "", "", nil
}
for _, cr := range repos { for _, cr := range repos {
if urlutil.Equal(repoURL, cr.Config.URL) { if urlutil.Equal(repoURL, cr.Config.URL) {
@ -727,11 +721,7 @@ func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*
} }
username = cr.Config.Username username = cr.Config.Username
password = cr.Config.Password password = cr.Config.Password
passcredentialsall = cr.Config.PassCredentialsAll token = cr.Config.Token
insecureskiptlsverify = cr.Config.InsecureSkipTLSverify
caFile = cr.Config.CAFile
certFile = cr.Config.CertFile
keyFile = cr.Config.KeyFile
return return
} }
} }

@ -84,7 +84,7 @@ func TestFindChartURL(t *testing.T) {
version := "0.1.0" version := "0.1.0"
repoURL := "http://example.com/charts" repoURL := "http://example.com/charts"
churl, username, password, insecureSkipTLSVerify, passcredentialsall, _, _, _, err := m.findChartURL(name, version, repoURL, repos) churl, username, password, token, err := m.findChartURL(name, version, repoURL, repos)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -98,36 +98,8 @@ func TestFindChartURL(t *testing.T) {
if password != "" { if password != "" {
t.Errorf("Unexpected password %q", password) t.Errorf("Unexpected password %q", password)
} }
if passcredentialsall != false { if token != "" {
t.Errorf("Unexpected passcredentialsall %t", passcredentialsall) t.Errorf("Unexpected token %q", token)
}
if insecureSkipTLSVerify {
t.Errorf("Unexpected insecureSkipTLSVerify %t", insecureSkipTLSVerify)
}
name = "tlsfoo"
version = "1.2.3"
repoURL = "https://example-https-insecureskiptlsverify.com"
churl, username, password, insecureSkipTLSVerify, passcredentialsall, _, _, _, err = m.findChartURL(name, version, repoURL, repos)
if err != nil {
t.Fatal(err)
}
if !insecureSkipTLSVerify {
t.Errorf("Unexpected insecureSkipTLSVerify %t", insecureSkipTLSVerify)
}
if churl != "https://example.com/tlsfoo-1.2.3.tgz" {
t.Errorf("Unexpected URL %q", churl)
}
if username != "" {
t.Errorf("Unexpected username %q", username)
}
if password != "" {
t.Errorf("Unexpected password %q", password)
}
if passcredentialsall != false {
t.Errorf("Unexpected passcredentialsall %t", passcredentialsall)
} }
} }

@ -21,6 +21,6 @@ repositories:
certFile: "cert" certFile: "cert"
keyFile: "key" keyFile: "key"
caFile: "ca" caFile: "ca"
- name: testing-https-insecureskip-tls-verify - name: testing-token
url: "https://example-https-insecureskiptlsverify.com" url: "http://example.com"
insecure_skip_tls_verify: true token: "JWT"

@ -0,0 +1,14 @@
apiVersion: v1
entries:
foo:
- name: foo
description: Foo Chart
home: https://helm.sh/helm
keywords: []
maintainers: []
sources:
- https://github.com/helm/charts
urls:
- http://example.com/foo-1.2.3.tgz
version: 1.2.3
checksum: 0e6661f193211d7a5206918d42f5c2a9470b737d

@ -44,7 +44,7 @@ type options struct {
version string version string
registryClient *registry.Client registryClient *registry.Client
timeout time.Duration timeout time.Duration
transport *http.Transport token string
} }
// Option allows specifying various settings configurable by the user for overriding the defaults // Option allows specifying various settings configurable by the user for overriding the defaults
@ -96,6 +96,13 @@ func WithTLSClientConfig(certFile, keyFile, caFile string) Option {
} }
} }
// WithBearerToken sets the request's Authorization header to use the provided token
func WithBearerToken(token string) Option {
return func(opts *options) {
opts.token = token
}
}
// WithTimeout sets the timeout for requests // WithTimeout sets the timeout for requests
func WithTimeout(timeout time.Duration) Option { func WithTimeout(timeout time.Duration) Option {
return func(opts *options) { return func(opts *options) {

@ -18,6 +18,7 @@ package getter
import ( import (
"bytes" "bytes"
"crypto/tls" "crypto/tls"
"fmt"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
@ -78,6 +79,10 @@ func (g *HTTPGetter) get(href string) (*bytes.Buffer, error) {
} }
} }
if g.opts.token != "" {
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", g.opts.token))
}
client, err := g.httpClient() client, err := g.httpClient()
if err != nil { if err != nil {
return nil, err return nil, err

@ -60,7 +60,7 @@ func TestHTTPGetter(t *testing.T) {
WithTLSClientConfig(pub, priv, ca), WithTLSClientConfig(pub, priv, ca),
WithInsecureSkipVerifyTLS(insecure), WithInsecureSkipVerifyTLS(insecure),
WithTimeout(timeout), WithTimeout(timeout),
WithTransport(transport), WithBearerToken("JWT"),
) )
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -107,8 +107,8 @@ func TestHTTPGetter(t *testing.T) {
t.Errorf("Expected NewHTTPGetter to contain %s as Timeout flag, got %s", timeout, hg.opts.timeout) t.Errorf("Expected NewHTTPGetter to contain %s as Timeout flag, got %s", timeout, hg.opts.timeout)
} }
if hg.opts.transport != transport { if hg.opts.token != "JWT" {
t.Errorf("Expected NewHTTPGetter to contain %p as Transport, got %p", transport, hg.opts.transport) t.Errorf("Expected NewHTTPGetter to contain %s as the token, got %s", "JWT", hg.opts.token)
} }
// Test if setting insecureSkipVerifyTLS is being passed to the ops // Test if setting insecureSkipVerifyTLS is being passed to the ops
@ -363,6 +363,64 @@ func TestDownloadInsecureSkipTLSVerify(t *testing.T) {
} }
func TestDownloadToken(t *testing.T) {
expect := "Call me Ishmael"
expectedUserAgent := "I am Groot"
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defaultUserAgent := "Helm/" + strings.TrimPrefix(version.GetVersion(), "v")
if r.UserAgent() != defaultUserAgent {
t.Errorf("Expected '%s', got '%s'", defaultUserAgent, r.UserAgent())
}
fmt.Fprint(w, expect)
}))
defer srv.Close()
g, err := All(cli.New()).ByScheme("http")
if err != nil {
t.Fatal(err)
}
got, err := g.Get(srv.URL, WithURL(srv.URL))
if err != nil {
t.Fatal(err)
}
if got.String() != expect {
t.Errorf("Expected %q, got %q", expect, got.String())
}
// test with http server
tokenSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := strings.Split(r.Header.Get("Authorization"), "Bearer ")
if len(token) != 2 || strings.TrimSpace(token[1]) != "JWT" {
t.Errorf("Expected request to use bearer token and for token == 'JWT' got '%s'", token)
}
if r.UserAgent() != expectedUserAgent {
t.Errorf("Expected '%s', got '%s'", expectedUserAgent, r.UserAgent())
}
fmt.Fprint(w, expect)
}))
defer tokenSrv.Close()
u, _ := url.ParseRequestURI(tokenSrv.URL)
httpgetter, err := NewHTTPGetter(
WithURL(u.String()),
WithBearerToken("JWT"),
WithUserAgent(expectedUserAgent),
)
if err != nil {
t.Fatal(err)
}
got, err = httpgetter.Get(u.String())
if err != nil {
t.Fatal(err)
}
if got.String() != expect {
t.Errorf("Expected %q, got %q", expect, got.String())
}
}
func TestHTTPGetterTarDownload(t *testing.T) { func TestHTTPGetterTarDownload(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
f, _ := os.Open("testdata/empty-0.0.1.tgz") f, _ := os.Open("testdata/empty-0.0.1.tgz")

@ -48,7 +48,7 @@ type Entry struct {
KeyFile string `json:"keyFile"` KeyFile string `json:"keyFile"`
CAFile string `json:"caFile"` CAFile string `json:"caFile"`
InsecureSkipTLSverify bool `json:"insecure_skip_tls_verify"` InsecureSkipTLSverify bool `json:"insecure_skip_tls_verify"`
PassCredentialsAll bool `json:"pass_credentials_all"` Token string `json:"token"`
} }
// ChartRepository represents a chart repository // ChartRepository represents a chart repository
@ -60,6 +60,70 @@ type ChartRepository struct {
CachePath string CachePath string
} }
// options are generic parameters to be provided to find chart.
type options struct {
chartName string
chartVersion string
repoURL string
certFile string
keyFile string
caFile string
username string
password string
token string
insecureSkipTLSverify bool
}
// Option allows specifying various settings configurable by the user for overriding the defaults
// used when performing find chart.
type Option func(*options)
// WithChartInfo informs the chart info.
func WithChartInfo(chartName, chartVersion string) Option {
return func(opts *options) {
opts.chartName = chartName
opts.chartVersion = chartVersion
}
}
// WithRepoURL informs the repo url that will be used when find chart.
func WithRepoURL(url string) Option {
return func(opts *options) {
opts.repoURL = url
}
}
// WithBasicAuth sets the request's Authorization header to use the provided credentials
func WithBasicAuth(username, password string) Option {
return func(opts *options) {
opts.username = username
opts.password = password
}
}
// WithTLSClientConfig sets the client auth with the provided credentials.
func WithTLSClientConfig(certFile, keyFile, caFile string) Option {
return func(opts *options) {
opts.certFile = certFile
opts.keyFile = keyFile
opts.caFile = caFile
}
}
// WithBearerToken sets the request's Authorization header to use the provided token
func WithBearerToken(token string) Option {
return func(opts *options) {
opts.token = token
}
}
// WithInsecureSkipVerifyTLS determines if a TLS Certificate will be checked
func WithInsecureSkipVerifyTLS(insecureSkipTLSverify bool) Option {
return func(opts *options) {
opts.insecureSkipTLSverify = insecureSkipTLSverify
}
}
// NewChartRepository constructs ChartRepository // NewChartRepository constructs ChartRepository
func NewChartRepository(cfg *Entry, getters getter.Providers) (*ChartRepository, error) { func NewChartRepository(cfg *Entry, getters getter.Providers) (*ChartRepository, error) {
u, err := url.Parse(cfg.URL) u, err := url.Parse(cfg.URL)
@ -130,7 +194,7 @@ func (r *ChartRepository) DownloadIndexFile() (string, error) {
getter.WithInsecureSkipVerifyTLS(r.Config.InsecureSkipTLSverify), getter.WithInsecureSkipVerifyTLS(r.Config.InsecureSkipTLSverify),
getter.WithTLSClientConfig(r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile), getter.WithTLSClientConfig(r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile),
getter.WithBasicAuth(r.Config.Username, r.Config.Password), getter.WithBasicAuth(r.Config.Username, r.Config.Password),
getter.WithPassCredentialsAll(r.Config.PassCredentialsAll), getter.WithBearerToken(r.Config.Token),
) )
if err != nil { if err != nil {
return "", err return "", err
@ -204,14 +268,33 @@ func (r *ChartRepository) generateIndex() error {
// FindChartInRepoURL finds chart in chart repository pointed by repoURL // FindChartInRepoURL finds chart in chart repository pointed by repoURL
// without adding repo to repositories // without adding repo to repositories
func FindChartInRepoURL(repoURL, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) { func FindChartInRepoURL(repoURL, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) {
return FindChartInAuthRepoURL(repoURL, "", "", chartName, chartVersion, certFile, keyFile, caFile, getters) return FindChartInRepoURLWithAuth(
getters,
WithRepoURL(repoURL),
WithChartInfo(chartName, chartVersion),
WithTLSClientConfig(certFile, keyFile, caFile),
)
} }
// FindChartInAuthRepoURL finds chart in chart repository pointed by repoURL // FindChartInAuthRepoURL finds chart in chart repository pointed by repoURL
// without adding repo to repositories, like FindChartInRepoURL, // without adding repo to repositories, like FindChartInRepoURL,
// but it also receives credentials for the chart repository. // but it also receives credentials for the chart repository.
// Deprecated: this function is deprecated and will be removed in Helm 4, please use FindChartInRepoURLWithAuth instead.
func FindChartInAuthRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) { func FindChartInAuthRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) {
return FindChartInAuthAndTLSRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile, false, getters) return findChartInAuthRepoURL(
getters,
WithRepoURL(repoURL),
WithChartInfo(chartName, chartVersion),
WithBasicAuth(username, password),
WithTLSClientConfig(certFile, keyFile, caFile),
)
}
// FindChartInRepoURLWithAuth finds chart in chart repository pointed by repoURL
// without adding repo to repositories, like FindChartInRepoURL,
// but it also receives credentials for the chart repository.
func FindChartInRepoURLWithAuth(getters getter.Providers, opts ...Option) (string, error) {
return findChartInAuthRepoURL(getters, opts...)
} }
// FindChartInAuthAndTLSRepoURL finds chart in chart repository pointed by repoURL // FindChartInAuthAndTLSRepoURL finds chart in chart repository pointed by repoURL
@ -219,31 +302,37 @@ func FindChartInAuthRepoURL(repoURL, username, password, chartName, chartVersion
// but it also receives credentials and TLS verify flag for the chart repository. // but it also receives credentials and TLS verify flag for the chart repository.
// TODO Helm 4, FindChartInAuthAndTLSRepoURL should be integrated into FindChartInAuthRepoURL. // TODO Helm 4, FindChartInAuthAndTLSRepoURL should be integrated into FindChartInAuthRepoURL.
func FindChartInAuthAndTLSRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile string, insecureSkipTLSverify bool, getters getter.Providers) (string, error) { func FindChartInAuthAndTLSRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile string, insecureSkipTLSverify bool, getters getter.Providers) (string, error) {
return FindChartInAuthAndTLSAndPassRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile, false, false, getters) return findChartInAuthRepoURL(
getters,
WithRepoURL(repoURL),
WithChartInfo(chartName, chartVersion),
WithBasicAuth(username, password),
WithTLSClientConfig(certFile, keyFile, caFile),
WithInsecureSkipVerifyTLS(insecureSkipTLSverify),
)
} }
// FindChartInAuthAndTLSAndPassRepoURL finds chart in chart repository pointed by repoURL func findChartInAuthRepoURL(getters getter.Providers, opts ...Option) (string, error) {
// without adding repo to repositories, like FindChartInRepoURL,
// but it also receives credentials, TLS verify flag, and if credentials should
// be passed on to other domains.
// TODO Helm 4, FindChartInAuthAndTLSAndPassRepoURL should be integrated into FindChartInAuthRepoURL.
func FindChartInAuthAndTLSAndPassRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile string, insecureSkipTLSverify, passCredentialsAll bool, getters getter.Providers) (string, error) {
// Download and write the index file to a temporary location // Download and write the index file to a temporary location
buf := make([]byte, 20) buf := make([]byte, 20)
rand.Read(buf) rand.Read(buf)
name := strings.ReplaceAll(base64.StdEncoding.EncodeToString(buf), "/", "-") name := strings.ReplaceAll(base64.StdEncoding.EncodeToString(buf), "/", "-")
repoOpts := options{}
for _, opt := range opts {
opt(&repoOpts)
}
c := Entry{ c := Entry{
URL: repoURL,
Username: username,
Password: password,
PassCredentialsAll: passCredentialsAll,
CertFile: certFile,
KeyFile: keyFile,
CAFile: caFile,
Name: name, Name: name,
InsecureSkipTLSverify: insecureSkipTLSverify, URL: repoOpts.repoURL,
Username: repoOpts.username,
Password: repoOpts.password,
CertFile: repoOpts.certFile,
KeyFile: repoOpts.keyFile,
CAFile: repoOpts.caFile,
Token: repoOpts.token,
InsecureSkipTLSverify: repoOpts.insecureSkipTLSverify,
} }
r, err := NewChartRepository(&c, getters) r, err := NewChartRepository(&c, getters)
if err != nil { if err != nil {
@ -251,7 +340,7 @@ func FindChartInAuthAndTLSAndPassRepoURL(repoURL, username, password, chartName,
} }
idx, err := r.DownloadIndexFile() idx, err := r.DownloadIndexFile()
if err != nil { if err != nil {
return "", errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", repoURL) return "", errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", repoOpts.repoURL)
} }
// Read the index file for the repository to get chart information and return chart URL // Read the index file for the repository to get chart information and return chart URL
@ -260,13 +349,13 @@ func FindChartInAuthAndTLSAndPassRepoURL(repoURL, username, password, chartName,
return "", err return "", err
} }
errMsg := fmt.Sprintf("chart %q", chartName) errMsg := fmt.Sprintf("chart %q", repoOpts.chartName)
if chartVersion != "" { if repoOpts.chartVersion != "" {
errMsg = fmt.Sprintf("%s version %q", errMsg, chartVersion) errMsg = fmt.Sprintf("%s version %q", errMsg, repoOpts.chartVersion)
} }
cv, err := repoIndex.Get(chartName, chartVersion) cv, err := repoIndex.Get(repoOpts.chartName, repoOpts.chartVersion)
if err != nil { if err != nil {
return "", errors.Errorf("%s not found in %s repository", errMsg, repoURL) return "", errors.Errorf("%s not found in %s repository", errMsg, repoOpts.repoURL)
} }
if len(cv.URLs) == 0 { if len(cv.URLs) == 0 {
@ -275,7 +364,7 @@ func FindChartInAuthAndTLSAndPassRepoURL(repoURL, username, password, chartName,
chartURL := cv.URLs[0] chartURL := cv.URLs[0]
absoluteChartURL, err := ResolveReferenceURL(repoURL, chartURL) absoluteChartURL, err := ResolveReferenceURL(repoOpts.repoURL, chartURL)
if err != nil { if err != nil {
return "", errors.Wrap(err, "failed to make chart URL absolute") return "", errors.Wrap(err, "failed to make chart URL absolute")
} }

Loading…
Cancel
Save