package api_test import ( "context" "crypto/tls" "crypto/x509" "encoding/json" "io/ioutil" "os" "testing" "time" "github.com/anuvu/zot/pkg/api" . "github.com/smartystreets/goconvey/convey" "gopkg.in/resty.v1" ) const ( BaseURL1 = "http://127.0.0.1:8081" BaseURL2 = "http://127.0.0.1:8082" BaseSecureURL2 = "https://127.0.0.1:8082" username = "test" passphrase = "test" htpasswdPath = "../../test/data/htpasswd" // nolint (gosec) - this is just test data ) func TestNew(t *testing.T) { Convey("Make a new controller", t, func() { config := api.NewConfig() So(config, ShouldNotBeNil) So(api.NewController(config), ShouldNotBeNil) }) } func TestBasicAuth(t *testing.T) { Convey("Make a new controller", t, func() { config := api.NewConfig() config.HTTP.Port = "8081" config.HTTP.Auth.HTPasswd.Path = htpasswdPath c := api.NewController(config) dir, err := ioutil.TempDir("", "oci-repo-test") if err != nil { panic(err) } defer os.RemoveAll(dir) c.Config.Storage.RootDirectory = dir go func() { // this blocks if err := c.Run(); err != nil { return } }() // wait till ready for { _, err := resty.R().Get(BaseURL1) if err == nil { break } time.Sleep(100 * time.Millisecond) } defer func() { ctx := context.Background() _ = c.Server.Shutdown(ctx) }() // without creds, should get access error resp, err := resty.R().Get(BaseURL1 + "/v2/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 401) var e api.Error err = json.Unmarshal(resp.Body(), &e) So(err, ShouldBeNil) // with creds, should get expected status code resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(BaseURL1) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 404) resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(BaseURL1 + "/v2/") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) }) } func TestTLSWithBasicAuth(t *testing.T) { Convey("Make a new controller", t, func() { caCert, err := ioutil.ReadFile("../../test/data/ca.crt") So(err, ShouldBeNil) caCertPool := x509.NewCertPool() caCertPool.AppendCertsFromPEM(caCert) resty.SetTLSClientConfig(&tls.Config{RootCAs: caCertPool}) defer func() { resty.SetTLSClientConfig(nil) }() config := api.NewConfig() config.HTTP.Port = "8082" config.HTTP.Auth.HTPasswd.Path = htpasswdPath config.HTTP.TLS.Cert = "../../test/data/server.crt" config.HTTP.TLS.Key = "../../test/data/server.key" c := api.NewController(config) dir, err := ioutil.TempDir("", "oci-repo-test") if err != nil { panic(err) } defer os.RemoveAll(dir) c.Config.Storage.RootDirectory = dir go func() { // this blocks if err := c.Run(); err != nil { return } }() // wait till ready for { _, err := resty.R().Get(BaseURL2) if err == nil { break } time.Sleep(100 * time.Millisecond) } defer func() { ctx := context.Background() _ = c.Server.Shutdown(ctx) }() // accessing insecure HTTP site should fail resp, err := resty.R().Get(BaseURL2) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 400) // without creds, should get access error resp, err = resty.R().Get(BaseSecureURL2 + "/v2/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 401) var e api.Error err = json.Unmarshal(resp.Body(), &e) So(err, ShouldBeNil) // with creds, should get expected status code resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(BaseSecureURL2) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 404) resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(BaseSecureURL2 + "/v2/") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) }) } func TestTLSMutualAuth(t *testing.T) { Convey("Make a new controller", t, func() { caCert, err := ioutil.ReadFile("../../test/data/ca.crt") So(err, ShouldBeNil) caCertPool := x509.NewCertPool() caCertPool.AppendCertsFromPEM(caCert) resty.SetTLSClientConfig(&tls.Config{RootCAs: caCertPool}) defer func() { resty.SetTLSClientConfig(nil) }() config := api.NewConfig() config.HTTP.Port = "8082" config.HTTP.Auth.HTPasswd.Path = htpasswdPath config.HTTP.TLS.Cert = "../../test/data/server.crt" config.HTTP.TLS.Key = "../../test/data/server.key" config.HTTP.TLS.CACert = "../../test/data/ca.crt" c := api.NewController(config) dir, err := ioutil.TempDir("", "oci-repo-test") if err != nil { panic(err) } defer os.RemoveAll(dir) c.Config.Storage.RootDirectory = dir go func() { // this blocks if err := c.Run(); err != nil { return } }() // wait till ready for { _, err := resty.R().Get(BaseURL2) if err == nil { break } time.Sleep(100 * time.Millisecond) } defer func() { ctx := context.Background() _ = c.Server.Shutdown(ctx) }() // accessing insecure HTTP site should fail resp, err := resty.R().Get(BaseURL2) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 400) // without client certs and creds, should get conn error _, err = resty.R().Get(BaseSecureURL2) So(err, ShouldNotBeNil) // with creds but without certs, should get conn error _, err = resty.R().SetBasicAuth(username, passphrase).Get(BaseSecureURL2) So(err, ShouldNotBeNil) // setup TLS mutual auth cert, err := tls.LoadX509KeyPair("../../test/data/client.crt", "../../test/data/client.key") So(err, ShouldBeNil) resty.SetCertificates(cert) defer func() { resty.SetCertificates(tls.Certificate{}) }() // with client certs but without creds, should get access error resp, err = resty.R().Get(BaseSecureURL2 + "/v2/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 401) // with client certs and creds, should get expected status code resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(BaseSecureURL2) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 404) resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(BaseSecureURL2 + "/v2/") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) }) }