zotregistry.dev/zot@v1.4.4-0.20240314164342-eec277e14d20/pkg/cli/client/client_test.go (about)

     1  //go:build search
     2  // +build search
     3  
     4  package client_test
     5  
     6  import (
     7  	"bytes"
     8  	"crypto/tls"
     9  	"crypto/x509"
    10  	"fmt"
    11  	"os"
    12  	"path"
    13  	"path/filepath"
    14  	"testing"
    15  
    16  	. "github.com/smartystreets/goconvey/convey"
    17  	"gopkg.in/resty.v1"
    18  
    19  	"zotregistry.dev/zot/pkg/api"
    20  	"zotregistry.dev/zot/pkg/api/config"
    21  	"zotregistry.dev/zot/pkg/api/constants"
    22  	"zotregistry.dev/zot/pkg/cli/client"
    23  	extConf "zotregistry.dev/zot/pkg/extensions/config"
    24  	test "zotregistry.dev/zot/pkg/test/common"
    25  )
    26  
    27  const (
    28  	BaseSecureURL1 = "https://127.0.0.1:8088"
    29  	HOST1          = "127.0.0.1:8088"
    30  	SecurePort1    = "8088"
    31  	BaseSecureURL2 = "https://127.0.0.1:8089"
    32  	SecurePort2    = "8089"
    33  	BaseSecureURL3 = "https://127.0.0.1:8090"
    34  	SecurePort3    = "8090"
    35  	ServerCert     = "../../../test/data/server.cert"
    36  	ServerKey      = "../../../test/data/server.key"
    37  	CACert         = "../../../test/data/ca.crt"
    38  	sourceCertsDir = "../../../test/data"
    39  	certsDir1      = "/.config/containers/certs.d/127.0.0.1:8088/"
    40  )
    41  
    42  func TestTLSWithAuth(t *testing.T) {
    43  	Convey("Make a new controller", t, func() {
    44  		caCert, err := os.ReadFile(CACert)
    45  		So(err, ShouldBeNil)
    46  		caCertPool := x509.NewCertPool()
    47  		caCertPool.AppendCertsFromPEM(caCert)
    48  
    49  		resty.SetTLSClientConfig(&tls.Config{RootCAs: caCertPool, MinVersion: tls.VersionTLS12})
    50  		defer func() { resty.SetTLSClientConfig(nil) }()
    51  		conf := config.New()
    52  		conf.HTTP.Port = SecurePort1
    53  		username, seedUser := test.GenerateRandomString()
    54  		password, seedPass := test.GenerateRandomString()
    55  		htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password))
    56  		defer os.Remove(htpasswdPath)
    57  
    58  		conf.HTTP.Auth = &config.AuthConfig{
    59  			HTPasswd: config.AuthHTPasswd{
    60  				Path: htpasswdPath,
    61  			},
    62  		}
    63  
    64  		conf.HTTP.TLS = &config.TLSConfig{
    65  			Cert:   ServerCert,
    66  			Key:    ServerKey,
    67  			CACert: CACert,
    68  		}
    69  
    70  		enable := true
    71  		conf.Extensions = &extConf.ExtensionConfig{
    72  			Search: &extConf.SearchConfig{BaseConfig: extConf.BaseConfig{Enable: &enable}},
    73  		}
    74  
    75  		ctlr := api.NewController(conf)
    76  		ctlr.Log.Info().Int64("seedUser", seedUser).Int64("seedPass", seedPass).Msg("random seed for username & password")
    77  		ctlr.Config.Storage.RootDirectory = t.TempDir()
    78  		cm := test.NewControllerManager(ctlr)
    79  		cm.StartAndWait(conf.HTTP.Port)
    80  		defer cm.StopServer()
    81  
    82  		Convey("Test with htpassw auth", func() {
    83  			configPath := makeConfigFile(`{"configs":[{"_name":"imagetest","showspinner":false}]}`)
    84  			defer os.Remove(configPath)
    85  
    86  			home := os.Getenv("HOME")
    87  			destCertsDir := filepath.Join(home, certsDir1)
    88  			err := test.CopyTestKeysAndCerts(destCertsDir)
    89  			So(err, ShouldBeNil)
    90  
    91  			defer os.RemoveAll(destCertsDir)
    92  
    93  			args := []string{"name", "dummyImageName", "--url", HOST1}
    94  			imageCmd := client.NewImageCommand(client.NewSearchService())
    95  			imageBuff := bytes.NewBufferString("")
    96  			imageCmd.SetOut(imageBuff)
    97  			imageCmd.SetErr(imageBuff)
    98  			imageCmd.SetArgs(args)
    99  			err = imageCmd.Execute()
   100  			So(err, ShouldNotBeNil)
   101  			So(imageBuff.String(), ShouldContainSubstring, "scheme not provided")
   102  
   103  			args = []string{"list", "--config", "imagetest"}
   104  			configPath = makeConfigFile(
   105  				fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s%s%s","showspinner":false}]}`,
   106  					BaseSecureURL1, constants.RoutePrefix, constants.ExtCatalogPrefix))
   107  			defer os.Remove(configPath)
   108  			imageCmd = client.NewImageCommand(client.NewSearchService())
   109  			imageBuff = bytes.NewBufferString("")
   110  			imageCmd.SetOut(imageBuff)
   111  			imageCmd.SetErr(imageBuff)
   112  			imageCmd.SetArgs(args)
   113  			err = imageCmd.Execute()
   114  			So(err, ShouldNotBeNil)
   115  			So(imageBuff.String(), ShouldContainSubstring, "check credentials")
   116  
   117  			user := fmt.Sprintf("%s:%s", username, password)
   118  			args = []string{"-u", user, "--config", "imagetest"}
   119  			configPath = makeConfigFile(
   120  				fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s%s%s","showspinner":false}]}`,
   121  					BaseSecureURL1, constants.RoutePrefix, constants.ExtCatalogPrefix))
   122  			defer os.Remove(configPath)
   123  			imageCmd = client.NewImageCommand(client.NewSearchService())
   124  			imageBuff = bytes.NewBufferString("")
   125  			imageCmd.SetOut(imageBuff)
   126  			imageCmd.SetErr(imageBuff)
   127  			imageCmd.SetArgs(args)
   128  			err = imageCmd.Execute()
   129  			So(err, ShouldBeNil)
   130  		})
   131  	})
   132  }
   133  
   134  func TestTLSWithoutAuth(t *testing.T) {
   135  	Convey("Home certs - Make a new controller", t, func() {
   136  		caCert, err := os.ReadFile(CACert)
   137  		So(err, ShouldBeNil)
   138  		caCertPool := x509.NewCertPool()
   139  		caCertPool.AppendCertsFromPEM(caCert)
   140  
   141  		resty.SetTLSClientConfig(&tls.Config{RootCAs: caCertPool, MinVersion: tls.VersionTLS12})
   142  		defer func() { resty.SetTLSClientConfig(nil) }()
   143  		conf := config.New()
   144  		conf.HTTP.Port = SecurePort1
   145  		conf.HTTP.TLS = &config.TLSConfig{
   146  			Cert:   ServerCert,
   147  			Key:    ServerKey,
   148  			CACert: CACert,
   149  		}
   150  
   151  		enable := true
   152  		conf.Extensions = &extConf.ExtensionConfig{
   153  			Search: &extConf.SearchConfig{BaseConfig: extConf.BaseConfig{Enable: &enable}},
   154  		}
   155  
   156  		ctlr := api.NewController(conf)
   157  		ctlr.Config.Storage.RootDirectory = t.TempDir()
   158  		cm := test.NewControllerManager(ctlr)
   159  		cm.StartAndWait(conf.HTTP.Port)
   160  		defer cm.StopServer()
   161  
   162  		Convey("Certs in user's home", func() {
   163  			configPath := makeConfigFile(
   164  				fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s%s%s","showspinner":false}]}`,
   165  					BaseSecureURL1, constants.RoutePrefix, constants.ExtCatalogPrefix))
   166  			defer os.Remove(configPath)
   167  
   168  			home := os.Getenv("HOME")
   169  			destCertsDir := filepath.Join(home, certsDir1)
   170  
   171  			err := test.CopyFiles(sourceCertsDir, destCertsDir)
   172  			So(err, ShouldBeNil)
   173  
   174  			defer os.RemoveAll(destCertsDir)
   175  
   176  			args := []string{"list", "--config", "imagetest"}
   177  			imageCmd := client.NewImageCommand(client.NewSearchService())
   178  			imageBuff := bytes.NewBufferString("")
   179  			imageCmd.SetOut(imageBuff)
   180  			imageCmd.SetErr(imageBuff)
   181  			imageCmd.SetArgs(args)
   182  			err = imageCmd.Execute()
   183  			So(err, ShouldBeNil)
   184  		})
   185  	})
   186  }
   187  
   188  func TestTLSBadCerts(t *testing.T) {
   189  	Convey("Make a new controller", t, func() {
   190  		caCert, err := os.ReadFile(CACert)
   191  		So(err, ShouldBeNil)
   192  		caCertPool := x509.NewCertPool()
   193  		caCertPool.AppendCertsFromPEM(caCert)
   194  
   195  		resty.SetTLSClientConfig(&tls.Config{RootCAs: caCertPool, MinVersion: tls.VersionTLS12})
   196  		defer func() { resty.SetTLSClientConfig(nil) }()
   197  		conf := config.New()
   198  		conf.HTTP.Port = SecurePort3
   199  		conf.HTTP.TLS = &config.TLSConfig{
   200  			Cert:   ServerCert,
   201  			Key:    ServerKey,
   202  			CACert: CACert,
   203  		}
   204  
   205  		ctlr := api.NewController(conf)
   206  		ctlr.Config.Storage.RootDirectory = t.TempDir()
   207  		cm := test.NewControllerManager(ctlr)
   208  		cm.StartAndWait(conf.HTTP.Port)
   209  		defer cm.StopServer()
   210  
   211  		Convey("Test with system certs", func() {
   212  			configPath := makeConfigFile(
   213  				fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s%s%s","showspinner":false}]}`,
   214  					BaseSecureURL3, constants.RoutePrefix, constants.ExtCatalogPrefix))
   215  			defer os.Remove(configPath)
   216  
   217  			args := []string{"list", "--config", "imagetest"}
   218  			imageCmd := client.NewImageCommand(client.NewSearchService())
   219  			imageBuff := bytes.NewBufferString("")
   220  			imageCmd.SetOut(imageBuff)
   221  			imageCmd.SetErr(imageBuff)
   222  			imageCmd.SetArgs(args)
   223  			err := imageCmd.Execute()
   224  			So(err, ShouldNotBeNil)
   225  			So(imageBuff.String(), ShouldContainSubstring, "certificate signed by unknown authority")
   226  		})
   227  	})
   228  }
   229  
   230  func makeConfigFile(content string) string {
   231  	os.Setenv("HOME", os.TempDir())
   232  
   233  	home, err := os.UserHomeDir()
   234  	if err != nil {
   235  		panic(err)
   236  	}
   237  
   238  	configPath := path.Join(home, "/.zot")
   239  
   240  	if err := os.WriteFile(configPath, []byte(content), 0o600); err != nil {
   241  		panic(err)
   242  	}
   243  
   244  	return configPath
   245  }