Add HTTP Support for OCI artifacts

Signed-off-by: Tom Runyon <runyontr@gmail.com>
Signed-off-by: Tom Runyon <tom@defenseunicorns.com>
pull/11623/head
Tom Runyon 3 years ago
parent 330105ca6f
commit 3265d17a81
No known key found for this signature in database
GPG Key ID: D1CF51977E0E790F

@ -132,7 +132,10 @@ func NewClient(options ...ClientOption) (*Client, error) {
TLSClientConfig: config, TLSClientConfig: config,
}, },
})) }))
}
if client.plainHTTP {
opts = append(opts, auth.WithResolverPlainHTTP())
}
if client.httpClient != nil { if client.httpClient != nil {
opts = append(opts, auth.WithResolverClient(client.httpClient)) opts = append(opts, auth.WithResolverClient(client.httpClient))
} }
@ -240,6 +243,9 @@ func ClientOptInsecureSkipVerifyTLS(insecureSkipVerifyTLS bool) ClientOption {
func ClientOptPlainHTTP(plainHTTP bool) ClientOption { func ClientOptPlainHTTP(plainHTTP bool) ClientOption {
return func(client *Client) { return func(client *Client) {
client.plainHTTP = plainHTTP client.plainHTTP = plainHTTP
}
}
// ClientOptHTTPClient returns a function that sets the httpClient setting on a client options set // ClientOptHTTPClient returns a function that sets the httpClient setting on a client options set
func ClientOptHTTPClient(httpClient *http.Client) ClientOption { func ClientOptHTTPClient(httpClient *http.Client) ClientOption {
return func(client *Client) { return func(client *Client) {
@ -258,6 +264,7 @@ type (
certFile string certFile string
keyFile string keyFile string
caFile 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 // LoginOptInsecure returns a function that sets the insecure setting on login
func LoginOptInsecure(insecure bool) LoginOption { func LoginOptInsecure(insecure bool) LoginOption {
return func(operation *loginOperation) { return func(operation *loginOperation) {

@ -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))
}

@ -17,12 +17,16 @@ limitations under the License.
package registry package registry
import ( import (
<<<<<<< HEAD
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net" "net"
=======
"fmt"
>>>>>>> dd5e82b5 (refactor to new test suite)
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
@ -200,39 +204,8 @@ func (suite *RegistryClientTestSuite) SetupSuite() {
suite.Nil(err, "no error finding free port for test TLS registry") suite.Nil(err, "no error finding free port for test TLS registry")
suite.TLSDockerRegistryHost = fmt.Sprintf("%s:%d", hostname, tlsRegistryPort) suite.TLSDockerRegistryHost = fmt.Sprintf("%s:%d", hostname, tlsRegistryPort)
tlsRegistryConfig := &configuration.Configuration{} // Start Docker registry
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
go dockerRegistry.ListenAndServe() go dockerRegistry.ListenAndServe()
go plainHTTPDockerRegistry.ListenAndServe()
go tlsDockerRegistry.ListenAndServe()
go anotherTLSDockerRegistry.ListenAndServe()
} }
func (suite *RegistryClientTestSuite) TearDownSuite() { func (suite *RegistryClientTestSuite) TearDownSuite() {
@ -259,36 +232,6 @@ func (suite *RegistryClientTestSuite) Test_0_Login() {
LoginOptBasicAuth(testUsername, testPassword), LoginOptBasicAuth(testUsername, testPassword),
LoginOptInsecure(true)) LoginOptInsecure(true))
suite.Nil(err, "no error logging into registry with good credentials, insecure mode") 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() { func (suite *RegistryClientTestSuite) Test_1_Push() {
@ -309,17 +252,6 @@ func (suite *RegistryClientTestSuite) Test_4_Logout() {
err = suite.RegistryClient.Logout(suite.DockerRegistryHost) err = suite.RegistryClient.Logout(suite.DockerRegistryHost)
suite.Nil(err, "no error logging out of registry") 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() { func (suite *RegistryClientTestSuite) Test_5_ManInTheMiddle() {

@ -155,3 +155,18 @@ func NewRegistryClientWithTLS(out io.Writer, certFile, keyFile, caFile string, i
} }
return registryClient, nil 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
}

@ -55,17 +55,29 @@ var (
testHtpasswdFileBasename = "authtest.htpasswd" testHtpasswdFileBasename = "authtest.htpasswd"
testUsername = "myuser" testUsername = "myuser"
testPassword = "mypass" testPassword = "mypass"
testCACertFileName = "root.pem"
testCAKeyFileName = "root-key.pem"
testClientCertFileName = "client.pem"
testClientKeyFileName = "client-key.pem"
) )
type TestSuite struct { type TestSuite struct {
suite.Suite suite.Suite
Out io.Writer Out io.Writer
DockerRegistryHost string DockerRegistryHost string
CompromisedRegistryHost string CompromisedRegistryHost string
WorkspaceDir string WorkspaceDir string
RegistryClient *Client 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 { func setup(suite *TestSuite, tlsEnabled bool, insecure bool) *registry.Registry {
suite.WorkspaceDir = testWorkspaceDir suite.WorkspaceDir = testWorkspaceDir
os.RemoveAll(suite.WorkspaceDir) os.RemoveAll(suite.WorkspaceDir)
@ -101,6 +113,7 @@ func setup(suite *TestSuite, tlsEnabled bool, insecure bool) *registry.Registry
ClientOptEnableCache(true), ClientOptEnableCache(true),
ClientOptWriter(suite.Out), ClientOptWriter(suite.Out),
ClientOptCredentialsFile(credentialsFile), ClientOptCredentialsFile(credentialsFile),
ClientOptPlainHTTP(true),
) )
} }

Loading…
Cancel
Save