diff --git a/pkg/registry/client.go b/pkg/registry/client.go index f08fb3e3c..52d84619e 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -70,7 +70,7 @@ type ( caFile string insecureSkipVerifyTLS bool plainHTTP bool - httpClient *http.Client + httpClient *http.Client } // ClientOption allows specifying various settings configurable by the user for overriding the defaults @@ -132,7 +132,10 @@ func NewClient(options ...ClientOption) (*Client, error) { TLSClientConfig: config, }, })) - + } + if client.plainHTTP { + opts = append(opts, auth.WithResolverPlainHTTP()) + } if client.httpClient != nil { opts = append(opts, auth.WithResolverClient(client.httpClient)) } @@ -240,6 +243,9 @@ func ClientOptInsecureSkipVerifyTLS(insecureSkipVerifyTLS bool) ClientOption { func ClientOptPlainHTTP(plainHTTP bool) ClientOption { return func(client *Client) { client.plainHTTP = plainHTTP + } +} + // ClientOptHTTPClient returns a function that sets the httpClient setting on a client options set func ClientOptHTTPClient(httpClient *http.Client) ClientOption { return func(client *Client) { @@ -252,12 +258,13 @@ type ( LoginOption func(*loginOperation) loginOperation struct { - username string - password string - insecure bool - certFile string - keyFile string - caFile string + username string + password string + insecure bool + certFile string + keyFile string + caFile string + plainHTTP bool } ) @@ -293,6 +300,13 @@ func LoginOptBasicAuth(username string, password string) LoginOption { } } +// LoginOptBasicAuth returns a function that sets the username/password settings on login +func LoginOptPlainHTTP() LoginOption { + return func(operation *loginOperation) { + operation.plainHTTP = true + } +} + // LoginOptInsecure returns a function that sets the insecure setting on login func LoginOptInsecure(insecure bool) LoginOption { return func(operation *loginOperation) { diff --git a/pkg/registry/client_http_test.go b/pkg/registry/client_http_test.go new file mode 100644 index 000000000..94b1b73b3 --- /dev/null +++ b/pkg/registry/client_http_test.go @@ -0,0 +1,76 @@ +/* +Copyright The Helm 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 registry + +import ( + "os" + "testing" + + "github.com/stretchr/testify/suite" +) + +type HTTPRegistryClientTestSuite struct { + TestSuite +} + +func (suite *HTTPRegistryClientTestSuite) SetupSuite() { + // init test client + dockerRegistry := setup(&suite.TestSuite, false, false) + + // Start Docker registry + go dockerRegistry.ListenAndServe() +} + +func (suite *HTTPRegistryClientTestSuite) TearDownSuite() { + os.RemoveAll(suite.WorkspaceDir) +} + +func (suite *HTTPRegistryClientTestSuite) Test_0_Login() { + err := suite.RegistryClient.Login(suite.DockerRegistryHost, + LoginOptBasicAuth(testUsername, testPassword), + LoginOptInsecure(false)) + suite.Nil(err, "Expected no error logging into registry with good credentials: %v", err) + + err = suite.RegistryClient.Login(suite.DockerRegistryHost, + LoginOptBasicAuth(testUsername, "badpassword"), + LoginOptInsecure(true)) + suite.NotNil(err, "error logging into registry with good credentials, insecure mode") +} + +func (suite *HTTPRegistryClientTestSuite) Test_1_Push() { + testPush(&suite.TestSuite) +} + +func (suite *HTTPRegistryClientTestSuite) Test_2_Pull() { + testPull(&suite.TestSuite) +} + +func (suite *HTTPRegistryClientTestSuite) Test_3_Tags() { + testTags(&suite.TestSuite) +} + +func (suite *HTTPRegistryClientTestSuite) Test_4_Logout() { + err := suite.RegistryClient.Logout("this-host-aint-real:5000") + suite.NotNil(err, "error logging out of registry that has no entry") + + err = suite.RegistryClient.Logout(suite.DockerRegistryHost) + suite.Nil(err, "no error logging out of registry") +} + +func TestHTTPRegistryClientTestSuite(t *testing.T) { + suite.Run(t, new(HTTPRegistryClientTestSuite)) +} diff --git a/pkg/registry/client_test.go b/pkg/registry/client_test.go index 4df031acc..f10152f94 100644 --- a/pkg/registry/client_test.go +++ b/pkg/registry/client_test.go @@ -17,12 +17,16 @@ limitations under the License. package registry import ( +<<<<<<< HEAD "bytes" "context" "fmt" "io" "io/ioutil" "net" +======= + "fmt" +>>>>>>> dd5e82b5 (refactor to new test suite) "os" "path/filepath" "testing" @@ -200,39 +204,8 @@ func (suite *RegistryClientTestSuite) SetupSuite() { suite.Nil(err, "no error finding free port for test TLS registry") suite.TLSDockerRegistryHost = fmt.Sprintf("%s:%d", hostname, tlsRegistryPort) - tlsRegistryConfig := &configuration.Configuration{} - tlsRegistryConfig.HTTP.Addr = fmt.Sprintf(":%d", tlsRegistryPort) - tlsRegistryConfig.HTTP.TLS.Certificate = caCertPath - tlsRegistryConfig.HTTP.TLS.Key = caKeyPath - tlsRegistryConfig.Storage = map[string]configuration.Parameters{"inmemory": map[string]interface{}{}} - tlsRegistryConfig.Auth = configuration.Auth{ - "htpasswd": configuration.Parameters{ - "realm": hostname, - "path": htpasswdPath, - }, - } - tlsDockerRegistry, err := registry.NewRegistry(context.Background(), tlsRegistryConfig) - suite.Nil(err, "no error creating test TLS registry") - // init TLS registry with self-signed CA and client verification enabled - anotherTLSRegistryPort, err := freeport.GetFreePort() - suite.Nil(err, "no error finding free port for test another TLS registry") - suite.TLSVerifyClientDockerRegistryHost = fmt.Sprintf("%s:%d", hostname, anotherTLSRegistryPort) - - anotherTLSRegistryConfig := &configuration.Configuration{} - anotherTLSRegistryConfig.HTTP.Addr = fmt.Sprintf(":%d", anotherTLSRegistryPort) - anotherTLSRegistryConfig.HTTP.TLS.Certificate = caCertPath - anotherTLSRegistryConfig.HTTP.TLS.Key = caKeyPath - anotherTLSRegistryConfig.HTTP.TLS.ClientCAs = []string{caCertPath} - anotherTLSRegistryConfig.Storage = map[string]configuration.Parameters{"inmemory": map[string]interface{}{}} - // no auth because we cannot pass Login action - anotherTLSDockerRegistry, err := registry.NewRegistry(context.Background(), anotherTLSRegistryConfig) - suite.Nil(err, "no error creating test another TLS registry") - - // start registries + // Start Docker registry go dockerRegistry.ListenAndServe() - go plainHTTPDockerRegistry.ListenAndServe() - go tlsDockerRegistry.ListenAndServe() - go anotherTLSDockerRegistry.ListenAndServe() } func (suite *RegistryClientTestSuite) TearDownSuite() { @@ -259,36 +232,6 @@ func (suite *RegistryClientTestSuite) Test_0_Login() { LoginOptBasicAuth(testUsername, testPassword), LoginOptInsecure(true)) suite.Nil(err, "no error logging into registry with good credentials, insecure mode") - - err = suite.PlainHTTPRegistryClient.Login(suite.PlainHTTPDockerRegistryHost, - LoginOptBasicAuth(testUsername, testPassword), - LoginOptInsecure(false)) - suite.NotNil(err, "no error logging into registry with good credentials") - - err = suite.PlainHTTPRegistryClient.Login(suite.PlainHTTPDockerRegistryHost, - LoginOptBasicAuth(testUsername, testPassword), - LoginOptInsecure(true)) - suite.Nil(err, "error logging into registry with good credentials, insecure mode") - - err = suite.InsecureRegistryClient.Login(suite.TLSDockerRegistryHost, - LoginOptBasicAuth(testUsername, testPassword), - LoginOptInsecure(false)) - suite.NotNil(err, "no error logging into insecure with good credentials") - - err = suite.InsecureRegistryClient.Login(suite.TLSDockerRegistryHost, - LoginOptBasicAuth(testUsername, testPassword), - LoginOptInsecure(true)) - suite.Nil(err, "error logging into insecure with good credentials, insecure mode") - - err = suite.RegistryClientWithCA.Login(suite.TLSDockerRegistryHost, - LoginOptBasicAuth(testUsername, testPassword), - LoginOptInsecure(false)) - suite.NotNil(err, "no error logging into insecure with good credentials") - - err = suite.RegistryClientWithCA.Login(suite.TLSDockerRegistryHost, - LoginOptBasicAuth(testUsername, testPassword), - LoginOptInsecure(true)) - suite.Nil(err, "error logging into insecure with good credentials, insecure mode") } func (suite *RegistryClientTestSuite) Test_1_Push() { @@ -309,17 +252,6 @@ func (suite *RegistryClientTestSuite) Test_4_Logout() { err = suite.RegistryClient.Logout(suite.DockerRegistryHost) suite.Nil(err, "no error logging out of registry") - - err = suite.PlainHTTPRegistryClient.Logout(suite.PlainHTTPDockerRegistryHost) - suite.Nil(err, "error logging out of plain http registry") - - err = suite.InsecureRegistryClient.Logout(suite.TLSDockerRegistryHost) - suite.Nil(err, "error logging out of insecure registry") - - // error as logout happened for TLSDockerRegistryHost in last step - err = suite.RegistryClientWithCA.Logout(suite.TLSDockerRegistryHost) - suite.Nil(err, "no error logging out of registry with ca cert") - } func (suite *RegistryClientTestSuite) Test_5_ManInTheMiddle() { diff --git a/pkg/registry/util.go b/pkg/registry/util.go index 2a2754378..8661202fb 100644 --- a/pkg/registry/util.go +++ b/pkg/registry/util.go @@ -155,3 +155,18 @@ func NewRegistryClientWithTLS(out io.Writer, certFile, keyFile, caFile string, i } return registryClient, nil } + +func NewRegistryClientHTTP(out io.Writer, certFile, keyFile, caFile string, insecureSkipTLSverify bool, registryConfig string, debug bool) (*Client, error) { + // Create a new http registry client + registryClient, err := NewClient( + ClientOptDebug(debug), + ClientOptEnableCache(true), + ClientOptWriter(out), + ClientOptCredentialsFile(registryConfig), + ClientOptPlainHTTP(true), + ) + if err != nil { + return nil, err + } + return registryClient, nil +} diff --git a/pkg/registry/utils_test.go b/pkg/registry/utils_test.go index 7cd338793..9dc832a4d 100644 --- a/pkg/registry/utils_test.go +++ b/pkg/registry/utils_test.go @@ -55,17 +55,29 @@ var ( testHtpasswdFileBasename = "authtest.htpasswd" testUsername = "myuser" testPassword = "mypass" + testCACertFileName = "root.pem" + testCAKeyFileName = "root-key.pem" + testClientCertFileName = "client.pem" + testClientKeyFileName = "client-key.pem" ) type TestSuite struct { suite.Suite - Out io.Writer - DockerRegistryHost string + Out io.Writer + DockerRegistryHost string + CompromisedRegistryHost string WorkspaceDir string RegistryClient *Client } +// setup creates a oci registry for use in testing and sets the internal +// RegistryClient in the provided *TestSutie object with a client for communicating +// to the registry for testing: +// +// tlsEnabled - true for an https registry, false for http +// insecure - true for forcing the client to trust the certs when communicating to the registry +// false otherwise func setup(suite *TestSuite, tlsEnabled bool, insecure bool) *registry.Registry { suite.WorkspaceDir = testWorkspaceDir os.RemoveAll(suite.WorkspaceDir) @@ -101,6 +113,7 @@ func setup(suite *TestSuite, tlsEnabled bool, insecure bool) *registry.Registry ClientOptEnableCache(true), ClientOptWriter(suite.Out), ClientOptCredentialsFile(credentialsFile), + ClientOptPlainHTTP(true), ) }