Merge pull request from GHSA-56hp-xqp3-w2jf

tweak basic handling
pull/9763/head
Matt Farina 4 years ago committed by GitHub
commit 179f90151d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -57,6 +57,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")
} }
// 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

@ -18,10 +18,36 @@ package main
import ( import (
"fmt" "fmt"
"net/http"
"net/http/httptest"
"testing" "testing"
"helm.sh/helm/v3/pkg/repo/repotest"
) )
func TestInstall(t *testing.T) { func TestInstall(t *testing.T) {
srv, err := repotest.NewTempServerWithCleanup(t, "testdata/testcharts/*.tgz*")
if err != nil {
t.Fatal(err)
}
defer srv.Stop()
srv.WithMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
username, password, ok := r.BasicAuth()
if !ok || username != "username" || password != "password" {
t.Errorf("Expected request to use basic auth and for username == 'username' and password == 'password', got '%v', '%s', '%s'", ok, username, password)
}
}))
srv2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.FileServer(http.Dir(srv.Root())).ServeHTTP(w, r)
}))
defer srv2.Close()
if err := srv.LinkIndices(); err != nil {
t.Fatal(err)
}
tests := []cmdTestCase{ tests := []cmdTestCase{
// Install, base case // Install, base case
{ {
@ -207,6 +233,17 @@ func TestInstall(t *testing.T) {
name: "install chart with only crds", name: "install chart with only crds",
cmd: "install crd-test testdata/testcharts/chart-with-only-crds --namespace default", cmd: "install crd-test testdata/testcharts/chart-with-only-crds --namespace default",
}, },
// Verify the user/pass works
{
name: "basic install with credentials",
cmd: "install aeneas reqtest --namespace default --repo " + srv.URL() + " --username username --password password",
golden: "output/install.txt",
},
{
name: "basic install with credentials",
cmd: "install aeneas reqtest --namespace default --repo " + srv2.URL + " --username username --password password --pass-credentials",
golden: "output/install.txt",
},
} }
runTestActionCmd(t, tests) runTestActionCmd(t, tests)

@ -18,6 +18,8 @@ package main
import ( import (
"fmt" "fmt"
"net/http"
"net/http/httptest"
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
@ -250,6 +252,115 @@ func TestPullCmd(t *testing.T) {
} }
} }
func TestPullWithCredentialsCmd(t *testing.T) {
srv, err := repotest.NewTempServerWithCleanup(t, "testdata/testcharts/*.tgz*")
if err != nil {
t.Fatal(err)
}
defer srv.Stop()
srv.WithMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
username, password, ok := r.BasicAuth()
if !ok || username != "username" || password != "password" {
t.Errorf("Expected request to use basic auth and for username == 'username' and password == 'password', got '%v', '%s', '%s'", ok, username, password)
}
}))
srv2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.FileServer(http.Dir(srv.Root())).ServeHTTP(w, r)
}))
defer srv2.Close()
if err := srv.LinkIndices(); err != nil {
t.Fatal(err)
}
// all flags will get "-d outdir" appended.
tests := []struct {
name string
args string
existFile string
existDir string
wantError bool
wantErrorMsg string
expectFile string
expectDir bool
}{
{
name: "Chart fetch using repo URL",
expectFile: "./signtest-0.1.0.tgz",
args: "signtest --repo " + srv.URL() + " --username username --password password",
},
{
name: "Fail fetching non-existent chart on repo URL",
args: "someChart --repo " + srv.URL() + " --username username --password password",
wantError: true,
},
{
name: "Specific version chart fetch using repo URL",
expectFile: "./signtest-0.1.0.tgz",
args: "signtest --version=0.1.0 --repo " + srv.URL() + " --username username --password password",
},
{
name: "Specific version chart fetch using repo URL",
args: "signtest --version=0.2.0 --repo " + srv.URL() + " --username username --password password",
wantError: true,
},
{
name: "Chart located on different domain with credentials passed",
args: "reqtest --repo " + srv2.URL + " --username username --password password --pass-credentials",
expectFile: "./reqtest-0.1.0.tgz",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
outdir := srv.Root()
cmd := fmt.Sprintf("pull %s -d '%s' --repository-config %s --repository-cache %s --registry-config %s",
tt.args,
outdir,
filepath.Join(outdir, "repositories.yaml"),
outdir,
filepath.Join(outdir, "config.json"),
)
// Create file or Dir before helm pull --untar, see: https://github.com/helm/helm/issues/7182
if tt.existFile != "" {
file := filepath.Join(outdir, tt.existFile)
_, err := os.Create(file)
if err != nil {
t.Fatal(err)
}
}
if tt.existDir != "" {
file := filepath.Join(outdir, tt.existDir)
err := os.Mkdir(file, 0755)
if err != nil {
t.Fatal(err)
}
}
_, _, err := executeActionCommand(cmd)
if err != nil {
if tt.wantError {
if tt.wantErrorMsg != "" && tt.wantErrorMsg == err.Error() {
t.Fatalf("Actual error %s, not equal to expected error %s", err, tt.wantErrorMsg)
}
return
}
t.Fatalf("%q reported error: %s", tt.name, err)
}
ef := filepath.Join(outdir, tt.expectFile)
fi, err := os.Stat(ef)
if err != nil {
t.Errorf("%q: expected a file at %s. %s", tt.name, ef, err)
}
if fi.IsDir() != tt.expectDir {
t.Errorf("%q: expected directory=%t, but it's not.", tt.name, tt.expectDir)
}
})
}
}
func TestPullVersionCompletion(t *testing.T) { func TestPullVersionCompletion(t *testing.T) {
repoFile := "testdata/helmhome/helm/repositories.yaml" repoFile := "testdata/helmhome/helm/repositories.yaml"
repoCache := "testdata/helmhome/helm/repository" repoCache := "testdata/helmhome/helm/repository"

@ -48,6 +48,7 @@ type repoAddOptions struct {
url string url string
username string username string
password string password string
passCredentialsAll bool
forceUpdate bool forceUpdate bool
allowDeprecatedRepos bool allowDeprecatedRepos bool
@ -91,6 +92,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")
return cmd return cmd
} }
@ -156,6 +158,7 @@ func (o *repoAddOptions) run(out io.Writer) error {
URL: o.url, URL: o.url,
Username: o.username, Username: o.username,
Password: o.password, Password: o.password,
PassCredentialsAll: o.passCredentialsAll,
CertFile: o.certFile, CertFile: o.certFile,
KeyFile: o.keyFile, KeyFile: o.keyFile,
CAFile: o.caFile, CAFile: o.caFile,

@ -20,6 +20,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/url"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
@ -113,6 +114,7 @@ type ChartPathOptions struct {
InsecureSkipTLSverify bool // --insecure-skip-verify InsecureSkipTLSverify bool // --insecure-skip-verify
Keyring string // --keyring Keyring string // --keyring
Password string // --password Password string // --password
PassCredentialsAll bool // --pass-credentials
RepoURL string // --repo RepoURL string // --repo
Username string // --username Username string // --username
Verify bool // --verify Verify bool // --verify
@ -654,7 +656,7 @@ func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) (
Keyring: c.Keyring, Keyring: c.Keyring,
Getters: getter.All(settings), Getters: getter.All(settings),
Options: []getter.Option{ Options: []getter.Option{
getter.WithBasicAuth(c.Username, c.Password), 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),
}, },
@ -665,12 +667,34 @@ 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.FindChartInAuthAndTLSRepoURL(c.RepoURL, c.Username, c.Password, name, version, chartURL, err := repo.FindChartInAuthAndTLSAndPassRepoURL(c.RepoURL, c.Username, c.Password, name, version,
c.CertFile, c.KeyFile, c.CaFile, c.InsecureSkipTLSverify, getter.All(settings)) c.CertFile, c.KeyFile, c.CaFile, c.InsecureSkipTLSverify, c.PassCredentialsAll, getter.All(settings))
if err != nil { if err != nil {
return "", err return "", err
} }
name = chartURL name = chartURL
// Only pass the user/pass on when the user has said to or when the
// location of the chart repo and the chart are the same domain.
u1, err := url.Parse(c.RepoURL)
if err != nil {
return "", err
}
u2, err := url.Parse(chartURL)
if err != nil {
return "", err
}
// Host on URL (returned from url.Parse) contains the port if present.
// This check ensures credentials are not passed between different
// services on different ports.
if c.PassCredentialsAll || (u1.Scheme == u2.Scheme && u1.Host == u2.Host) {
dl.Options = append(dl.Options, getter.WithBasicAuth(c.Username, c.Password))
} else {
dl.Options = append(dl.Options, getter.WithBasicAuth("", ""))
}
} else {
dl.Options = append(dl.Options, getter.WithBasicAuth(c.Username, c.Password))
} }
if err := os.MkdirAll(settings.RepositoryCache, 0755); err != nil { if err := os.MkdirAll(settings.RepositoryCache, 0755); err != nil {

@ -82,6 +82,7 @@ func (p *Pull) Run(chartRef string) (string, error) {
Getters: getter.All(p.Settings), Getters: getter.All(p.Settings),
Options: []getter.Option{ Options: []getter.Option{
getter.WithBasicAuth(p.Username, p.Password), getter.WithBasicAuth(p.Username, p.Password),
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),
}, },
@ -118,7 +119,7 @@ func (p *Pull) Run(chartRef string) (string, error) {
} }
if p.RepoURL != "" { if p.RepoURL != "" {
chartURL, err := repo.FindChartInAuthAndTLSRepoURL(p.RepoURL, p.Username, p.Password, chartRef, p.Version, p.CertFile, p.KeyFile, p.CaFile, p.InsecureSkipTLSverify, getter.All(p.Settings)) 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))
if err != nil { if err != nil {
return out.String(), err return out.String(), err
} }

@ -195,6 +195,7 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er
c.Options = append( c.Options = append(
c.Options, c.Options,
getter.WithBasicAuth(rc.Username, rc.Password), getter.WithBasicAuth(rc.Username, rc.Password),
getter.WithPassCredentialsAll(rc.PassCredentialsAll),
) )
} }
return u, nil return u, nil
@ -224,7 +225,10 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er
c.Options = append(c.Options, getter.WithTLSClientConfig(r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile)) c.Options = append(c.Options, getter.WithTLSClientConfig(r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile))
} }
if r.Config.Username != "" && r.Config.Password != "" { if r.Config.Username != "" && r.Config.Password != "" {
c.Options = append(c.Options, getter.WithBasicAuth(r.Config.Username, r.Config.Password)) c.Options = append(c.Options,
getter.WithBasicAuth(r.Config.Username, r.Config.Password),
getter.WithPassCredentialsAll(r.Config.PassCredentialsAll),
)
} }
} }

@ -205,6 +205,7 @@ func TestDownloadTo(t *testing.T) {
}), }),
Options: []getter.Option{ Options: []getter.Option{
getter.WithBasicAuth("username", "password"), getter.WithBasicAuth("username", "password"),
getter.WithPassCredentialsAll(false),
}, },
} }
cname := "/signtest-0.1.0.tgz" cname := "/signtest-0.1.0.tgz"

@ -310,7 +310,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, err := m.findChartURL(dep.Name, dep.Version, dep.Repository, repos) churl, username, password, insecureskiptlsverify, passcredentialsall, 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
@ -332,6 +332,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.WithInsecureSkipVerifyTLS(insecureskiptlsverify), getter.WithInsecureSkipVerifyTLS(insecureskiptlsverify),
}, },
} }
@ -686,9 +687,9 @@ 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 bool, err error) { func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRepository) (url, username, password string, insecureskiptlsverify, passcredentialsall bool, err error) {
if strings.HasPrefix(repoURL, "oci://") { if strings.HasPrefix(repoURL, "oci://") {
return fmt.Sprintf("%s/%s:%s", repoURL, name, version), "", "", false, nil return fmt.Sprintf("%s/%s:%s", repoURL, name, version), "", "", false, false, nil
} }
for _, cr := range repos { for _, cr := range repos {
@ -710,16 +711,17 @@ 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
insecureskiptlsverify = cr.Config.InsecureSkipTLSverify insecureskiptlsverify = cr.Config.InsecureSkipTLSverify
return return
} }
} }
url, err = repo.FindChartInRepoURL(repoURL, name, version, "", "", "", m.Getters) url, err = repo.FindChartInRepoURL(repoURL, name, version, "", "", "", m.Getters)
if err == nil { if err == nil {
return url, username, password, false, err return url, username, password, false, false, err
} }
err = errors.Errorf("chart %s not found in %s: %s", name, repoURL, err) err = errors.Errorf("chart %s not found in %s: %s", name, repoURL, err)
return url, username, password, false, err return url, username, password, false, false, err
} }
// findEntryByName finds an entry in the chart repository whose name matches the given name. // findEntryByName finds an entry in the chart repository whose name matches the given name.

@ -81,7 +81,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, err := m.findChartURL(name, version, repoURL, repos) churl, username, password, insecureSkipTLSVerify, passcredentialsall, err := m.findChartURL(name, version, repoURL, repos)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -95,6 +95,9 @@ func TestFindChartURL(t *testing.T) {
if password != "" { if password != "" {
t.Errorf("Unexpected password %q", password) t.Errorf("Unexpected password %q", password)
} }
if passcredentialsall != false {
t.Errorf("Unexpected passcredentialsall %t", passcredentialsall)
}
if insecureSkipTLSVerify { if insecureSkipTLSVerify {
t.Errorf("Unexpected insecureSkipTLSVerify %t", insecureSkipTLSVerify) t.Errorf("Unexpected insecureSkipTLSVerify %t", insecureSkipTLSVerify)
} }
@ -103,7 +106,7 @@ func TestFindChartURL(t *testing.T) {
version = "1.2.3" version = "1.2.3"
repoURL = "https://example-https-insecureskiptlsverify.com" repoURL = "https://example-https-insecureskiptlsverify.com"
churl, username, password, insecureSkipTLSVerify, err = m.findChartURL(name, version, repoURL, repos) churl, username, password, insecureSkipTLSVerify, passcredentialsall, err = m.findChartURL(name, version, repoURL, repos)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -120,6 +123,9 @@ func TestFindChartURL(t *testing.T) {
if password != "" { if password != "" {
t.Errorf("Unexpected password %q", password) t.Errorf("Unexpected password %q", password)
} }
if passcredentialsall != false {
t.Errorf("Unexpected passcredentialsall %t", passcredentialsall)
}
} }
func TestGetRepoNames(t *testing.T) { func TestGetRepoNames(t *testing.T) {

@ -38,6 +38,7 @@ type options struct {
insecureSkipVerifyTLS bool insecureSkipVerifyTLS bool
username string username string
password string password string
passCredentialsAll bool
userAgent string userAgent string
version string version string
registryClient *registry.Client registryClient *registry.Client
@ -64,6 +65,12 @@ func WithBasicAuth(username, password string) Option {
} }
} }
func WithPassCredentialsAll(pass bool) Option {
return func(opts *options) {
opts.passCredentialsAll = pass
}
}
// WithUserAgent sets the request's User-Agent header to use the provided agent name. // WithUserAgent sets the request's User-Agent header to use the provided agent name.
func WithUserAgent(userAgent string) Option { func WithUserAgent(userAgent string) Option {
return func(opts *options) { return func(opts *options) {

@ -20,6 +20,7 @@ import (
"crypto/tls" "crypto/tls"
"io" "io"
"net/http" "net/http"
"net/url"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -56,8 +57,24 @@ func (g *HTTPGetter) get(href string) (*bytes.Buffer, error) {
req.Header.Set("User-Agent", g.opts.userAgent) req.Header.Set("User-Agent", g.opts.userAgent)
} }
if g.opts.username != "" && g.opts.password != "" { // Before setting the basic auth credentials, make sure the URL associated
req.SetBasicAuth(g.opts.username, g.opts.password) // with the basic auth is the one being fetched.
u1, err := url.Parse(g.opts.url)
if err != nil {
return buf, errors.Wrap(err, "Unable to parse getter URL")
}
u2, err := url.Parse(href)
if err != nil {
return buf, errors.Wrap(err, "Unable to parse URL getting from")
}
// Host on URL (returned from url.Parse) contains the port if present.
// This check ensures credentials are not passed between different
// services on different ports.
if g.opts.passCredentialsAll || (u1.Scheme == u2.Scheme && u1.Host == u2.Host) {
if g.opts.username != "" && g.opts.password != "" {
req.SetBasicAuth(g.opts.username, g.opts.password)
}
} }
client, err := g.httpClient() client, err := g.httpClient()

@ -54,6 +54,7 @@ func TestHTTPGetter(t *testing.T) {
// Test with options // Test with options
g, err = NewHTTPGetter( g, err = NewHTTPGetter(
WithBasicAuth("I", "Am"), WithBasicAuth("I", "Am"),
WithPassCredentialsAll(false),
WithUserAgent("Groot"), WithUserAgent("Groot"),
WithTLSClientConfig(pub, priv, ca), WithTLSClientConfig(pub, priv, ca),
WithInsecureSkipVerifyTLS(insecure), WithInsecureSkipVerifyTLS(insecure),
@ -76,6 +77,10 @@ func TestHTTPGetter(t *testing.T) {
t.Errorf("Expected NewHTTPGetter to contain %q as the password, got %q", "Am", hg.opts.password) t.Errorf("Expected NewHTTPGetter to contain %q as the password, got %q", "Am", hg.opts.password)
} }
if hg.opts.passCredentialsAll != false {
t.Errorf("Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", false, hg.opts.passCredentialsAll)
}
if hg.opts.userAgent != "Groot" { if hg.opts.userAgent != "Groot" {
t.Errorf("Expected NewHTTPGetter to contain %q as the user agent, got %q", "Groot", hg.opts.userAgent) t.Errorf("Expected NewHTTPGetter to contain %q as the user agent, got %q", "Groot", hg.opts.userAgent)
} }
@ -118,6 +123,28 @@ func TestHTTPGetter(t *testing.T) {
if hg.opts.insecureSkipVerifyTLS != insecure { if hg.opts.insecureSkipVerifyTLS != insecure {
t.Errorf("Expected NewHTTPGetter to contain %t as InsecureSkipVerifyTLs flag, got %t", insecure, hg.opts.insecureSkipVerifyTLS) t.Errorf("Expected NewHTTPGetter to contain %t as InsecureSkipVerifyTLs flag, got %t", insecure, hg.opts.insecureSkipVerifyTLS)
} }
// Checking false by default
if hg.opts.passCredentialsAll != false {
t.Errorf("Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", false, hg.opts.passCredentialsAll)
}
// Test setting PassCredentialsAll
g, err = NewHTTPGetter(
WithBasicAuth("I", "Am"),
WithPassCredentialsAll(true),
)
if err != nil {
t.Fatal(err)
}
hg, ok = g.(*HTTPGetter)
if !ok {
t.Fatal("expected NewHTTPGetter to produce an *HTTPGetter")
}
if hg.opts.passCredentialsAll != true {
t.Errorf("Expected NewHTTPGetter to contain %t as PassCredentialsAll, got %t", true, hg.opts.passCredentialsAll)
}
} }
func TestDownload(t *testing.T) { func TestDownload(t *testing.T) {
@ -163,6 +190,7 @@ func TestDownload(t *testing.T) {
httpgetter, err := NewHTTPGetter( httpgetter, err := NewHTTPGetter(
WithURL(u.String()), WithURL(u.String()),
WithBasicAuth("username", "password"), WithBasicAuth("username", "password"),
WithPassCredentialsAll(false),
WithUserAgent(expectedUserAgent), WithUserAgent(expectedUserAgent),
) )
if err != nil { if err != nil {
@ -176,6 +204,76 @@ func TestDownload(t *testing.T) {
if got.String() != expect { if got.String() != expect {
t.Errorf("Expected %q, got %q", expect, got.String()) t.Errorf("Expected %q, got %q", expect, got.String())
} }
// test with Get URL differing from withURL
crossAuthSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
username, password, ok := r.BasicAuth()
if ok || username == "username" || password == "password" {
t.Errorf("Expected request to not include but got '%v', '%s', '%s'", ok, username, password)
}
fmt.Fprint(w, expect)
}))
defer crossAuthSrv.Close()
u, _ = url.ParseRequestURI(crossAuthSrv.URL)
// A different host is provided for the WithURL from the one used for Get
u2, _ := url.ParseRequestURI(crossAuthSrv.URL)
host := strings.Split(u2.Host, ":")
host[0] = host[0] + "a"
u2.Host = strings.Join(host, ":")
httpgetter, err = NewHTTPGetter(
WithURL(u2.String()),
WithBasicAuth("username", "password"),
WithPassCredentialsAll(false),
)
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())
}
// test with Get URL differing from withURL and should pass creds
crossAuthSrv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
username, password, ok := r.BasicAuth()
if !ok || username != "username" || password != "password" {
t.Errorf("Expected request to use basic auth and for username == 'username' and password == 'password', got '%v', '%s', '%s'", ok, username, password)
}
fmt.Fprint(w, expect)
}))
defer crossAuthSrv.Close()
u, _ = url.ParseRequestURI(crossAuthSrv.URL)
// A different host is provided for the WithURL from the one used for Get
u2, _ = url.ParseRequestURI(crossAuthSrv.URL)
host = strings.Split(u2.Host, ":")
host[0] = host[0] + "a"
u2.Host = strings.Join(host, ":")
httpgetter, err = NewHTTPGetter(
WithURL(u2.String()),
WithBasicAuth("username", "password"),
WithPassCredentialsAll(true),
)
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 TestDownloadTLS(t *testing.T) { func TestDownloadTLS(t *testing.T) {

@ -48,6 +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"`
} }
// ChartRepository represents a chart repository // ChartRepository represents a chart repository
@ -129,6 +130,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),
) )
if err != nil { if err != nil {
return "", err return "", err
@ -217,6 +219,15 @@ 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)
}
// FindChartInAuthAndTLSAndPassRepoURL finds chart in chart repository pointed by repoURL
// 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)
@ -227,6 +238,7 @@ func FindChartInAuthAndTLSRepoURL(repoURL, username, password, chartName, chartV
URL: repoURL, URL: repoURL,
Username: username, Username: username,
Password: password, Password: password,
PassCredentialsAll: passCredentialsAll,
CertFile: certFile, CertFile: certFile,
KeyFile: keyFile, KeyFile: keyFile,
CAFile: caFile, CAFile: caFile,

@ -292,14 +292,14 @@ func startLocalTLSServerForTests(handler http.Handler) (*httptest.Server, error)
return httptest.NewTLSServer(handler), nil return httptest.NewTLSServer(handler), nil
} }
func TestFindChartInAuthAndTLSRepoURL(t *testing.T) { func TestFindChartInAuthAndTLSAndPassRepoURL(t *testing.T) {
srv, err := startLocalTLSServerForTests(nil) srv, err := startLocalTLSServerForTests(nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer srv.Close() defer srv.Close()
chartURL, err := FindChartInAuthAndTLSRepoURL(srv.URL, "", "", "nginx", "", "", "", "", true, getter.All(&cli.EnvSettings{})) chartURL, err := FindChartInAuthAndTLSAndPassRepoURL(srv.URL, "", "", "nginx", "", "", "", "", true, false, getter.All(&cli.EnvSettings{}))
if err != nil { if err != nil {
t.Fatalf("%v", err) t.Fatalf("%v", err)
} }
@ -308,10 +308,10 @@ func TestFindChartInAuthAndTLSRepoURL(t *testing.T) {
} }
// If the insecureSkipTLsverify is false, it will return an error that contains "x509: certificate signed by unknown authority". // If the insecureSkipTLsverify is false, it will return an error that contains "x509: certificate signed by unknown authority".
_, err = FindChartInAuthAndTLSRepoURL(srv.URL, "", "", "nginx", "0.1.0", "", "", "", false, getter.All(&cli.EnvSettings{})) _, err = FindChartInAuthAndTLSAndPassRepoURL(srv.URL, "", "", "nginx", "0.1.0", "", "", "", false, false, getter.All(&cli.EnvSettings{}))
if !strings.Contains(err.Error(), "x509: certificate signed by unknown authority") { if !strings.Contains(err.Error(), "x509: certificate signed by unknown authority") {
t.Errorf("Expected TLS error for function FindChartInAuthAndTLSRepoURL not found, but got a different error (%v)", err) t.Errorf("Expected TLS error for function FindChartInAuthAndTLSAndPassRepoURL not found, but got a different error (%v)", err)
} }
} }

Loading…
Cancel
Save