From a208dbc83a94696e774407c8e490a725d513f7dd Mon Sep 17 00:00:00 2001 From: Alexei Dodon Date: Thu, 5 Oct 2023 23:47:32 +0300 Subject: [PATCH] fix: metrics should be protected behind authZ Signed-off-by: Alexei Dodon --- examples/config-metrics-authn.json | 26 + pkg/api/authn.go | 4 +- pkg/api/authn_test.go | 22 +- pkg/api/authz.go | 61 ++- pkg/api/config/config.go | 5 + pkg/api/controller_test.go | 506 ++++++++++--------- pkg/api/routes.go | 2 +- pkg/api/routes_test.go | 5 +- pkg/cli/client/client_test.go | 11 +- pkg/debug/pprof/pprof_test.go | 12 +- pkg/extensions/README.md | 6 +- pkg/extensions/extension_metrics.go | 5 +- pkg/extensions/extension_metrics_disabled.go | 5 +- pkg/extensions/extensions_test.go | 28 +- pkg/extensions/lint/lint_test.go | 40 +- pkg/extensions/monitoring/monitoring_test.go | 306 +++++++++++ pkg/extensions/search/cve/cve_test.go | 117 +++-- pkg/extensions/search/userprefs_test.go | 76 ++- pkg/extensions/sync/sync_test.go | 22 +- pkg/log/log_test.go | 42 +- pkg/storage/cache_benchmark_test.go | 38 +- pkg/test/common/fs.go | 10 +- pkg/test/common/utils.go | 36 +- pkg/test/skip/skip_test.go | 37 ++ test/blackbox/helpers_metrics.bash | 3 + test/blackbox/metrics.bats | 25 +- test/blackbox/metrics_minimal.bats | 26 +- 27 files changed, 965 insertions(+), 511 deletions(-) create mode 100644 examples/config-metrics-authn.json create mode 100644 pkg/test/skip/skip_test.go diff --git a/examples/config-metrics-authn.json b/examples/config-metrics-authn.json new file mode 100644 index 0000000000..2b94e25835 --- /dev/null +++ b/examples/config-metrics-authn.json @@ -0,0 +1,26 @@ +{ + "distSpecVersion": "1.1.0-dev", + "storage": { + "rootDirectory": "/tmp/zot" + }, + "http": { + "address": "127.0.0.1", + "port": "8080", + "auth": { + "htpasswd": { + "path": "test/data/htpasswd" + } + } + }, + "log": { + "level": "debug" + }, + "extensions": { + "metrics": { + "enable": true, + "prometheus": { + "path": "/metrics" + } + } + } +} diff --git a/pkg/api/authn.go b/pkg/api/authn.go index bd7f03d735..9777b8bee9 100644 --- a/pkg/api/authn.go +++ b/pkg/api/authn.go @@ -57,7 +57,7 @@ func AuthHandler(ctlr *Controller) mux.MiddlewareFunc { return bearerAuthHandler(ctlr) } - return authnMiddleware.TryAuthnHandlers(ctlr) + return authnMiddleware.tryAuthnHandlers(ctlr) } func (amw *AuthnMiddleware) sessionAuthn(ctlr *Controller, userAc *reqCtx.UserAccessControl, @@ -247,7 +247,7 @@ func (amw *AuthnMiddleware) basicAuthn(ctlr *Controller, userAc *reqCtx.UserAcce return false, nil } -func (amw *AuthnMiddleware) TryAuthnHandlers(ctlr *Controller) mux.MiddlewareFunc { //nolint: gocyclo +func (amw *AuthnMiddleware) tryAuthnHandlers(ctlr *Controller) mux.MiddlewareFunc { //nolint: gocyclo // no password based authN, if neither LDAP nor HTTP BASIC is enabled if !ctlr.Config.IsBasicAuthnEnabled() { return noPasswdAuth(ctlr) diff --git a/pkg/api/authn_test.go b/pkg/api/authn_test.go index b989d7865d..dc60173ca6 100644 --- a/pkg/api/authn_test.go +++ b/pkg/api/authn_test.go @@ -79,7 +79,9 @@ func TestAPIKeys(t *testing.T) { conf := config.New() conf.HTTP.Port = port - htpasswdPath := test.MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) mockOIDCServer, err := authutils.MockOIDCRun() @@ -145,7 +147,7 @@ func TestAPIKeys(t *testing.T) { Convey("API key retrieved with basic auth", func() { resp, err := resty.R(). SetBody(reqBody). - SetBasicAuth("test", "test"). + SetBasicAuth(username, password). Post(baseURL + constants.APIKeyPath) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) @@ -162,7 +164,7 @@ func TestAPIKeys(t *testing.T) { So(email, ShouldNotBeEmpty) resp, err = resty.R(). - SetBasicAuth("test", apiKeyResponse.APIKey). + SetBasicAuth(username, apiKeyResponse.APIKey). Get(baseURL + "/v2/_catalog") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) @@ -170,7 +172,7 @@ func TestAPIKeys(t *testing.T) { // get API key list with basic auth resp, err = resty.R(). - SetBasicAuth("test", "test"). + SetBasicAuth(username, password). Get(baseURL + constants.APIKeyPath) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) @@ -189,7 +191,7 @@ func TestAPIKeys(t *testing.T) { // add another one resp, err = resty.R(). SetBody(reqBody). - SetBasicAuth("test", "test"). + SetBasicAuth(username, password). Post(baseURL + constants.APIKeyPath) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) @@ -199,7 +201,7 @@ func TestAPIKeys(t *testing.T) { So(err, ShouldBeNil) resp, err = resty.R(). - SetBasicAuth("test", apiKeyResponse.APIKey). + SetBasicAuth(username, apiKeyResponse.APIKey). Get(baseURL + "/v2/_catalog") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) @@ -207,7 +209,7 @@ func TestAPIKeys(t *testing.T) { // get API key list with api key auth resp, err = resty.R(). - SetBasicAuth("test", apiKeyResponse.APIKey). + SetBasicAuth(username, apiKeyResponse.APIKey). Get(baseURL + constants.APIKeyPath) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) @@ -600,7 +602,7 @@ func TestAPIKeys(t *testing.T) { So(len(apiKeyListResponse.APIKeys), ShouldEqual, 0) resp, err = client.R(). - SetBasicAuth("test", "test"). + SetBasicAuth(username, password). SetQueryParam("id", apiKeyResponse.UUID). Delete(baseURL + constants.APIKeyPath) So(err, ShouldBeNil) @@ -832,7 +834,9 @@ func TestAPIKeys(t *testing.T) { func TestAPIKeysOpenDBError(t *testing.T) { Convey("Test API keys - unable to create database", t, func() { conf := config.New() - htpasswdPath := test.MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) mockOIDCServer, err := authutils.MockOIDCRun() diff --git a/pkg/api/authz.go b/pkg/api/authz.go index 3228e8b038..42c972478b 100644 --- a/pkg/api/authz.go +++ b/pkg/api/authz.go @@ -191,14 +191,10 @@ func (ac *AccessController) getAuthnMiddlewareContext(authnType string, request func (ac *AccessController) isPermitted(userGroups []string, username, action string, policyGroup config.PolicyGroup, ) bool { - var result bool - // check repo/system based policies for _, p := range policyGroup.Policies { if common.Contains(p.Users, username) && common.Contains(p.Actions, action) { - result = true - - return result + return true } } @@ -207,9 +203,7 @@ func (ac *AccessController) isPermitted(userGroups []string, username, action st if common.Contains(p.Actions, action) { for _, group := range p.Groups { if common.Contains(userGroups, group) { - result = true - - return result + return true } } } @@ -217,20 +211,16 @@ func (ac *AccessController) isPermitted(userGroups []string, username, action st } // check defaultPolicy - if !result { - if common.Contains(policyGroup.DefaultPolicy, action) && username != "" { - result = true - } + if common.Contains(policyGroup.DefaultPolicy, action) && username != "" { + return true } // check anonymousPolicy - if !result { - if common.Contains(policyGroup.AnonymousPolicy, action) && username == "" { - result = true - } + if common.Contains(policyGroup.AnonymousPolicy, action) && username == "" { + return true } - return result + return false } func BaseAuthzHandler(ctlr *Controller) mux.MiddlewareFunc { @@ -343,3 +333,40 @@ func DistSpecAuthzHandler(ctlr *Controller) mux.MiddlewareFunc { }) } } + +func MetricsAuthzHandler(ctlr *Controller) mux.MiddlewareFunc { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) { + if ctlr.Config.HTTP.AccessControl == nil { + // allow access to authenticated user as anonymous policy does not exist + next.ServeHTTP(response, request) + + return + } + if len(ctlr.Config.HTTP.AccessControl.Metrics.Users) == 0 { + log := ctlr.Log + log.Warn().Msg("auth is enabled but no metrics users in accessControl: /metrics is unaccesible") + common.AuthzFail(response, request, "", ctlr.Config.HTTP.Realm, ctlr.Config.HTTP.Auth.FailDelay) + + return + } + + // get access control context made in authn.go + userAc, err := reqCtx.UserAcFromContext(request.Context()) + if err != nil { // should never happen + common.AuthzFail(response, request, "", ctlr.Config.HTTP.Realm, ctlr.Config.HTTP.Auth.FailDelay) + + return + } + + username := userAc.GetUsername() + if !common.Contains(ctlr.Config.HTTP.AccessControl.Metrics.Users, username) { + common.AuthzFail(response, request, username, ctlr.Config.HTTP.Realm, ctlr.Config.HTTP.Auth.FailDelay) + + return + } + + next.ServeHTTP(response, request) //nolint:contextcheck + }) + } +} diff --git a/pkg/api/config/config.go b/pkg/api/config/config.go index 8ab156e328..c6ed53da26 100644 --- a/pkg/api/config/config.go +++ b/pkg/api/config/config.go @@ -131,6 +131,7 @@ type AccessControlConfig struct { Repositories Repositories `json:"repositories" mapstructure:"repositories"` AdminPolicy Policy Groups Groups + Metrics Metrics } func (config *AccessControlConfig) AnonymousPolicyExists() bool { @@ -168,6 +169,10 @@ type Policy struct { Groups []string } +type Metrics struct { + Users []string +} + type Config struct { DistSpecVersion string `json:"distSpecVersion" mapstructure:"distSpecVersion"` GoVersion string diff --git a/pkg/api/controller_test.go b/pkg/api/controller_test.go index 0fdf0c90cd..59f37c990a 100644 --- a/pkg/api/controller_test.go +++ b/pkg/api/controller_test.go @@ -46,7 +46,6 @@ import ( . "github.com/smartystreets/goconvey/convey" "github.com/stretchr/testify/assert" "go.etcd.io/bbolt" - "golang.org/x/crypto/bcrypt" "gopkg.in/resty.v1" "zotregistry.io/zot/errors" @@ -73,31 +72,23 @@ import ( ) const ( - username = "test" - htpasswdUsername = "htpasswduser" - passphrase = "test" - group = "test" - repo = "test" ServerCert = "../../test/data/server.cert" ServerKey = "../../test/data/server.key" CACert = "../../test/data/ca.crt" - AuthorizedNamespace = "everyone/isallowed" UnauthorizedNamespace = "fortknox/notallowed" - ALICE = "alice" AuthorizationNamespace = "authz/image" - AuthorizationAllRepos = "**" + LDAPAddress = "127.0.0.1" ) -func getCredString(username, password string) string { - hash, err := bcrypt.GenerateFromPassword([]byte(password), 10) - if err != nil { - panic(err) - } - - usernameAndHash := fmt.Sprintf("%s:%s", username, string(hash)) - - return usernameAndHash -} +var ( + username = test.GenerateRandomString() //nolint: gochecknoglobals + password = test.GenerateRandomString() //nolint: gochecknoglobals + group = test.GenerateRandomString() //nolint: gochecknoglobals + repo = "repo" //nolint: gochecknoglobals + LDAPBaseDN = "ou=" + username //nolint: gochecknoglobals + LDAPBindDN = "cn=reader," + LDAPBaseDN //nolint: gochecknoglobals + LDAPBindPassword = test.GenerateRandomString() //nolint: gochecknoglobals +) func TestNew(t *testing.T) { Convey("Make a new controller", t, func() { @@ -522,10 +513,10 @@ func TestHtpasswdSingleCred(t *testing.T) { port := test.GetFreePort() baseURL := test.GetBaseURL(port) singleCredtests := []string{} - user := ALICE - password := ALICE - singleCredtests = append(singleCredtests, getCredString(user, password)) - singleCredtests = append(singleCredtests, getCredString(user, password)+"\n") + user := test.GenerateRandomString() + password := test.GenerateRandomString() + singleCredtests = append(singleCredtests, test.GetCredString(user, password)) + singleCredtests = append(singleCredtests, test.GetCredString(user, password)) for _, testString := range singleCredtests { func() { @@ -583,7 +574,7 @@ func TestAllowMethodsHeader(t *testing.T) { simpleUser := "simpleUser" simpleUserPassword := "simpleUserPass" - credTests := fmt.Sprintf("%s\n\n", getCredString(simpleUser, simpleUserPassword)) + credTests := fmt.Sprintf("%s\n\n", test.GetCredString(simpleUser, simpleUserPassword)) htpasswdPath := test.MakeHtpasswdFileFromString(credTests) defer os.Remove(htpasswdPath) @@ -661,14 +652,14 @@ func TestHtpasswdTwoCreds(t *testing.T) { password1 := "aliciapassword" user2 := "bob" password2 := "robert" - twoCredTests = append(twoCredTests, getCredString(user1, password1)+"\n"+ - getCredString(user2, password2)) + twoCredTests = append(twoCredTests, test.GetCredString(user1, password1)+"\n"+ + test.GetCredString(user2, password2)) - twoCredTests = append(twoCredTests, getCredString(user1, password1)+"\n"+ - getCredString(user2, password2)+"\n") + twoCredTests = append(twoCredTests, test.GetCredString(user1, password1)+"\n"+ + test.GetCredString(user2, password2)+"\n") - twoCredTests = append(twoCredTests, getCredString(user1, password1)+"\n\n"+ - getCredString(user2, password2)+"\n\n") + twoCredTests = append(twoCredTests, test.GetCredString(user1, password1)+"\n\n"+ + test.GetCredString(user2, password2)+"\n\n") for _, testString := range twoCredTests { func() { @@ -717,7 +708,7 @@ func TestHtpasswdFiveCreds(t *testing.T) { } credString := strings.Builder{} for key, val := range tests { - credString.WriteString(getCredString(key, val) + "\n") + credString.WriteString(test.GetCredString(key, val) + "\n") } func() { @@ -862,7 +853,9 @@ func TestBasicAuth(t *testing.T) { baseURL := test.GetBaseURL(port) conf := config.New() conf.HTTP.Port = port - htpasswdPath := test.MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ @@ -886,11 +879,11 @@ func TestBasicAuth(t *testing.T) { So(err, ShouldBeNil) // with creds, should get expected status code - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL) + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusNotFound) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/v2/") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + "/v2/") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) }) @@ -970,7 +963,8 @@ func TestInterruptedBlobUpload(t *testing.T) { //nolint: dupl Convey("Test interrupt PATCH blob upload", func() { - resp, err := client.R().Post(baseURL + "/v2/" + AuthorizedNamespace + "/blobs/uploads/") + repoName := test.GenerateRandomName() + "/" + test.GenerateRandomName() + resp, err := client.R().Post(baseURL + "/v2/" + repoName + "/blobs/uploads/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusAccepted) @@ -999,7 +993,7 @@ func TestInterruptedBlobUpload(t *testing.T) { // if the blob upload has started then interrupt by running cancel() for { - n, err := ctlr.StoreController.DefaultStore.GetBlobUpload(AuthorizedNamespace, sessionID) + n, err := ctlr.StoreController.DefaultStore.GetBlobUpload(repoName, sessionID) if n > 0 && err == nil { cancel() @@ -1012,7 +1006,7 @@ func TestInterruptedBlobUpload(t *testing.T) { // wait for zot to remove blobUpload time.Sleep(1 * time.Second) - resp, err = client.R().Get(baseURL + "/v2/" + AuthorizedNamespace + "/blobs/uploads/" + sessionID) + resp, err = client.R().Get(baseURL + "/v2/" + repoName + "/blobs/uploads/" + sessionID) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusNotFound) @@ -1020,7 +1014,8 @@ func TestInterruptedBlobUpload(t *testing.T) { //nolint: dupl Convey("Test negative interrupt PATCH blob upload", func() { - resp, err := client.R().Post(baseURL + "/v2/" + AuthorizedNamespace + "/blobs/uploads/") + repoName := test.GenerateRandomName() + "/" + test.GenerateRandomName() + resp, err := client.R().Post(baseURL + "/v2/" + repoName + "/blobs/uploads/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusAccepted) @@ -1049,10 +1044,10 @@ func TestInterruptedBlobUpload(t *testing.T) { // if the blob upload has started then interrupt by running cancel() for { - n, err := ctlr.StoreController.DefaultStore.GetBlobUpload(AuthorizedNamespace, sessionID) + n, err := ctlr.StoreController.DefaultStore.GetBlobUpload(repoName, sessionID) if n > 0 && err == nil { // cleaning blob uploads, so that zot fails to clean up, +code coverage - err = ctlr.StoreController.DefaultStore.DeleteBlobUpload(AuthorizedNamespace, sessionID) + err = ctlr.StoreController.DefaultStore.DeleteBlobUpload(repoName, sessionID) So(err, ShouldBeNil) cancel() @@ -1065,7 +1060,7 @@ func TestInterruptedBlobUpload(t *testing.T) { // wait for zot to remove blobUpload time.Sleep(1 * time.Second) - resp, err = client.R().Get(baseURL + "/v2/" + AuthorizedNamespace + "/blobs/uploads/" + sessionID) + resp, err = client.R().Get(baseURL + "/v2/" + repoName + "/blobs/uploads/" + sessionID) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusNotFound) @@ -1073,7 +1068,8 @@ func TestInterruptedBlobUpload(t *testing.T) { //nolint: dupl Convey("Test interrupt PUT blob upload", func() { - resp, err := client.R().Post(baseURL + "/v2/" + AuthorizedNamespace + "/blobs/uploads/") + repoName := test.GenerateRandomName() + "/" + test.GenerateRandomName() + resp, err := client.R().Post(baseURL + "/v2/" + repoName + "/blobs/uploads/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusAccepted) @@ -1102,7 +1098,7 @@ func TestInterruptedBlobUpload(t *testing.T) { // if the blob upload has started then interrupt by running cancel() for { - n, err := ctlr.StoreController.DefaultStore.GetBlobUpload(AuthorizedNamespace, sessionID) + n, err := ctlr.StoreController.DefaultStore.GetBlobUpload(repoName, sessionID) if n > 0 && err == nil { cancel() @@ -1115,7 +1111,7 @@ func TestInterruptedBlobUpload(t *testing.T) { // wait for zot to try to remove blobUpload time.Sleep(1 * time.Second) - resp, err = client.R().Get(baseURL + "/v2/" + AuthorizedNamespace + "/blobs/uploads/" + sessionID) + resp, err = client.R().Get(baseURL + "/v2/" + repoName + "/blobs/uploads/" + sessionID) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusNotFound) @@ -1123,7 +1119,8 @@ func TestInterruptedBlobUpload(t *testing.T) { //nolint: dupl Convey("Test negative interrupt PUT blob upload", func() { - resp, err := client.R().Post(baseURL + "/v2/" + AuthorizedNamespace + "/blobs/uploads/") + repoName := test.GenerateRandomName() + "/" + test.GenerateRandomName() + resp, err := client.R().Post(baseURL + "/v2/" + repoName + "/blobs/uploads/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusAccepted) @@ -1152,10 +1149,10 @@ func TestInterruptedBlobUpload(t *testing.T) { // if the blob upload has started then interrupt by running cancel() for { - n, err := ctlr.StoreController.DefaultStore.GetBlobUpload(AuthorizedNamespace, sessionID) + n, err := ctlr.StoreController.DefaultStore.GetBlobUpload(repoName, sessionID) if n > 0 && err == nil { // cleaning blob uploads, so that zot fails to clean up, +code coverage - err = ctlr.StoreController.DefaultStore.DeleteBlobUpload(AuthorizedNamespace, sessionID) + err = ctlr.StoreController.DefaultStore.DeleteBlobUpload(repoName, sessionID) So(err, ShouldBeNil) cancel() @@ -1168,7 +1165,7 @@ func TestInterruptedBlobUpload(t *testing.T) { // wait for zot to try to remove blobUpload time.Sleep(1 * time.Second) - resp, err = client.R().Get(baseURL + "/v2/" + AuthorizedNamespace + "/blobs/uploads/" + sessionID) + resp, err = client.R().Get(baseURL + "/v2/" + repoName + "/blobs/uploads/" + sessionID) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusNotFound) @@ -1182,7 +1179,9 @@ func TestMultipleInstance(t *testing.T) { baseURL := test.GetBaseURL(port) conf := config.New() conf.HTTP.Port = port - htpasswdPath := test.MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ @@ -1208,7 +1207,7 @@ func TestMultipleInstance(t *testing.T) { client := resty.New() - tagResponse, err := client.R().SetBasicAuth(username, passphrase). + tagResponse, err := client.R().SetBasicAuth(username, password). Get(baseURL + "/v2/zot-test/tags/list") So(err, ShouldBeNil) So(tagResponse.StatusCode(), ShouldEqual, http.StatusNotFound) @@ -1219,7 +1218,9 @@ func TestMultipleInstance(t *testing.T) { baseURL := test.GetBaseURL(port) conf := config.New() conf.HTTP.Port = port - htpasswdPath := test.MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ @@ -1247,11 +1248,11 @@ func TestMultipleInstance(t *testing.T) { So(err, ShouldBeNil) // with creds, should get expected status code - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL) + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusNotFound) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/v2/") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + "/v2/") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) }) @@ -1261,7 +1262,9 @@ func TestMultipleInstance(t *testing.T) { baseURL := test.GetBaseURL(port) conf := config.New() conf.HTTP.Port = port - htpasswdPath := test.MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ @@ -1310,11 +1313,11 @@ func TestMultipleInstance(t *testing.T) { So(err, ShouldBeNil) // with creds, should get expected status code - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL) + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusNotFound) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/v2/") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + "/v2/") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) }) @@ -1326,7 +1329,9 @@ func TestTLSWithBasicAuth(t *testing.T) { So(err, ShouldBeNil) caCertPool := x509.NewCertPool() caCertPool.AppendCertsFromPEM(caCert) - htpasswdPath := test.MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) port := test.GetFreePort() @@ -1369,11 +1374,11 @@ func TestTLSWithBasicAuth(t *testing.T) { So(err, ShouldBeNil) // with creds, should get expected status code - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(secureBaseURL) + resp, _ = resty.R().SetBasicAuth(username, password).Get(secureBaseURL) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusNotFound) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(secureBaseURL + "/v2/") + resp, _ = resty.R().SetBasicAuth(username, password).Get(secureBaseURL + "/v2/") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) }) @@ -1385,7 +1390,9 @@ func TestTLSWithBasicAuthAllowReadAccess(t *testing.T) { So(err, ShouldBeNil) caCertPool := x509.NewCertPool() caCertPool.AppendCertsFromPEM(caCert) - htpasswdPath := test.MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) port := test.GetFreePort() @@ -1408,7 +1415,7 @@ func TestTLSWithBasicAuthAllowReadAccess(t *testing.T) { conf.HTTP.AccessControl = &config.AccessControlConfig{ Repositories: config.Repositories{ - AuthorizationAllRepos: config.PolicyGroup{ + test.AuthorizationAllRepos: config.PolicyGroup{ AnonymousPolicy: []string{"read"}, }, }, @@ -1432,11 +1439,11 @@ func TestTLSWithBasicAuthAllowReadAccess(t *testing.T) { So(resp.StatusCode(), ShouldEqual, http.StatusOK) // with creds, should get expected status code - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(secureBaseURL) + resp, _ = resty.R().SetBasicAuth(username, password).Get(secureBaseURL) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusNotFound) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(secureBaseURL + "/v2/") + resp, _ = resty.R().SetBasicAuth(username, password).Get(secureBaseURL + "/v2/") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -1453,8 +1460,10 @@ func TestMutualTLSAuthWithUserPermissions(t *testing.T) { So(err, ShouldBeNil) caCertPool := x509.NewCertPool() caCertPool.AppendCertsFromPEM(caCert) - htpasswdPath := test.MakeHtpasswdFile() - defer os.Remove(htpasswdPath) + /* username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) + defer os.Remove(htpasswdPath) */ port := test.GetFreePort() baseURL := test.GetBaseURL(port) @@ -1473,7 +1482,7 @@ func TestMutualTLSAuthWithUserPermissions(t *testing.T) { conf.HTTP.AccessControl = &config.AccessControlConfig{ Repositories: config.Repositories{ - AuthorizationAllRepos: config.PolicyGroup{ + test.AuthorizationAllRepos: config.PolicyGroup{ Policies: []config.Policy{ { Users: []string{"*"}, @@ -1495,7 +1504,7 @@ func TestMutualTLSAuthWithUserPermissions(t *testing.T) { So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusBadRequest) - repoPolicy := conf.HTTP.AccessControl.Repositories[AuthorizationAllRepos] + repoPolicy := conf.HTTP.AccessControl.Repositories[test.AuthorizationAllRepos] // setup TLS mutual auth cert, err := tls.LoadX509KeyPair("../../test/data/client.cert", "../../test/data/client.key") @@ -1533,7 +1542,7 @@ func TestMutualTLSAuthWithUserPermissions(t *testing.T) { // empty default authorization and give user the permission to create repoPolicy.Policies[0].Actions = append(repoPolicy.Policies[0].Actions, "create") - conf.HTTP.AccessControl.Repositories[AuthorizationAllRepos] = repoPolicy + conf.HTTP.AccessControl.Repositories[test.AuthorizationAllRepos] = repoPolicy resp, err = resty.R().Post(secureBaseURL + "/v2/repo/blobs/uploads/") So(err, ShouldBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusAccepted) @@ -1563,7 +1572,7 @@ func TestMutualTLSAuthWithoutCN(t *testing.T) { conf.HTTP.AccessControl = &config.AccessControlConfig{ Repositories: config.Repositories{ - AuthorizationAllRepos: config.PolicyGroup{ + test.AuthorizationAllRepos: config.PolicyGroup{ Policies: []config.Policy{ { Users: []string{"*"}, @@ -1630,8 +1639,10 @@ func TestTLSMutualAuth(t *testing.T) { _, err = resty.R().Get(secureBaseURL) So(err, ShouldNotBeNil) + username := test.GenerateRandomString() + password := test.GenerateRandomString() // with creds but without certs, should get conn error - _, err = resty.R().SetBasicAuth(username, passphrase).Get(secureBaseURL) + _, err = resty.R().SetBasicAuth(username, password).Get(secureBaseURL) So(err, ShouldNotBeNil) // setup TLS mutual auth @@ -1648,12 +1659,12 @@ func TestTLSMutualAuth(t *testing.T) { So(resp.StatusCode(), ShouldEqual, http.StatusOK) // with client certs and creds, should get expected status code - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(secureBaseURL) + resp, _ = resty.R().SetBasicAuth(username, password).Get(secureBaseURL) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusNotFound) // with client certs, creds shouldn't matter - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(secureBaseURL + "/v2/") + resp, _ = resty.R().SetBasicAuth(username, password).Get(secureBaseURL + "/v2/") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) }) @@ -1682,7 +1693,7 @@ func TestTLSMutualAuthAllowReadAccess(t *testing.T) { conf.HTTP.AccessControl = &config.AccessControlConfig{ Repositories: config.Repositories{ - AuthorizationAllRepos: config.PolicyGroup{ + test.AuthorizationAllRepos: config.PolicyGroup{ AnonymousPolicy: []string{"read"}, }, }, @@ -1705,8 +1716,10 @@ func TestTLSMutualAuthAllowReadAccess(t *testing.T) { So(err, ShouldBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) + username := test.GenerateRandomString() + password := test.GenerateRandomString() // with creds but without certs, reads are allowed - resp, err = resty.R().SetBasicAuth(username, passphrase).Get(secureBaseURL + "/v2/") + resp, err = resty.R().SetBasicAuth(username, password).Get(secureBaseURL + "/v2/") So(err, ShouldBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -1729,12 +1742,12 @@ func TestTLSMutualAuthAllowReadAccess(t *testing.T) { So(resp.StatusCode(), ShouldEqual, http.StatusOK) // with client certs and creds, should get expected status code - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(secureBaseURL) + resp, _ = resty.R().SetBasicAuth(username, password).Get(secureBaseURL) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusNotFound) // with client certs, creds shouldn't matter - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(secureBaseURL + "/v2/") + resp, _ = resty.R().SetBasicAuth(username, password).Get(secureBaseURL + "/v2/") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) }) @@ -1746,7 +1759,9 @@ func TestTLSMutualAndBasicAuth(t *testing.T) { So(err, ShouldBeNil) caCertPool := x509.NewCertPool() caCertPool.AppendCertsFromPEM(caCert) - htpasswdPath := test.MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) port := test.GetFreePort() @@ -1787,7 +1802,7 @@ func TestTLSMutualAndBasicAuth(t *testing.T) { So(resp.StatusCode(), ShouldEqual, http.StatusBadRequest) // with creds but without certs, should succeed - _, err = resty.R().SetBasicAuth(username, passphrase).Get(secureBaseURL) + _, err = resty.R().SetBasicAuth(username, password).Get(secureBaseURL) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusBadRequest) @@ -1806,11 +1821,11 @@ func TestTLSMutualAndBasicAuth(t *testing.T) { So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized) // with client certs and creds, should get expected status code - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(secureBaseURL) + resp, _ = resty.R().SetBasicAuth(username, password).Get(secureBaseURL) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusNotFound) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(secureBaseURL + "/v2/") + resp, _ = resty.R().SetBasicAuth(username, password).Get(secureBaseURL + "/v2/") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) }) @@ -1822,7 +1837,9 @@ func TestTLSMutualAndBasicAuthAllowReadAccess(t *testing.T) { So(err, ShouldBeNil) caCertPool := x509.NewCertPool() caCertPool.AppendCertsFromPEM(caCert) - htpasswdPath := test.MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) port := test.GetFreePort() @@ -1846,7 +1863,7 @@ func TestTLSMutualAndBasicAuthAllowReadAccess(t *testing.T) { conf.HTTP.AccessControl = &config.AccessControlConfig{ Repositories: config.Repositories{ - AuthorizationAllRepos: config.PolicyGroup{ + test.AuthorizationAllRepos: config.PolicyGroup{ AnonymousPolicy: []string{"read"}, }, }, @@ -1871,7 +1888,7 @@ func TestTLSMutualAndBasicAuthAllowReadAccess(t *testing.T) { So(resp.StatusCode(), ShouldEqual, http.StatusBadRequest) // with creds but without certs, should succeed - _, err = resty.R().SetBasicAuth(username, passphrase).Get(secureBaseURL) + _, err = resty.R().SetBasicAuth(username, password).Get(secureBaseURL) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusBadRequest) @@ -1894,23 +1911,16 @@ func TestTLSMutualAndBasicAuthAllowReadAccess(t *testing.T) { So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized) // with client certs and creds, should get expected status code - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(secureBaseURL) + resp, _ = resty.R().SetBasicAuth(username, password).Get(secureBaseURL) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusNotFound) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(secureBaseURL + "/v2/") + resp, _ = resty.R().SetBasicAuth(username, password).Get(secureBaseURL + "/v2/") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) }) } -const ( - LDAPAddress = "127.0.0.1" - LDAPBaseDN = "ou=test" - LDAPBindDN = "cn=reader," + LDAPBaseDN - LDAPBindPassword = "bindPassword" -) - type testLDAPServer struct { server *vldap.Server quitCh chan bool @@ -1958,7 +1968,7 @@ func (l *testLDAPServer) Bind(bindDN, bindSimplePw string, conn net.Conn) (vldap } if (bindDN == LDAPBindDN && bindSimplePw == LDAPBindPassword) || - (bindDN == fmt.Sprintf("cn=%s,%s", username, LDAPBaseDN) && bindSimplePw == passphrase) { + (bindDN == fmt.Sprintf("cn=%s,%s", username, LDAPBaseDN) && bindSimplePw == password) { return vldap.LDAPResultSuccess, nil } @@ -2030,11 +2040,11 @@ func TestBasicAuthWithLDAP(t *testing.T) { So(err, ShouldBeNil) // with creds, should get expected status code - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL) + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusNotFound) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/v2/") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + "/v2/") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -2106,7 +2116,7 @@ func TestGroupsPermissionsForLDAP(t *testing.T) { err = UploadImageWithBasicAuth( img, baseURL, repo, img.DigestStr(), - username, passphrase) + username, password) So(err, ShouldBeNil) }) } @@ -2207,7 +2217,8 @@ func TestBearerAuth(t *testing.T) { So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusNoContent) - resp, err = resty.R().Post(baseURL + "/v2/" + AuthorizedNamespace + "/blobs/uploads/") + repoName := test.GenerateRandomName() + "/" + test.GenerateRandomName() + resp, err = resty.R().Post(baseURL + "/v2/" + repoName + "/blobs/uploads/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized) @@ -2225,7 +2236,7 @@ func TestBearerAuth(t *testing.T) { resp, err = resty.R(). SetHeader("Authorization", fmt.Sprintf("Bearer %s", goodToken.AccessToken)). - Post(baseURL + "/v2/" + AuthorizedNamespace + "/blobs/uploads/") + Post(baseURL + "/v2/" + repoName + "/blobs/uploads/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusAccepted) @@ -2265,7 +2276,7 @@ func TestBearerAuth(t *testing.T) { resp, err = resty.R(). SetHeader("Authorization", fmt.Sprintf("Bearer %s", goodToken.AccessToken)). - Get(baseURL + "/v2/" + AuthorizedNamespace + "/tags/list") + Get(baseURL + "/v2/" + repoName + "/tags/list") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized) @@ -2283,7 +2294,7 @@ func TestBearerAuth(t *testing.T) { resp, err = resty.R(). SetHeader("Authorization", fmt.Sprintf("Bearer %s", goodToken.AccessToken)). - Get(baseURL + "/v2/" + AuthorizedNamespace + "/tags/list") + Get(baseURL + "/v2/" + repoName + "/tags/list") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -2361,7 +2372,7 @@ func TestBearerAuthWithAllowReadAccess(t *testing.T) { conf.HTTP.AccessControl = &config.AccessControlConfig{ Repositories: config.Repositories{ - AuthorizationAllRepos: config.PolicyGroup{ + test.AuthorizationAllRepos: config.PolicyGroup{ AnonymousPolicy: []string{"read"}, }, }, @@ -2398,7 +2409,8 @@ func TestBearerAuthWithAllowReadAccess(t *testing.T) { So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) - resp, err = resty.R().Post(baseURL + "/v2/" + AuthorizedNamespace + "/blobs/uploads/") + repoName := test.GenerateRandomName() + "/" + test.GenerateRandomName() + resp, err = resty.R().Post(baseURL + "/v2/" + repoName + "/blobs/uploads/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized) @@ -2416,7 +2428,7 @@ func TestBearerAuthWithAllowReadAccess(t *testing.T) { resp, err = resty.R(). SetHeader("Authorization", fmt.Sprintf("Bearer %s", goodToken.AccessToken)). - Post(baseURL + "/v2/" + AuthorizedNamespace + "/blobs/uploads/") + Post(baseURL + "/v2/" + repoName + "/blobs/uploads/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusAccepted) @@ -2456,7 +2468,7 @@ func TestBearerAuthWithAllowReadAccess(t *testing.T) { resp, err = resty.R(). SetHeader("Authorization", fmt.Sprintf("Bearer %s", goodToken.AccessToken)). - Get(baseURL + "/v2/" + AuthorizedNamespace + "/tags/list") + Get(baseURL + "/v2/" + repoName + "/tags/list") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized) @@ -2474,7 +2486,7 @@ func TestBearerAuthWithAllowReadAccess(t *testing.T) { resp, err = resty.R(). SetHeader("Authorization", fmt.Sprintf("Bearer %s", goodToken.AccessToken)). - Get(baseURL + "/v2/" + AuthorizedNamespace + "/tags/list") + Get(baseURL + "/v2/" + repoName + "/tags/list") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -2605,8 +2617,9 @@ func TestOpenIDMiddleware(t *testing.T) { } // need a username different than ldap one, to test both logic - content := fmt.Sprintf("%s:$2y$05$hlbSXDp6hzDLu6VwACS39ORvVRpr3OMR4RlJ31jtlaOEGnPjKZI1m\n", htpasswdUsername) - htpasswdPath := test.MakeHtpasswdFileFromString(content) + htpasswdUsername := test.GenerateRandomString() + htpasswdPassword := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(htpasswdUsername, htpasswdPassword)) defer os.Remove(htpasswdPath) @@ -2721,7 +2734,7 @@ func TestOpenIDMiddleware(t *testing.T) { client := resty.New() // without header should not create session - resp, err := client.R().SetBasicAuth(htpasswdUsername, passphrase).Get(baseURL + "/v2/") + resp, err := client.R().SetBasicAuth(htpasswdUsername, htpasswdPassword).Get(baseURL + "/v2/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -2732,7 +2745,7 @@ func TestOpenIDMiddleware(t *testing.T) { client.SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue) - resp, err = client.R().SetBasicAuth(htpasswdUsername, passphrase).Get(baseURL + "/v2/") + resp, err = client.R().SetBasicAuth(htpasswdUsername, htpasswdPassword).Get(baseURL + "/v2/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -2745,7 +2758,7 @@ func TestOpenIDMiddleware(t *testing.T) { client.SetCookies(resp.Cookies()) // should get same cookie - resp, err = client.R().SetBasicAuth(htpasswdUsername, passphrase).Get(baseURL + "/v2/") + resp, err = client.R().SetBasicAuth(htpasswdUsername, htpasswdPassword).Get(baseURL + "/v2/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -2754,8 +2767,7 @@ func TestOpenIDMiddleware(t *testing.T) { So(err, ShouldBeNil) So(sessionsNo, ShouldEqual, 1) - resp, err = client.R(). - SetBasicAuth(htpasswdUsername, passphrase). + resp, err = client.R().SetBasicAuth(htpasswdUsername, htpasswdPassword). Get(baseURL + constants.FullMgmt) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) @@ -2770,7 +2782,7 @@ func TestOpenIDMiddleware(t *testing.T) { So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) - resp, err = client.R().SetBasicAuth(htpasswdUsername, passphrase).Get(baseURL + "/v2/") + resp, err = client.R().SetBasicAuth(htpasswdUsername, htpasswdPassword).Get(baseURL + "/v2/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -2850,18 +2862,17 @@ func TestOpenIDMiddleware(t *testing.T) { // first login user // with creds, should get expected status code - resp, err = client.R().SetBasicAuth(htpasswdUsername, passphrase).Get(baseURL) + resp, err = client.R().SetBasicAuth(htpasswdUsername, htpasswdPassword).Get(baseURL) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) - resp, err = client.R().SetBasicAuth(htpasswdUsername, passphrase).Get(baseURL + "/v2/") + resp, err = client.R().SetBasicAuth(htpasswdUsername, htpasswdPassword).Get(baseURL + "/v2/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) - resp, err = client.R(). - SetBasicAuth(htpasswdUsername, passphrase). + resp, err = client.R().SetBasicAuth(htpasswdUsername, htpasswdPassword). Get(baseURL + constants.FullMgmt) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) @@ -2913,18 +2924,17 @@ func TestOpenIDMiddleware(t *testing.T) { // first login user // with creds, should get expected status code - resp, err = client.R().SetBasicAuth(username, passphrase).Get(baseURL) + resp, err = client.R().SetBasicAuth(username, password).Get(baseURL) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) - resp, err = client.R().SetBasicAuth(username, passphrase).Get(baseURL + "/v2/") + resp, err = client.R().SetBasicAuth(username, password).Get(baseURL + "/v2/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) - resp, err = client.R(). - SetBasicAuth(username, passphrase). + resp, err = client.R().SetBasicAuth(username, password). Get(baseURL + constants.FullMgmt) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) @@ -3086,9 +3096,9 @@ func TestAuthnSessionErrors(t *testing.T) { invalidSessionID := "sessionID" // need a username different than ldap one, to test both logic - content := fmt.Sprintf("%s:$2y$05$hlbSXDp6hzDLu6VwACS39ORvVRpr3OMR4RlJ31jtlaOEGnPjKZI1m\n", htpasswdUsername) - - htpasswdPath := test.MakeHtpasswdFileFromString(content) + htpasswdUsername := test.GenerateRandomString() + htpasswdPassword := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(htpasswdUsername, htpasswdPassword)) defer os.Remove(htpasswdPath) ldapServer := newTestLDAPServer() @@ -3175,8 +3185,7 @@ func TestAuthnSessionErrors(t *testing.T) { }, } - resp, err := client.R(). - SetBasicAuth(htpasswdUsername, passphrase). + resp, err := client.R().SetBasicAuth(htpasswdUsername, htpasswdPassword). Get(baseURL + "/v2/_catalog") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) @@ -3192,8 +3201,7 @@ func TestAuthnSessionErrors(t *testing.T) { }, } - resp, err := client.R(). - SetBasicAuth(username, passphrase). + resp, err := client.R().SetBasicAuth(username, password). Get(baseURL + "/v2/_catalog") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) @@ -3335,16 +3343,14 @@ func TestAuthnSessionErrors(t *testing.T) { client.SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue) // first htpasswd saveSessionLoggedUser() error - resp, err := client.R(). - SetBasicAuth(htpasswdUsername, passphrase). + resp, err := client.R().SetBasicAuth(htpasswdUsername, htpasswdPassword). Get(baseURL + "/v2/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusInternalServerError) // second ldap saveSessionLoggedUser() error - resp, err = client.R(). - SetBasicAuth(username, passphrase). + resp, err = client.R().SetBasicAuth(username, password). Get(baseURL + "/v2/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) @@ -3448,7 +3454,7 @@ func TestAuthnSessionErrors(t *testing.T) { session.ID = invalidSessionID session.IsNew = false session.Values["authStatus"] = false - session.Values["username"] = username + session.Values["test.Username"] = username cookieStore, ok := ctlr.CookieStore.Store.(*sessions.FilesystemStore) So(ok, ShouldBeTrue) @@ -3491,7 +3497,9 @@ func TestAuthnMetaDBErrors(t *testing.T) { conf := config.New() conf.HTTP.Port = port - htpasswdPath := test.MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) mockOIDCServer, err := authutils.MockOIDCRun() @@ -3545,8 +3553,7 @@ func TestAuthnMetaDBErrors(t *testing.T) { }, } - resp, err := client.R(). - SetBasicAuth(username, passphrase). + resp, err := client.R().SetBasicAuth(username, password). Get(baseURL + "/v2/_catalog") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) @@ -3600,7 +3607,9 @@ func TestAuthorization(t *testing.T) { baseURL := test.GetBaseURL(port) conf := config.New() conf.HTTP.Port = port - htpasswdPath := test.MakeHtpasswdFile() + username := test.GenerateRandomName() + password := test.GenerateRandomName() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ @@ -3610,7 +3619,7 @@ func TestAuthorization(t *testing.T) { } conf.HTTP.AccessControl = &config.AccessControlConfig{ Repositories: config.Repositories{ - AuthorizationAllRepos: config.PolicyGroup{ + test.AuthorizationAllRepos: config.PolicyGroup{ Policies: []config.Policy{ { Users: []string{}, @@ -3670,7 +3679,7 @@ func TestAuthorization(t *testing.T) { client.SetRedirectPolicy(test.CustomRedirectPolicy(20)) mockOIDCServer.QueueUser(&mockoidc.MockUser{ - Email: "test", + Email: username, Subject: "1234567890", }) @@ -3686,7 +3695,7 @@ func TestAuthorization(t *testing.T) { client.SetCookies(resp.Cookies()) client.SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue) - RunAuthorizationTests(t, client, baseURL, conf) + RunAuthorizationTests(t, client, baseURL, username, conf) }) Convey("with basic auth", func() { @@ -3702,9 +3711,9 @@ func TestAuthorization(t *testing.T) { defer cm.StopServer() client := resty.New() - client.SetBasicAuth(username, passphrase) + client.SetBasicAuth(username, password) - RunAuthorizationTests(t, client, baseURL, conf) + RunAuthorizationTests(t, client, baseURL, username, conf) }) }) } @@ -3714,7 +3723,9 @@ func TestGetUsername(t *testing.T) { port := test.GetFreePort() baseURL := test.GetBaseURL(port) - htpasswdPath := test.MakeHtpasswdFileFromString(getCredString(username, passphrase)) + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) conf := config.New() @@ -3759,7 +3770,7 @@ func TestGetUsername(t *testing.T) { err = json.Unmarshal(resp.Body(), &e) So(err, ShouldBeNil) - resp, err = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/v2/_catalog") + resp, err = resty.R().SetBasicAuth(username, password).Get(baseURL + "/v2/_catalog") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -4010,10 +4021,9 @@ func TestAuthorizationWithAnonymousPolicyBasicAuthAndSessionHeader(t *testing.T) baseURL := test.GetBaseURL(port) badpassphrase := "bad" - htpasswdContent := fmt.Sprintf("%s:$2y$05$hlbSXDp6hzDLu6VwACS39ORvVRpr3OMR4RlJ31jtlaOEGnPjKZI1m\n", - htpasswdUsername) - - htpasswdPath := test.MakeHtpasswdFileFromString(htpasswdContent) + htpasswdUsername := test.GenerateRandomString() + htpasswdPassword := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(htpasswdUsername, htpasswdPassword)) defer os.Remove(htpasswdPath) img := CreateRandomImage() @@ -4064,16 +4074,14 @@ func TestAuthorizationWithAnonymousPolicyBasicAuthAndSessionHeader(t *testing.T) So(resp.StatusCode(), ShouldEqual, http.StatusOK) // Can access /v2 with correct credentials - resp, err = resty.R(). - SetBasicAuth(htpasswdUsername, passphrase). + resp, err = resty.R().SetBasicAuth(htpasswdUsername, htpasswdPassword). Get(baseURL + "/v2/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) // Fail to access /v2 with incorrect credentials - resp, err = resty.R(). - SetBasicAuth(htpasswdUsername, badpassphrase). + resp, err = resty.R().SetBasicAuth(htpasswdUsername, badpassphrase). Get(baseURL + "/v2/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) @@ -4098,8 +4106,7 @@ func TestAuthorizationWithAnonymousPolicyBasicAuthAndSessionHeader(t *testing.T) err = json.Unmarshal(resp.Body(), &apiError) So(err, ShouldBeNil) - resp, err = resty.R(). - SetBasicAuth(htpasswdUsername, passphrase). + resp, err = resty.R().SetBasicAuth(htpasswdUsername, htpasswdPassword). Get(baseURL + "/v2/_catalog") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) @@ -4124,7 +4131,7 @@ func TestAuthorizationWithAnonymousPolicyBasicAuthAndSessionHeader(t *testing.T) So(err, ShouldNotBeNil) err = UploadImageWithBasicAuth(img, baseURL, - TestRepo, tagAuth, htpasswdUsername, passphrase) + TestRepo, tagAuth, htpasswdUsername, htpasswdPassword) So(err, ShouldNotBeNil) err = UploadImageWithBasicAuth(img, baseURL, @@ -4145,7 +4152,7 @@ func TestAuthorizationWithAnonymousPolicyBasicAuthAndSessionHeader(t *testing.T) So(err, ShouldBeNil) err = UploadImageWithBasicAuth(img, baseURL, - TestRepo, tagAuth, htpasswdUsername, passphrase) + TestRepo, tagAuth, htpasswdUsername, htpasswdPassword) So(err, ShouldBeNil) err = UploadImageWithBasicAuth(img, baseURL, @@ -4187,8 +4194,7 @@ func TestAuthorizationWithAnonymousPolicyBasicAuthAndSessionHeader(t *testing.T) Repositories []string `json:"repositories"` }{} - resp, err = resty.R(). - SetBasicAuth(htpasswdUsername, passphrase). + resp, err = resty.R().SetBasicAuth(htpasswdUsername, htpasswdPassword). Get(baseURL + "/v2/_catalog") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) @@ -4199,8 +4205,7 @@ func TestAuthorizationWithAnonymousPolicyBasicAuthAndSessionHeader(t *testing.T) So(len(catalog.Repositories), ShouldEqual, 1) So(catalog.Repositories, ShouldContain, TestRepo) - resp, err = resty.R(). - SetBasicAuth(htpasswdUsername, badpassphrase). + resp, err = resty.R().SetBasicAuth(htpasswdUsername, badpassphrase). Get(baseURL + "/v2/_catalog") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) @@ -4215,9 +4220,13 @@ func TestAuthorizationWithMultiplePolicies(t *testing.T) { conf := config.New() conf.HTTP.Port = port - // have two users: "test" user for user Policy, and "bob" for default policy - htpasswdPath := test.MakeHtpasswdFileFromString(getCredString(username, passphrase) + - "\n" + getCredString("bob", passphrase)) + // have two users: one for user Policy, and another for default policy + username1 := test.GenerateRandomString() + password1 := test.GenerateRandomString() + username2 := test.GenerateRandomString() + password2 := test.GenerateRandomString() + content := test.GetCredString(username1, password1) + test.GetCredString(username2, password2) + htpasswdPath := test.MakeHtpasswdFileFromString(content) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ @@ -4228,7 +4237,7 @@ func TestAuthorizationWithMultiplePolicies(t *testing.T) { // config with all policy types, to test that the correct one is applied in each case conf.HTTP.AccessControl = &config.AccessControlConfig{ Repositories: config.Repositories{ - AuthorizationAllRepos: config.PolicyGroup{ + test.AuthorizationAllRepos: config.PolicyGroup{ Policies: []config.Policy{ { Users: []string{}, @@ -4312,8 +4321,8 @@ func TestAuthorizationWithMultiplePolicies(t *testing.T) { bobUserClient.SetRedirectPolicy(test.CustomRedirectPolicy(20)) mockOIDCServer.QueueUser(&mockoidc.MockUser{ - Email: "bob", - Subject: "1234567890", + Email: test.GenerateRandomString(), + Subject: test.GenerateRandomString(), }) // first login user @@ -4345,13 +4354,13 @@ func TestAuthorizationWithMultiplePolicies(t *testing.T) { cm.StartAndWait(port) defer cm.StopServer() - testUserClient := resty.New() - testUserClient.SetBasicAuth(username, passphrase) + userClient1 := resty.New() + userClient1.SetBasicAuth(username1, password1) - bobUserClient := resty.New() - bobUserClient.SetBasicAuth("bob", passphrase) + userClient2 := resty.New() + userClient2.SetBasicAuth(username2, password2) - RunAuthorizationWithMultiplePoliciesTests(t, testUserClient, bobUserClient, baseURL, conf) + RunAuthorizationWithMultiplePoliciesTests(t, userClient1, userClient2, baseURL, conf) }) }) } @@ -4363,8 +4372,9 @@ func TestInvalidCases(t *testing.T) { conf := config.New() conf.HTTP.Port = port - htpasswdPath := test.MakeHtpasswdFileFromString(getCredString(username, passphrase)) - + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ @@ -4410,7 +4420,7 @@ func TestInvalidCases(t *testing.T) { params["mount"] = digest postResponse, err := client.R(). - SetBasicAuth(username, passphrase).SetQueryParams(params). + SetBasicAuth(username, password).SetQueryParams(params). Post(fmt.Sprintf("%s/v2/%s/blobs/uploads/", baseURL, name)) So(err, ShouldBeNil) So(postResponse.StatusCode(), ShouldEqual, http.StatusInternalServerError) @@ -4420,10 +4430,10 @@ func TestInvalidCases(t *testing.T) { func TestHTTPReadOnly(t *testing.T) { Convey("Single cred", t, func() { singleCredtests := []string{} - user := ALICE - password := ALICE - singleCredtests = append(singleCredtests, getCredString(user, password)) - singleCredtests = append(singleCredtests, getCredString(user, password)+"\n") + user := test.GenerateRandomString() + password := test.GenerateRandomString() + singleCredtests = append(singleCredtests, test.GetCredString(user, password)) + singleCredtests = append(singleCredtests, test.GetCredString(user, password)+"\n") port := test.GetFreePort() baseURL := test.GetBaseURL(port) @@ -4435,7 +4445,7 @@ func TestHTTPReadOnly(t *testing.T) { // enable read-only mode conf.HTTP.AccessControl = &config.AccessControlConfig{ Repositories: config.Repositories{ - AuthorizationAllRepos: config.PolicyGroup{ + test.AuthorizationAllRepos: config.PolicyGroup{ DefaultPolicy: []string{"read"}, }, }, @@ -4459,9 +4469,10 @@ func TestHTTPReadOnly(t *testing.T) { So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) + repoName := test.GenerateRandomName() + "/" + test.GenerateRandomName() // with creds, any modifications should still fail on read-only mode resp, err := resty.R().SetBasicAuth(user, password). - Post(baseURL + "/v2/" + AuthorizedNamespace + "/blobs/uploads/") + Post(baseURL + "/v2/" + repoName + "/blobs/uploads/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusForbidden) @@ -4482,8 +4493,9 @@ func TestCrossRepoMount(t *testing.T) { conf := config.New() conf.HTTP.Port = port - htpasswdPath := test.MakeHtpasswdFileFromString(getCredString(username, passphrase)) - + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ @@ -4518,7 +4530,7 @@ func TestCrossRepoMount(t *testing.T) { params["from"] = name client := resty.New() - headResponse, err := client.R().SetBasicAuth(username, passphrase). + headResponse, err := client.R().SetBasicAuth(username, password). Head(fmt.Sprintf("%s/v2/%s/blobs/%s", baseURL, name, manifestDigest)) So(err, ShouldBeNil) So(headResponse.StatusCode(), ShouldEqual, http.StatusOK) @@ -4527,7 +4539,7 @@ func TestCrossRepoMount(t *testing.T) { params["mount"] = "sha:" postResponse, err := client.R(). - SetBasicAuth(username, passphrase).SetQueryParams(params). + SetBasicAuth(username, password).SetQueryParams(params). Post(baseURL + "/v2/zot-c-test/blobs/uploads/") So(err, ShouldBeNil) So(postResponse.StatusCode(), ShouldEqual, http.StatusAccepted) @@ -4541,7 +4553,7 @@ func TestCrossRepoMount(t *testing.T) { incorrectParams["from"] = "zot-x-test" postResponse, err = client.R(). - SetBasicAuth(username, passphrase).SetQueryParams(incorrectParams). + SetBasicAuth(username, password).SetQueryParams(incorrectParams). Post(baseURL + "/v2/zot-y-test/blobs/uploads/") So(err, ShouldBeNil) So(postResponse.StatusCode(), ShouldEqual, http.StatusAccepted) @@ -4552,7 +4564,7 @@ func TestCrossRepoMount(t *testing.T) { // This is correct request but it will return 202 because blob is not present in cache. params["mount"] = string(manifestDigest) postResponse, err = client.R(). - SetBasicAuth(username, passphrase).SetQueryParams(params). + SetBasicAuth(username, password).SetQueryParams(params). Post(baseURL + "/v2/zot-c-test/blobs/uploads/") So(err, ShouldBeNil) So(postResponse.StatusCode(), ShouldEqual, http.StatusAccepted) @@ -4561,30 +4573,30 @@ func TestCrossRepoMount(t *testing.T) { // Send same request again postResponse, err = client.R(). - SetBasicAuth(username, passphrase).SetQueryParams(params). + SetBasicAuth(username, password).SetQueryParams(params). Post(baseURL + "/v2/zot-c-test/blobs/uploads/") So(err, ShouldBeNil) So(postResponse.StatusCode(), ShouldEqual, http.StatusAccepted) // Valid requests postResponse, err = client.R(). - SetBasicAuth(username, passphrase).SetQueryParams(params). + SetBasicAuth(username, password).SetQueryParams(params). Post(baseURL + "/v2/zot-d-test/blobs/uploads/") So(err, ShouldBeNil) So(postResponse.StatusCode(), ShouldEqual, http.StatusAccepted) - headResponse, err = client.R().SetBasicAuth(username, passphrase). + headResponse, err = client.R().SetBasicAuth(username, password). Head(fmt.Sprintf("%s/v2/zot-cv-test/blobs/%s", baseURL, manifestDigest)) So(err, ShouldBeNil) So(headResponse.StatusCode(), ShouldEqual, http.StatusNotFound) postResponse, err = client.R(). - SetBasicAuth(username, passphrase).SetQueryParams(params).Post(baseURL + "/v2/zot-c-test/blobs/uploads/") + SetBasicAuth(username, password).SetQueryParams(params).Post(baseURL + "/v2/zot-c-test/blobs/uploads/") So(err, ShouldBeNil) So(postResponse.StatusCode(), ShouldEqual, http.StatusAccepted) postResponse, err = client.R(). - SetBasicAuth(username, passphrase).SetQueryParams(params). + SetBasicAuth(username, password).SetQueryParams(params). Post(baseURL + "/v2/ /blobs/uploads/") So(err, ShouldBeNil) So(postResponse.StatusCode(), ShouldEqual, http.StatusNotFound) @@ -4597,7 +4609,7 @@ func TestCrossRepoMount(t *testing.T) { } postResponse, err = client.R().SetHeader("Content-type", "application/octet-stream"). - SetBasicAuth(username, passphrase).SetQueryParam("digest", "sha256:"+blob). + SetBasicAuth(username, password).SetQueryParam("digest", "sha256:"+blob). SetBody(buf).Post(baseURL + "/v2/zot-d-test/blobs/uploads/") So(err, ShouldBeNil) So(postResponse.StatusCode(), ShouldEqual, http.StatusCreated) @@ -4625,7 +4637,7 @@ func TestCrossRepoMount(t *testing.T) { params["mount"] = string(manifestDigest) postResponse, err = client.R(). - SetBasicAuth(username, passphrase).SetQueryParams(params). + SetBasicAuth(username, password).SetQueryParams(params). Post(baseURL + "/v2/zot-mount-test/blobs/uploads/") So(err, ShouldBeNil) So(postResponse.StatusCode(), ShouldEqual, http.StatusCreated) @@ -4650,7 +4662,7 @@ func TestCrossRepoMount(t *testing.T) { params["mount"] = string(manifestDigest) params["from"] = "zot-mount-test" postResponse, err = client.R(). - SetBasicAuth(username, passphrase).SetQueryParams(params). + SetBasicAuth(username, password).SetQueryParams(params). Post(baseURL + "/v2/zot-mount1-test/blobs/uploads/") So(err, ShouldBeNil) So(postResponse.StatusCode(), ShouldEqual, http.StatusCreated) @@ -4664,7 +4676,7 @@ func TestCrossRepoMount(t *testing.T) { So(os.SameFile(cacheFi, linkFi), ShouldEqual, true) - headResponse, err = client.R().SetBasicAuth(username, passphrase). + headResponse, err = client.R().SetBasicAuth(username, password). Head(fmt.Sprintf("%s/v2/zot-cv-test/blobs/%s", baseURL, manifestDigest)) So(err, ShouldBeNil) So(headResponse.StatusCode(), ShouldEqual, http.StatusOK) @@ -4673,7 +4685,7 @@ func TestCrossRepoMount(t *testing.T) { params = make(map[string]string) params["mount"] = "sha256:" postResponse, err = client.R(). - SetBasicAuth(username, passphrase).SetQueryParams(params). + SetBasicAuth(username, password).SetQueryParams(params). Post(baseURL + "/v2/zot-mount-test/blobs/uploads/") So(err, ShouldBeNil) So(postResponse.StatusCode(), ShouldEqual, http.StatusAccepted) @@ -4681,7 +4693,7 @@ func TestCrossRepoMount(t *testing.T) { params = make(map[string]string) params["from"] = "zot-cve-test" postResponse, err = client.R(). - SetBasicAuth(username, passphrase).SetQueryParams(params). + SetBasicAuth(username, password).SetQueryParams(params). Post(baseURL + "/v2/zot-mount-test/blobs/uploads/") So(err, ShouldBeNil) So(postResponse.StatusCode(), ShouldEqual, http.StatusMethodNotAllowed) @@ -4693,7 +4705,7 @@ func TestCrossRepoMount(t *testing.T) { conf := config.New() conf.HTTP.Port = port - htpasswdPath := test.MakeHtpasswdFileFromString(getCredString(username, passphrase)) + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) @@ -4724,7 +4736,7 @@ func TestCrossRepoMount(t *testing.T) { digest := godigest.FromBytes(image.Layers[0]) name := "zot-c-test" client := resty.New() - headResponse, err := client.R().SetBasicAuth(username, passphrase). + headResponse, err := client.R().SetBasicAuth(username, password). Head(fmt.Sprintf("%s/v2/%s/blobs/%s", baseURL, name, digest)) So(err, ShouldBeNil) So(headResponse.StatusCode(), ShouldEqual, http.StatusNotFound) @@ -4834,7 +4846,13 @@ func TestParallelRequests(t *testing.T) { conf := config.New() conf.HTTP.Port = port - htpasswdPath := test.MakeHtpasswdFileFromString(getCredString(username, passphrase)) + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) + + t.Cleanup(func() { + os.Remove(htpasswdPath) + }) conf.HTTP.Auth = &config.AuthConfig{ HTPasswd: config.AuthHTPasswd{ @@ -4875,7 +4893,7 @@ func TestParallelRequests(t *testing.T) { t.Parallel() client := resty.New() - tagResponse, err := client.R().SetBasicAuth(username, passphrase). + tagResponse, err := client.R().SetBasicAuth(username, password). Get(baseURL + "/v2/" + testcase.destImageName + "/tags/list") assert.Equal(t, err, nil, "Error should be nil") assert.NotEqual(t, tagResponse.StatusCode(), http.StatusBadRequest, "bad request") @@ -4883,12 +4901,12 @@ func TestParallelRequests(t *testing.T) { manifestList := getAllManifests(path.Join(testImagesDir, testcase.srcImageName)) for _, manifest := range manifestList { - headResponse, err := client.R().SetBasicAuth(username, passphrase). + headResponse, err := client.R().SetBasicAuth(username, password). Head(baseURL + "/v2/" + testcase.destImageName + "/manifests/" + manifest) assert.Equal(t, err, nil, "Error should be nil") assert.Equal(t, headResponse.StatusCode(), http.StatusNotFound, "response status code should return 404") - getResponse, err := client.R().SetBasicAuth(username, passphrase). + getResponse, err := client.R().SetBasicAuth(username, password). Get(baseURL + "/v2/" + testcase.destImageName + "/manifests/" + manifest) assert.Equal(t, err, nil, "Error should be nil") assert.Equal(t, getResponse.StatusCode(), http.StatusNotFound, "response status code should return 404") @@ -4898,16 +4916,14 @@ func TestParallelRequests(t *testing.T) { for _, blob := range blobList { // Get request of blob - headResponse, err := client.R(). - SetBasicAuth(username, passphrase). + headResponse, err := client.R().SetBasicAuth(username, password). Head(baseURL + "/v2/" + testcase.destImageName + "/blobs/sha256:" + blob) assert.Equal(t, err, nil, "Should not be nil") assert.NotEqual(t, headResponse.StatusCode(), http.StatusInternalServerError, "internal server error should not occurred") - getResponse, err := client.R(). - SetBasicAuth(username, passphrase). + getResponse, err := client.R().SetBasicAuth(username, password). Get(baseURL + "/v2/" + testcase.destImageName + "/blobs/sha256:" + blob) assert.Equal(t, err, nil, "Should not be nil") @@ -4924,7 +4940,7 @@ func TestParallelRequests(t *testing.T) { // Post request of blob postResponse, err := client.R(). SetHeader("Content-type", "application/octet-stream"). - SetBasicAuth(username, passphrase). + SetBasicAuth(username, password). SetBody(buf).Post(baseURL + "/v2/" + testcase.destImageName + "/blobs/uploads/") assert.Equal(t, err, nil, "Error should be nil") @@ -4935,7 +4951,7 @@ func TestParallelRequests(t *testing.T) { if run%2 == 0 { postResponse, err = client.R(). SetHeader("Content-type", "application/octet-stream"). - SetBasicAuth(username, passphrase). + SetBasicAuth(username, password). SetBody(buf). Post(baseURL + "/v2/" + testcase.destImageName + "/blobs/uploads/") @@ -4982,7 +4998,7 @@ func TestParallelRequests(t *testing.T) { SetHeader("Content-Type", "application/octet-stream"). SetHeader("Content-Length", fmt.Sprintf("%d", nbytes)). SetHeader("Content-Range", fmt.Sprintf("%d", readContent)+"-"+fmt.Sprintf("%d", readContent+nbytes-1)). - SetBasicAuth(username, passphrase). + SetBasicAuth(username, password). Patch(baseURL + "/v2/" + testcase.destImageName + "/blobs/uploads/" + sessionID) assert.Equal(t, err, nil, "Error should be nil") @@ -5003,7 +5019,7 @@ func TestParallelRequests(t *testing.T) { // Patch request of blob patchResponse, err := client.R().SetBody(buf[0:nbytes]).SetHeader("Content-type", "application/octet-stream"). - SetBasicAuth(username, passphrase). + SetBasicAuth(username, password). Patch(baseURL + "/v2/" + testcase.destImageName + "/blobs/uploads/" + sessionID) if err != nil { panic(err) @@ -5017,7 +5033,7 @@ func TestParallelRequests(t *testing.T) { } else { postResponse, err = client.R(). SetHeader("Content-type", "application/octet-stream"). - SetBasicAuth(username, passphrase). + SetBasicAuth(username, password). SetBody(buf).SetQueryParam("digest", "sha256:"+blob). Post(baseURL + "/v2/" + testcase.destImageName + "/blobs/uploads/") @@ -5027,26 +5043,26 @@ func TestParallelRequests(t *testing.T) { } headResponse, err = client.R(). - SetBasicAuth(username, passphrase). + SetBasicAuth(username, password). Head(baseURL + "/v2/" + testcase.destImageName + "/blobs/sha256:" + blob) assert.Equal(t, err, nil, "Should not be nil") assert.NotEqual(t, headResponse.StatusCode(), http.StatusInternalServerError, "response should return success code") getResponse, err = client.R(). - SetBasicAuth(username, passphrase). + SetBasicAuth(username, password). Get(baseURL + "/v2/" + testcase.destImageName + "/blobs/sha256:" + blob) assert.Equal(t, err, nil, "Should not be nil") assert.NotEqual(t, getResponse.StatusCode(), http.StatusInternalServerError, "response should return success code") } - tagResponse, err = client.R().SetBasicAuth(username, passphrase). + tagResponse, err = client.R().SetBasicAuth(username, password). Get(baseURL + "/v2/" + testcase.destImageName + "/tags/list") assert.Equal(t, err, nil, "Error should be nil") assert.Equal(t, tagResponse.StatusCode(), http.StatusOK, "response status code should return success code") - repoResponse, err := client.R().SetBasicAuth(username, passphrase). + repoResponse, err := client.R().SetBasicAuth(username, password). Get(baseURL + constants.RoutePrefix + constants.ExtCatalogPrefix) assert.Equal(t, err, nil, "Error should be nil") assert.Equal(t, repoResponse.StatusCode(), http.StatusOK, "response status code should return success code") @@ -7173,7 +7189,7 @@ func TestManifestCollision(t *testing.T) { conf.HTTP.AccessControl = &config.AccessControlConfig{ Repositories: config.Repositories{ - AuthorizationAllRepos: config.PolicyGroup{ + test.AuthorizationAllRepos: config.PolicyGroup{ AnonymousPolicy: []string{ constants.ReadPermission, constants.CreatePermission, @@ -7231,9 +7247,9 @@ func TestManifestCollision(t *testing.T) { So(resp.StatusCode(), ShouldEqual, http.StatusConflict) // remove detectManifestCollision action from ** (all repos) - repoPolicy := conf.HTTP.AccessControl.Repositories[AuthorizationAllRepos] + repoPolicy := conf.HTTP.AccessControl.Repositories[test.AuthorizationAllRepos] repoPolicy.AnonymousPolicy = []string{"read", "delete"} - conf.HTTP.AccessControl.Repositories[AuthorizationAllRepos] = repoPolicy + conf.HTTP.AccessControl.Repositories[test.AuthorizationAllRepos] = repoPolicy resp, err = resty.R().Delete(baseURL + "/v2/index/manifests/" + digest.String()) So(err, ShouldBeNil) @@ -8246,7 +8262,7 @@ func TestSearchRoutes(t *testing.T) { user1 := "test" password1 := "test" - testString1 := getCredString(user1, password1) + testString1 := test.GetCredString(user1, password1) htpasswdPath := test.MakeHtpasswdFileFromString(testString1) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ @@ -8395,7 +8411,7 @@ func TestSearchRoutes(t *testing.T) { user1 := "test1" password1 := "test1" group1 := "testgroup3" - testString1 := getCredString(user1, password1) + testString1 := test.GetCredString(user1, password1) htpasswdPath := test.MakeHtpasswdFileFromString(testString1) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ @@ -8478,7 +8494,7 @@ func TestSearchRoutes(t *testing.T) { password1 := "test2" group1 := "testgroup1" group2 := "secondtestgroup" - testString1 := getCredString(user1, password1) + testString1 := test.GetCredString(user1, password1) htpasswdPath := test.MakeHtpasswdFileFromString(testString1) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ @@ -8546,7 +8562,7 @@ func TestSearchRoutes(t *testing.T) { user1 := "test3" password1 := "test3" group1 := "testgroup" - testString1 := getCredString(user1, password1) + testString1 := test.GetCredString(user1, password1) htpasswdPath := test.MakeHtpasswdFileFromString(testString1) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ @@ -8614,7 +8630,7 @@ func TestSearchRoutes(t *testing.T) { user1 := "test4" password1 := "test4" group1 := "testgroup1" - testString1 := getCredString(user1, password1) + testString1 := test.GetCredString(user1, password1) htpasswdPath := test.MakeHtpasswdFileFromString(testString1) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ @@ -8682,7 +8698,7 @@ func TestSearchRoutes(t *testing.T) { user1 := "test5" password1 := "test5" group1 := "testgroup2" - testString1 := getCredString(user1, password1) + testString1 := test.GetCredString(user1, password1) htpasswdPath := test.MakeHtpasswdFileFromString(testString1) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ @@ -8736,13 +8752,12 @@ func TestSearchRoutes(t *testing.T) { conf.HTTP.Port = port defaultVal := true - group1 := group - user1 := username - password1 := passphrase - - testString1 := getCredString(user1, password1) - htpasswdPath := test.MakeHtpasswdFileFromString(testString1) + group1 := test.GenerateRandomString() + user1 := test.GenerateRandomString() + password1 := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(user1, password1)) defer os.Remove(htpasswdPath) + conf.HTTP.Auth = &config.AuthConfig{ HTPasswd: config.AuthHTPasswd{ Path: htpasswdPath, @@ -9165,9 +9180,9 @@ func RunAuthorizationWithMultiplePoliciesTests(t *testing.T, userClient *resty.C So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 401) - repoPolicy := conf.HTTP.AccessControl.Repositories[AuthorizationAllRepos] + repoPolicy := conf.HTTP.AccessControl.Repositories[test.AuthorizationAllRepos] repoPolicy.AnonymousPolicy = append(repoPolicy.AnonymousPolicy, "read") - conf.HTTP.AccessControl.Repositories[AuthorizationAllRepos] = repoPolicy + conf.HTTP.AccessControl.Repositories[test.AuthorizationAllRepos] = repoPolicy // should have access to /v2/, anonymous policy is applied, "read" allowed resp, err = resty.R().Get(baseURL + "/v2/") @@ -9216,7 +9231,7 @@ func RunAuthorizationWithMultiplePoliciesTests(t *testing.T, userClient *resty.C So(resp.StatusCode(), ShouldEqual, http.StatusForbidden) repoPolicy.DefaultPolicy = append(repoPolicy.DefaultPolicy, "read") - conf.HTTP.AccessControl.Repositories[AuthorizationAllRepos] = repoPolicy + conf.HTTP.AccessControl.Repositories[test.AuthorizationAllRepos] = repoPolicy // with read permission should get 200, because default policy allows reading now resp, err = userClient.R().Get(baseURL + "/v2/" + AuthorizationNamespace + "/tags/list") @@ -9286,7 +9301,7 @@ func RunAuthorizationWithMultiplePoliciesTests(t *testing.T, userClient *resty.C So(catalog.Repositories, ShouldContain, AuthorizationNamespace) // no policy - conf.HTTP.AccessControl.Repositories[AuthorizationAllRepos] = config.PolicyGroup{} + conf.HTTP.AccessControl.Repositories[test.AuthorizationAllRepos] = config.PolicyGroup{} // no policies, so no anonymous allowed resp, err = resty.R().Get(baseURL + "/v2/_catalog") @@ -9315,7 +9330,7 @@ func RunAuthorizationWithMultiplePoliciesTests(t *testing.T, userClient *resty.C So(len(catalog.Repositories), ShouldEqual, 0) } -func RunAuthorizationTests(t *testing.T, client *resty.Client, baseURL string, conf *config.Config) { +func RunAuthorizationTests(t *testing.T, client *resty.Client, baseURL, user string, conf *config.Config) { t.Helper() Convey("run authorization tests", func() { @@ -9351,9 +9366,8 @@ func RunAuthorizationTests(t *testing.T, client *resty.Client, baseURL string, c // first let's use global based policies // add test user to global policy with create perm - conf.HTTP.AccessControl.Repositories[AuthorizationAllRepos].Policies[0].Users = append(conf.HTTP.AccessControl.Repositories[AuthorizationAllRepos].Policies[0].Users, "test") //nolint:lll // gofumpt conflicts with lll - - conf.HTTP.AccessControl.Repositories[AuthorizationAllRepos].Policies[0].Actions = append(conf.HTTP.AccessControl.Repositories[AuthorizationAllRepos].Policies[0].Actions, "create") //nolint:lll // gofumpt conflicts with lll + conf.HTTP.AccessControl.Repositories[test.AuthorizationAllRepos].Policies[0].Users = append(conf.HTTP.AccessControl.Repositories[test.AuthorizationAllRepos].Policies[0].Users, user) //nolint:lll // gofumpt conflicts with lll + conf.HTTP.AccessControl.Repositories[test.AuthorizationAllRepos].Policies[0].Actions = append(conf.HTTP.AccessControl.Repositories[test.AuthorizationAllRepos].Policies[0].Actions, "create") //nolint:lll // gofumpt conflicts with lll // now it should get 202 resp, err = client.R().Post(baseURL + "/v2/" + AuthorizationNamespace + "/blobs/uploads/") @@ -9386,7 +9400,7 @@ func RunAuthorizationTests(t *testing.T, client *resty.Client, baseURL string, c So(resp.StatusCode(), ShouldEqual, http.StatusForbidden) // get tags with read access should get 200 - conf.HTTP.AccessControl.Repositories[AuthorizationAllRepos].Policies[0].Actions = append(conf.HTTP.AccessControl.Repositories[AuthorizationAllRepos].Policies[0].Actions, "read") //nolint:lll // gofumpt conflicts with lll + conf.HTTP.AccessControl.Repositories[test.AuthorizationAllRepos].Policies[0].Actions = append(conf.HTTP.AccessControl.Repositories[test.AuthorizationAllRepos].Policies[0].Actions, "read") //nolint:lll // gofumpt conflicts with lll resp, err = client.R().Get(baseURL + "/v2/" + AuthorizationNamespace + "/tags/list") So(err, ShouldBeNil) @@ -9412,7 +9426,7 @@ func RunAuthorizationTests(t *testing.T, client *resty.Client, baseURL string, c So(resp.StatusCode(), ShouldEqual, http.StatusForbidden) // add delete perm on repo - conf.HTTP.AccessControl.Repositories[AuthorizationAllRepos].Policies[0].Actions = append(conf.HTTP.AccessControl.Repositories[AuthorizationAllRepos].Policies[0].Actions, "delete") //nolint:lll // gofumpt conflicts with lll + conf.HTTP.AccessControl.Repositories[test.AuthorizationAllRepos].Policies[0].Actions = append(conf.HTTP.AccessControl.Repositories[test.AuthorizationAllRepos].Policies[0].Actions, "delete") //nolint:lll // gofumpt conflicts with lll // delete blob should get 202 resp, err = client.R().Delete(baseURL + "/v2/" + AuthorizationNamespace + "/blobs/" + digest) @@ -9433,7 +9447,7 @@ func RunAuthorizationTests(t *testing.T, client *resty.Client, baseURL string, c DefaultPolicy: []string{}, } - conf.HTTP.AccessControl.Repositories[AuthorizationNamespace].Policies[0].Users = append(conf.HTTP.AccessControl.Repositories[AuthorizationNamespace].Policies[0].Users, "test") //nolint:lll // gofumpt conflicts with lll + conf.HTTP.AccessControl.Repositories[AuthorizationNamespace].Policies[0].Users = append(conf.HTTP.AccessControl.Repositories[AuthorizationNamespace].Policies[0].Users, user) //nolint:lll // gofumpt conflicts with lll conf.HTTP.AccessControl.Repositories[AuthorizationNamespace].Policies[0].Actions = append(conf.HTTP.AccessControl.Repositories[AuthorizationNamespace].Policies[0].Actions, "create") //nolint:lll // gofumpt conflicts with lll // now it should get 202 @@ -9507,10 +9521,10 @@ func RunAuthorizationTests(t *testing.T, client *resty.Client, baseURL string, c So(resp.StatusCode(), ShouldEqual, http.StatusAccepted) // remove permissions on **/* so it will not interfere with zot-test namespace - repoPolicy := conf.HTTP.AccessControl.Repositories[AuthorizationAllRepos] + repoPolicy := conf.HTTP.AccessControl.Repositories[test.AuthorizationAllRepos] repoPolicy.Policies = []config.Policy{} repoPolicy.DefaultPolicy = []string{} - conf.HTTP.AccessControl.Repositories[AuthorizationAllRepos] = repoPolicy + conf.HTTP.AccessControl.Repositories[test.AuthorizationAllRepos] = repoPolicy // get manifest should get 403, we don't have perm at all on this repo resp, err = client.R().Get(baseURL + "/v2/zot-test/manifests/0.0.1") @@ -9521,7 +9535,7 @@ func RunAuthorizationTests(t *testing.T, client *resty.Client, baseURL string, c // add read perm on repo conf.HTTP.AccessControl.Repositories["zot-test"] = config.PolicyGroup{Policies: []config.Policy{ { - Users: []string{"test"}, + Users: []string{user}, Actions: []string{"read"}, }, }, DefaultPolicy: []string{}} @@ -9729,7 +9743,7 @@ func RunAuthorizationTests(t *testing.T, client *resty.Client, baseURL string, c So(resp.StatusCode(), ShouldEqual, http.StatusForbidden) // add read perm - conf.HTTP.AccessControl.AdminPolicy.Users = append(conf.HTTP.AccessControl.AdminPolicy.Users, "test") + conf.HTTP.AccessControl.AdminPolicy.Users = append(conf.HTTP.AccessControl.AdminPolicy.Users, user) conf.HTTP.AccessControl.AdminPolicy.Actions = append(conf.HTTP.AccessControl.AdminPolicy.Actions, "read") // with read perm should get 200 diff --git a/pkg/api/routes.go b/pkg/api/routes.go index 1db9a8044b..6cd5d9a73b 100644 --- a/pkg/api/routes.go +++ b/pkg/api/routes.go @@ -183,7 +183,7 @@ func (rh *RouteHandler) SetupRoutes() { pprof.SetupPprofRoutes(rh.c.Config, prefixedRouter, authHandler, rh.c.Log) // Preconditions for enabling the actual extension routes are part of extensions themselves - ext.SetupMetricsRoutes(rh.c.Config, rh.c.Router, authHandler, rh.c.Log, rh.c.Metrics) + ext.SetupMetricsRoutes(rh.c.Config, rh.c.Router, authHandler, MetricsAuthzHandler(rh.c), rh.c.Log, rh.c.Metrics) ext.SetupSearchRoutes(rh.c.Config, prefixedRouter, rh.c.StoreController, rh.c.MetaDB, rh.c.CveScanner, rh.c.Log) ext.SetupImageTrustRoutes(rh.c.Config, prefixedRouter, rh.c.MetaDB, rh.c.Log) diff --git a/pkg/api/routes_test.go b/pkg/api/routes_test.go index 554aff1922..86d7c94bd4 100644 --- a/pkg/api/routes_test.go +++ b/pkg/api/routes_test.go @@ -44,8 +44,11 @@ func TestRoutes(t *testing.T) { conf := config.New() conf.HTTP.Port = port - htpasswdPath := test.MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) + mockOIDCServer, err := mockoidc.Run() if err != nil { panic(err) diff --git a/pkg/cli/client/client_test.go b/pkg/cli/client/client_test.go index 6192d44102..87f19c695b 100644 --- a/pkg/cli/client/client_test.go +++ b/pkg/cli/client/client_test.go @@ -25,18 +25,13 @@ import ( ) const ( - BaseURL1 = "http://127.0.0.1:8088" BaseSecureURL1 = "https://127.0.0.1:8088" HOST1 = "127.0.0.1:8088" SecurePort1 = "8088" - BaseURL2 = "http://127.0.0.1:8089" BaseSecureURL2 = "https://127.0.0.1:8089" SecurePort2 = "8089" - BaseURL3 = "http://127.0.0.1:8090" BaseSecureURL3 = "https://127.0.0.1:8090" SecurePort3 = "8090" - username = "test" - passphrase = "test" ServerCert = "../../../test/data/server.cert" ServerKey = "../../../test/data/server.key" CACert = "../../../test/data/ca.crt" @@ -55,7 +50,9 @@ func TestTLSWithAuth(t *testing.T) { defer func() { resty.SetTLSClientConfig(nil) }() conf := config.New() conf.HTTP.Port = SecurePort1 - htpasswdPath := test.MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ @@ -116,7 +113,7 @@ func TestTLSWithAuth(t *testing.T) { So(err, ShouldNotBeNil) So(imageBuff.String(), ShouldContainSubstring, "check credentials") - user := fmt.Sprintf("%s:%s", username, passphrase) + user := fmt.Sprintf("%s:%s", username, password) args = []string{"-u", user, "--config", "imagetest"} configPath = makeConfigFile( fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s%s%s","showspinner":false}]}`, diff --git a/pkg/debug/pprof/pprof_test.go b/pkg/debug/pprof/pprof_test.go index f1ceb6c9a5..43cf1eb8cd 100644 --- a/pkg/debug/pprof/pprof_test.go +++ b/pkg/debug/pprof/pprof_test.go @@ -22,14 +22,14 @@ func TestProfilingAuthz(t *testing.T) { Convey("Make a new controller", t, func() { port := test.GetFreePort() baseURL := test.GetBaseURL(port) - adminUsername := "admin" - adminPassword := "admin" - username := "test" - password := "test" - authorizationAllRepos := "**" + adminUsername := test.GenerateRandomString() + adminPassword := test.GenerateRandomString() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + authorizationAllRepos := test.AuthorizationAllRepos testCreds := test.GetCredString(adminUsername, adminPassword) + - "\n" + test.GetCredString(username, password) + test.GetCredString(username, password) htpasswdPath := test.MakeHtpasswdFileFromString(testCreds) defer os.Remove(htpasswdPath) diff --git a/pkg/extensions/README.md b/pkg/extensions/README.md index a6cb9ba33a..6f9df76ba3 100644 --- a/pkg/extensions/README.md +++ b/pkg/extensions/README.md @@ -30,9 +30,9 @@ package extensions IsAdmin bool Username string Groups []string - } + } ``` - This data can then be accessed from the request context so that every extension can apply its own authorization logic, if needed . + This data can then be accessed from the request context so that every extension can apply its own authorization logic, if needed . - when a new extension comes out, the developer should also write some blackbox tests, where a binary that contains the new extension should be tested in a real usage scenario. See [test/blackbox](test/blackbox/sync.bats) folder for multiple extensions examples. @@ -40,6 +40,6 @@ package extensions - with every new extension, you should modify the EXTENSIONS variable in Makefile by adding the new extension. The EXTENSIONS variable represents all extensions and is used in Make targets that require them all (e.g make test). -- the available extensions that can be used at the moment are: sync, scrub, metrics, search . +- the available extensions that can be used at the moment are: sync, search, scrub, metrics, lint, ui, mgmt, userprefs, imagetrust . NOTE: When multiple extensions are used, they should be listed in the above presented order. diff --git a/pkg/extensions/extension_metrics.go b/pkg/extensions/extension_metrics.go index 54e71982fa..1837d7ef78 100644 --- a/pkg/extensions/extension_metrics.go +++ b/pkg/extensions/extension_metrics.go @@ -26,13 +26,14 @@ func EnableMetricsExtension(config *config.Config, log log.Logger, rootDir strin } func SetupMetricsRoutes(config *config.Config, router *mux.Router, - authFunc mux.MiddlewareFunc, log log.Logger, metrics monitoring.MetricServer, + authnFunc, authzFunc mux.MiddlewareFunc, log log.Logger, metrics monitoring.MetricServer, ) { log.Info().Msg("setting up metrics routes") if config.IsMetricsEnabled() { extRouter := router.PathPrefix(config.Extensions.Metrics.Prometheus.Path).Subrouter() - extRouter.Use(authFunc) + extRouter.Use(authnFunc) + extRouter.Use(authzFunc) extRouter.Methods("GET").Handler(promhttp.Handler()) } } diff --git a/pkg/extensions/extension_metrics_disabled.go b/pkg/extensions/extension_metrics_disabled.go index 6d280b9ba6..624fc06125 100644 --- a/pkg/extensions/extension_metrics_disabled.go +++ b/pkg/extensions/extension_metrics_disabled.go @@ -22,13 +22,14 @@ func EnableMetricsExtension(config *config.Config, log log.Logger, rootDir strin // SetupMetricsRoutes ... func SetupMetricsRoutes(conf *config.Config, router *mux.Router, - authFunc mux.MiddlewareFunc, log log.Logger, metrics monitoring.MetricServer, + authnFunc, authzFunc mux.MiddlewareFunc, log log.Logger, metrics monitoring.MetricServer, ) { getMetrics := func(w http.ResponseWriter, r *http.Request) { m := metrics.ReceiveMetrics() zcommon.WriteJSON(w, http.StatusOK, m) } - router.Use(authFunc) + router.Use(authnFunc) + router.Use(authzFunc) router.HandleFunc("/metrics", getMetrics).Methods("GET") } diff --git a/pkg/extensions/extensions_test.go b/pkg/extensions/extensions_test.go index 9f10636751..de1e8ce6cb 100644 --- a/pkg/extensions/extensions_test.go +++ b/pkg/extensions/extensions_test.go @@ -140,7 +140,9 @@ func TestMgmtExtension(t *testing.T) { mockOIDCConfig := mockOIDCServer.Config() Convey("Verify mgmt auth info route enabled with htpasswd", t, func() { - htpasswdPath := test.MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) conf.HTTP.Auth.HTPasswd.Path = htpasswdPath conf.Extensions = &extconf.ExtensionConfig{} @@ -202,7 +204,7 @@ func TestMgmtExtension(t *testing.T) { So(mgmtResp.HTTP.Auth.LDAP, ShouldBeNil) // with credentials - resp, err = resty.R().SetBasicAuth("test", "test").Get(baseURL + constants.FullMgmt) + resp, err = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullMgmt) So(err, ShouldBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -215,12 +217,13 @@ func TestMgmtExtension(t *testing.T) { So(mgmtResp.HTTP.Auth.LDAP, ShouldBeNil) // with wrong credentials - resp, err = resty.R().SetBasicAuth("test", "wrong").Get(baseURL + constants.FullMgmt) + resp, err = resty.R().SetBasicAuth(username, "wrong").Get(baseURL + constants.FullMgmt) So(err, ShouldBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized) }) Convey("Verify mgmt auth info route enabled with ldap", t, func() { + defer os.Remove(conf.HTTP.Auth.HTPasswd.Path) // cleanup of a file created in previous Convey conf.HTTP.Auth.LDAP = &config.LDAPConfig{ BindDN: "binddn", BaseDN: "basedn", @@ -281,7 +284,10 @@ func TestMgmtExtension(t *testing.T) { }) Convey("Verify mgmt auth info route enabled with htpasswd + ldap", t, func() { - htpasswdPath := test.MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) + defer os.Remove(htpasswdPath) conf.HTTP.Auth.HTPasswd.Path = htpasswdPath conf.HTTP.Auth.LDAP = &config.LDAPConfig{ BindDN: "binddn", @@ -342,7 +348,7 @@ func TestMgmtExtension(t *testing.T) { So(mgmtResp.HTTP.Auth.Bearer, ShouldBeNil) // with credentials - resp, err = resty.R().SetBasicAuth("test", "test").Get(baseURL + constants.FullMgmt) + resp, err = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullMgmt) So(err, ShouldBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -356,7 +362,10 @@ func TestMgmtExtension(t *testing.T) { }) Convey("Verify mgmt auth info route enabled with htpasswd + ldap + bearer", t, func() { - htpasswdPath := test.MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) + defer os.Remove(htpasswdPath) conf.HTTP.Auth.HTPasswd.Path = htpasswdPath conf.HTTP.Auth.LDAP = &config.LDAPConfig{ BindDN: "binddn", @@ -420,7 +429,7 @@ func TestMgmtExtension(t *testing.T) { So(mgmtResp.HTTP.Auth.Bearer.Service, ShouldEqual, "service") // with credentials - resp, err = resty.R().SetBasicAuth("test", "test").Get(baseURL + constants.FullMgmt) + resp, err = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullMgmt) So(err, ShouldBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -629,7 +638,10 @@ func TestMgmtExtension(t *testing.T) { }) Convey("Verify mgmt auth info route enabled with empty openID provider list", t, func() { - htpasswdPath := test.MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) + defer os.Remove(htpasswdPath) conf.HTTP.Auth.HTPasswd.Path = htpasswdPath conf.HTTP.Auth.LDAP = nil diff --git a/pkg/extensions/lint/lint_test.go b/pkg/extensions/lint/lint_test.go index 9a784bf570..5f42d82554 100644 --- a/pkg/extensions/lint/lint_test.go +++ b/pkg/extensions/lint/lint_test.go @@ -28,19 +28,6 @@ import ( ociutils "zotregistry.io/zot/pkg/test/oci-utils" ) -const ( - username = "test" - passphrase = "test" - ServerCert = "../../test/data/server.cert" - ServerKey = "../../test/data/server.key" - CACert = "../../test/data/ca.crt" - AuthorizedNamespace = "everyone/isallowed" - UnauthorizedNamespace = "fortknox/notallowed" - ALICE = "alice" - AuthorizationNamespace = "authz/image" - AuthorizationAllRepos = "**" -) - func TestVerifyMandatoryAnnotations(t *testing.T) { //nolint: dupl Convey("Mandatory annotations disabled", t, func() { @@ -67,8 +54,7 @@ func TestVerifyMandatoryAnnotations(t *testing.T) { cm.StartAndWait(port) defer cm.StopServer() - resp, err := resty.R().SetBasicAuth(username, passphrase). - Get(baseURL + "/v2/zot-test/manifests/0.0.1") + resp, err := resty.R().Get(baseURL + "/v2/zot-test/manifests/0.0.1") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -114,8 +100,7 @@ func TestVerifyMandatoryAnnotations(t *testing.T) { cm.StartAndWait(port) defer cm.StopServer() - resp, err := resty.R().SetBasicAuth(username, passphrase). - Get(baseURL + "/v2/zot-test/manifests/0.0.1") + resp, err := resty.R().Get(baseURL + "/v2/zot-test/manifests/0.0.1") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -161,8 +146,7 @@ func TestVerifyMandatoryAnnotations(t *testing.T) { cm.StartAndWait(port) defer cm.StopServer() - resp, err := resty.R().SetBasicAuth(username, passphrase). - Get(baseURL + "/v2/zot-test/manifests/0.0.1") + resp, err := resty.R().Get(baseURL + "/v2/zot-test/manifests/0.0.1") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -214,8 +198,7 @@ func TestVerifyMandatoryAnnotations(t *testing.T) { cm.StartAndWait(port) defer cm.StopServer() - resp, err := resty.R().SetBasicAuth(username, passphrase). - Get(baseURL + "/v2/zot-test/manifests/0.0.1") + resp, err := resty.R().Get(baseURL + "/v2/zot-test/manifests/0.0.1") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -232,8 +215,7 @@ func TestVerifyMandatoryAnnotations(t *testing.T) { configDigest := manifest.Config.Digest - resp, err = resty.R().SetBasicAuth(username, passphrase). - Get(baseURL + fmt.Sprintf("/v2/zot-test/blobs/%s", configDigest)) + resp, err = resty.R().Get(baseURL + fmt.Sprintf("/v2/zot-test/blobs/%s", configDigest)) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -302,8 +284,7 @@ func TestVerifyMandatoryAnnotations(t *testing.T) { cm.StartAndWait(port) defer cm.StopServer() - resp, err := resty.R().SetBasicAuth(username, passphrase). - Get(baseURL + "/v2/zot-test/manifests/0.0.1") + resp, err := resty.R().Get(baseURL + "/v2/zot-test/manifests/0.0.1") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -319,8 +300,7 @@ func TestVerifyMandatoryAnnotations(t *testing.T) { configDigest := manifest.Config.Digest - resp, err = resty.R().SetBasicAuth(username, passphrase). - Get(baseURL + fmt.Sprintf("/v2/zot-test/blobs/%s", configDigest)) + resp, err = resty.R().Get(baseURL + fmt.Sprintf("/v2/zot-test/blobs/%s", configDigest)) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -389,8 +369,7 @@ func TestVerifyMandatoryAnnotations(t *testing.T) { cm.StartAndWait(port) defer cm.StopServer() - resp, err := resty.R().SetBasicAuth(username, passphrase). - Get(baseURL + "/v2/zot-test/manifests/0.0.1") + resp, err := resty.R().Get(baseURL + "/v2/zot-test/manifests/0.0.1") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -445,8 +424,7 @@ func TestVerifyMandatoryAnnotations(t *testing.T) { cm.StartAndWait(port) defer cm.StopServer() - resp, err := resty.R().SetBasicAuth(username, passphrase). - Get(baseURL + "/v2/zot-test/manifests/0.0.1") + resp, err := resty.R().Get(baseURL + "/v2/zot-test/manifests/0.0.1") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) diff --git a/pkg/extensions/monitoring/monitoring_test.go b/pkg/extensions/monitoring/monitoring_test.go index 9b5089f01b..93df56acf6 100644 --- a/pkg/extensions/monitoring/monitoring_test.go +++ b/pkg/extensions/monitoring/monitoring_test.go @@ -5,6 +5,7 @@ package monitoring_test import ( "net/http" + "os" "testing" "time" @@ -103,3 +104,308 @@ func TestExtensionMetrics(t *testing.T) { So(resp.StatusCode(), ShouldEqual, http.StatusNotFound) }) } + +func TestMetricsAuthentication(t *testing.T) { + Convey("test metrics without authentication and metrics enabled", t, func() { + port := test.GetFreePort() + baseURL := test.GetBaseURL(port) + conf := config.New() + conf.HTTP.Port = port + + ctlr := api.NewController(conf) + ctlr.Config.Storage.RootDirectory = t.TempDir() + + cm := test.NewControllerManager(ctlr) + cm.StartAndWait(port) + defer cm.StopServer() + + // metrics endpoint not available + resp, err := resty.R().Get(baseURL + "/metrics") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusNotFound) + }) + Convey("test metrics without authentication and with metrics enabled", t, func() { + port := test.GetFreePort() + baseURL := test.GetBaseURL(port) + conf := config.New() + conf.HTTP.Port = port + enabled := true + metricsConfig := &extconf.MetricsConfig{ + BaseConfig: extconf.BaseConfig{Enable: &enabled}, + Prometheus: &extconf.PrometheusConfig{Path: "/metrics"}, + } + conf.Extensions = &extconf.ExtensionConfig{ + Metrics: metricsConfig, + } + + ctlr := api.NewController(conf) + ctlr.Config.Storage.RootDirectory = t.TempDir() + + cm := test.NewControllerManager(ctlr) + cm.StartAndWait(port) + defer cm.StopServer() + + // without auth set metrics endpoint is available + resp, err := resty.R().Get(baseURL + "/metrics") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusOK) + }) + Convey("test metrics with authentication and metrics enabled", t, func() { + port := test.GetFreePort() + baseURL := test.GetBaseURL(port) + conf := config.New() + conf.HTTP.Port = port + + username := test.GenerateRandomString() + password := test.GenerateRandomString() + metricsuser := test.GenerateRandomString() + metricspass := test.GenerateRandomString() + content := test.GetCredString(username, password) + test.GetCredString(metricsuser, metricspass) + htpasswdPath := test.MakeHtpasswdFileFromString(content) + defer os.Remove(htpasswdPath) + + conf.HTTP.Auth = &config.AuthConfig{ + HTPasswd: config.AuthHTPasswd{ + Path: htpasswdPath, + }, + } + + enabled := true + metricsConfig := &extconf.MetricsConfig{ + BaseConfig: extconf.BaseConfig{Enable: &enabled}, + Prometheus: &extconf.PrometheusConfig{Path: "/metrics"}, + } + conf.Extensions = &extconf.ExtensionConfig{ + Metrics: metricsConfig, + } + + ctlr := api.NewController(conf) + ctlr.Config.Storage.RootDirectory = t.TempDir() + + cm := test.NewControllerManager(ctlr) + cm.StartAndWait(port) + defer cm.StopServer() + + // without credentials + resp, err := resty.R().Get(baseURL + "/metrics") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized) + + // with wrong credentials + resp, err = resty.R().SetBasicAuth("atacker", "wrongpassword").Get(baseURL + "/metrics") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized) + + // authenticated users + resp, err = resty.R().SetBasicAuth(username, password).Get(baseURL + "/metrics") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusOK) + + resp, err = resty.R().SetBasicAuth(metricsuser, metricspass).Get(baseURL + "/metrics") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusOK) + }) +} + +func TestMetricsAuthorization(t *testing.T) { + Convey("Make a new controller with auth & metrics enabled", t, func() { + port := test.GetFreePort() + baseURL := test.GetBaseURL(port) + conf := config.New() + conf.HTTP.Port = port + + username := test.GenerateRandomString() + password := test.GenerateRandomString() + metricsuser := test.GenerateRandomString() + metricspass := test.GenerateRandomString() + content := test.GetCredString(username, password) + test.GetCredString(metricsuser, metricspass) + htpasswdPath := test.MakeHtpasswdFileFromString(content) + defer os.Remove(htpasswdPath) + + conf.HTTP.Auth = &config.AuthConfig{ + HTPasswd: config.AuthHTPasswd{ + Path: htpasswdPath, + }, + } + + enabled := true + metricsConfig := &extconf.MetricsConfig{ + BaseConfig: extconf.BaseConfig{Enable: &enabled}, + Prometheus: &extconf.PrometheusConfig{Path: "/metrics"}, + } + conf.Extensions = &extconf.ExtensionConfig{ + Metrics: metricsConfig, + } + + Convey("with basic auth: no metrics users in accessControl", func() { + conf.HTTP.AccessControl = &config.AccessControlConfig{ + Metrics: config.Metrics{ + Users: []string{}, + }, + } + ctlr := api.NewController(conf) + ctlr.Config.Storage.RootDirectory = t.TempDir() + + cm := test.NewControllerManager(ctlr) + cm.StartAndWait(port) + defer cm.StopServer() + + // authenticated but not authorized user should not have access to/metrics + client := resty.New() + client.SetBasicAuth(username, password) + resp, err := client.R().Get(baseURL + "/metrics") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized) + + // authenticated but not authorized user should not have access to/metrics + client.SetBasicAuth(metricsuser, metricspass) + resp, err = client.R().Get(baseURL + "/metrics") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized) + }) + Convey("with basic auth: metrics users in accessControl", func() { + conf.HTTP.AccessControl = &config.AccessControlConfig{ + Metrics: config.Metrics{ + Users: []string{metricsuser}, + }, + } + ctlr := api.NewController(conf) + ctlr.Config.Storage.RootDirectory = t.TempDir() + + cm := test.NewControllerManager(ctlr) + cm.StartAndWait(port) + defer cm.StopServer() + + // authenticated but not authorized user should not have access to/metrics + client := resty.New() + client.SetBasicAuth(username, password) + resp, err := client.R().Get(baseURL + "/metrics") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusForbidden) + + // authenticated & authorized user should have access to/metrics + client.SetBasicAuth(metricsuser, metricspass) + resp, err = client.R().Get(baseURL + "/metrics") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusOK) + }) + Convey("with basic auth: with anonymousPolicy in accessControl", func() { + conf.HTTP.AccessControl = &config.AccessControlConfig{ + Metrics: config.Metrics{ + Users: []string{metricsuser}, + }, + Repositories: config.Repositories{ + test.AuthorizationAllRepos: config.PolicyGroup{ + Policies: []config.Policy{ + { + Users: []string{}, + Actions: []string{}, + }, + }, + AnonymousPolicy: []string{"read"}, + DefaultPolicy: []string{}, + }, + }, + } + ctlr := api.NewController(conf) + ctlr.Config.Storage.RootDirectory = t.TempDir() + + cm := test.NewControllerManager(ctlr) + cm.StartAndWait(port) + defer cm.StopServer() + + // unauthenticated clients should not have access to /metrics + resp, err := resty.R().Get(baseURL + "/metrics") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized) + + // unauthenticated clients should not have access to /metrics + resp, err = resty.R().SetBasicAuth("hacker", "trywithwrongpass").Get(baseURL + "/metrics") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized) + + // authenticated but not authorized user should not have access to/metrics + client := resty.New() + client.SetBasicAuth(username, password) + resp, err = client.R().Get(baseURL + "/metrics") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusForbidden) + + // authenticated & authorized user should have access to/metrics + client.SetBasicAuth(metricsuser, metricspass) + resp, err = client.R().Get(baseURL + "/metrics") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusOK) + }) + Convey("with basic auth: with adminPolicy in accessControl", func() { + conf.HTTP.AccessControl = &config.AccessControlConfig{ + Metrics: config.Metrics{ + Users: []string{metricsuser}, + }, + Repositories: config.Repositories{ + test.AuthorizationAllRepos: config.PolicyGroup{ + Policies: []config.Policy{ + { + Users: []string{}, + Actions: []string{}, + }, + }, + DefaultPolicy: []string{}, + }, + }, + AdminPolicy: config.Policy{ + Users: []string{"test"}, + Groups: []string{"admins"}, + Actions: []string{"read", "create", "update", "delete"}, + }, + } + ctlr := api.NewController(conf) + ctlr.Config.Storage.RootDirectory = t.TempDir() + + cm := test.NewControllerManager(ctlr) + cm.StartAndWait(port) + defer cm.StopServer() + + // unauthenticated clients should not have access to /metrics + resp, err := resty.R().Get(baseURL + "/metrics") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized) + + // unauthenticated clients should not have access to /metrics + resp, err = resty.R().SetBasicAuth("hacker", "trywithwrongpass").Get(baseURL + "/metrics") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized) + + // authenticated admin user (but not authorized) should not have access to/metrics + client := resty.New() + client.SetBasicAuth(username, password) + resp, err = client.R().Get(baseURL + "/metrics") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusForbidden) + + // authenticated & authorized user should have access to/metrics + client.SetBasicAuth(metricsuser, metricspass) + resp, err = client.R().Get(baseURL + "/metrics") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusOK) + }) + }) +} diff --git a/pkg/extensions/search/cve/cve_test.go b/pkg/extensions/search/cve/cve_test.go index 32d9059150..0faa6f0822 100644 --- a/pkg/extensions/search/cve/cve_test.go +++ b/pkg/extensions/search/cve/cve_test.go @@ -38,18 +38,13 @@ import ( mTypes "zotregistry.io/zot/pkg/meta/types" "zotregistry.io/zot/pkg/storage" "zotregistry.io/zot/pkg/storage/local" - . "zotregistry.io/zot/pkg/test/common" + test "zotregistry.io/zot/pkg/test/common" "zotregistry.io/zot/pkg/test/deprecated" . "zotregistry.io/zot/pkg/test/image-utils" "zotregistry.io/zot/pkg/test/mocks" ociutils "zotregistry.io/zot/pkg/test/oci-utils" ) -const ( - username = "test" - passphrase = "test" -) - type CveResult struct { ImgList ImgList `json:"data"` Errors []ErrorGQL `json:"errors"` @@ -418,11 +413,13 @@ func TestImageFormat(t *testing.T) { func TestCVESearchDisabled(t *testing.T) { Convey("Test with CVE search disabled", t, func() { - port := GetFreePort() - baseURL := GetBaseURL(port) + port := test.GetFreePort() + baseURL := test.GetBaseURL(port) conf := config.New() conf.HTTP.Port = port - htpasswdPath := MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ @@ -454,26 +451,26 @@ func TestCVESearchDisabled(t *testing.T) { ctlr := api.NewController(conf) ctlr.Log.Logger = ctlr.Log.Output(writers) - ctrlManager := NewControllerManager(ctlr) + ctrlManager := test.NewControllerManager(ctlr) ctrlManager.StartAndWait(port) // Wait for trivy db to download - found, err := ReadLogFileAndSearchString(logPath, "CVE config not provided, skipping CVE update", 90*time.Second) + found, err := test.ReadLogFileAndSearchString(logPath, "CVE config not provided, skipping CVE update", 90*time.Second) So(err, ShouldBeNil) So(found, ShouldBeTrue) defer ctrlManager.StopServer() - resp, _ := resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}") + resp, _ := resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}") So(string(resp.Body()), ShouldContainSubstring, "search: CVE search is disabled") So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListForCVE(id:\"CVE-201-20482\"){Results{RepoName%20Tag}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListForCVE(id:\"CVE-201-20482\"){Results{RepoName%20Tag}}}") So(string(resp.Body()), ShouldContainSubstring, "search: CVE search is disabled") So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + "randomId" + "\",image:\"zot-test\"){Results{RepoName%20LastUpdated}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + "randomId" + "\",image:\"zot-test\"){Results{RepoName%20LastUpdated}}}") So(resp, ShouldNotBeNil) So(string(resp.Body()), ShouldContainSubstring, "search: CVE search is disabled") So(resp.StatusCode(), ShouldEqual, 200) @@ -483,11 +480,13 @@ func TestCVESearchDisabled(t *testing.T) { func TestCVESearch(t *testing.T) { Convey("Test image vulnerability scanning", t, func() { updateDuration, _ := time.ParseDuration("1h") - port := GetFreePort() - baseURL := GetBaseURL(port) + port := test.GetFreePort() + baseURL := test.GetBaseURL(port) conf := config.New() conf.HTTP.Port = port - htpasswdPath := MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) dbDir, err := testSetup(t) @@ -529,14 +528,14 @@ func TestCVESearch(t *testing.T) { ctlr := api.NewController(conf) ctlr.Log.Logger = ctlr.Log.Output(writers) - ctrlManager := NewControllerManager(ctlr) + ctrlManager := test.NewControllerManager(ctlr) ctrlManager.StartAndWait(port) // trivy db download fail err = os.Mkdir(dbDir+"/_trivy", 0o000) So(err, ShouldBeNil) - found, err := ReadLogFileAndSearchString(logPath, "Error downloading Trivy DB to destination dir", 180*time.Second) + found, err := test.ReadLogFileAndSearchString(logPath, "Error downloading Trivy DB to destination dir", 180*time.Second) So(err, ShouldBeNil) So(found, ShouldBeTrue) @@ -544,7 +543,7 @@ func TestCVESearch(t *testing.T) { So(err, ShouldBeNil) // Wait for trivy db to download - found, err = ReadLogFileAndSearchString(logPath, "DB update completed, next update scheduled", 180*time.Second) + found, err = test.ReadLogFileAndSearchString(logPath, "DB update completed, next update scheduled", 180*time.Second) So(err, ShouldBeNil) So(found, ShouldBeTrue) @@ -567,21 +566,21 @@ func TestCVESearch(t *testing.T) { So(err, ShouldBeNil) // with creds, should get expected status code - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL) + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 404) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/v2/") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + "/v2/") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix) + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 422) var cveResult CveResult contains := false - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}") err = json.Unmarshal(resp.Body(), &cveResult) So(err, ShouldBeNil) for _, err := range cveResult.Errors { @@ -592,7 +591,7 @@ func TestCVESearch(t *testing.T) { } So(contains, ShouldBeTrue) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) @@ -602,7 +601,7 @@ func TestCVESearch(t *testing.T) { cveid := cveResult.ImgList.CVEResultForImage.CVEList[0].ID - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cveid + "\",image:\"zot-test\"){Results{RepoName%20LastUpdated}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cveid + "\",image:\"zot-test\"){Results{RepoName%20LastUpdated}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) @@ -611,7 +610,7 @@ func TestCVESearch(t *testing.T) { So(err, ShouldBeNil) So(len(imgListWithCVEFixed.Images), ShouldEqual, 0) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cveid + "\",image:\"zot-cve-test\"){Results{RepoName%20LastUpdated}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cveid + "\",image:\"zot-cve-test\"){Results{RepoName%20LastUpdated}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) @@ -619,11 +618,11 @@ func TestCVESearch(t *testing.T) { So(err, ShouldBeNil) So(len(imgListWithCVEFixed.Images), ShouldEqual, 0) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cveid + "\",image:\"zot-test\"){Results{RepoName%20LastUpdated}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cveid + "\",image:\"zot-test\"){Results{RepoName%20LastUpdated}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"b/zot-squashfs-test:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"b/zot-squashfs-test:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) @@ -632,108 +631,108 @@ func TestCVESearch(t *testing.T) { So(err, ShouldBeNil) So(len(cveSquashFSResult.ImgList.CVEResultForImage.CVEList), ShouldBeZeroValue) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-squashfs-noindex:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-squashfs-noindex:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cveid + "\",image:\"zot-squashfs-noindex\"){Results{RepoName%20LastUpdated}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cveid + "\",image:\"zot-squashfs-noindex\"){Results{RepoName%20LastUpdated}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-squashfs-invalid-index:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-squashfs-invalid-index:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cveid + "\",image:\"zot-squashfs-invalid-index\"){Results{RepoName%20LastUpdated}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cveid + "\",image:\"zot-squashfs-invalid-index\"){Results{RepoName%20LastUpdated}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-squashfs-noblobs:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-squashfs-noblobs:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cveid + "\",image:\"zot-squashfs-noblob\"){Results{RepoName%20LastUpdated}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cveid + "\",image:\"zot-squashfs-noblob\"){Results{RepoName%20LastUpdated}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cveid + "\",image:\"zot-squashfs-test\"){Results{RepoName%20LastUpdated}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cveid + "\",image:\"zot-squashfs-test\"){Results{RepoName%20LastUpdated}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-squashfs-invalid-blob:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-squashfs-invalid-blob:commit-aaa7c6e7-squashfs\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cveid + "\",image:\"zot-squashfs-invalid-blob\"){Results{RepoName%20LastUpdated}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListWithCVEFixed(id:\"" + cveid + "\",image:\"zot-squashfs-invalid-blob\"){Results{RepoName%20LastUpdated}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-squashfs-test\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-squashfs-test\"){Tag%20CVEList{Id%20Description%20Severity%20PackageList{Name%20InstalledVersion%20FixedVersion}}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"cntos\"){Tag%20CVEList{Id%20Description%20Severity}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"cntos\"){Tag%20CVEList{Id%20Description%20Severity}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListForCVE(id:\"CVE-201-20482\"){Results{RepoName%20Tag}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListForCVE(id:\"CVE-201-20482\"){Results{RepoName%20Tag}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test\"){Tag%20CVEList{Id%20Description}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test\"){Tag%20CVEList{Id%20Description}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){Tag}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){Tag}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Id%20Description%20Severity}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Id%20Description%20Severity}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Description%20Severity}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Description%20Severity}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Id%20Severity}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Id%20Severity}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Id%20Description}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Id%20Description}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Id}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Id}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Description}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){CVEList{Description}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) // Testing Invalid Search URL - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){Ta%20CVEList{Id%20Description%20Severity}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(image:\"zot-test:0.0.1\"){Ta%20CVEList{Id%20Description%20Severity}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 422) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListForCVE(tet:\"CVE-2018-20482\"){Results{RepoName%20Tag}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListForCVE(tet:\"CVE-2018-20482\"){Results{RepoName%20Tag}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 422) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageistForCVE(id:\"CVE-2018-20482\"){Results{RepoName%20Tag}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={ImageistForCVE(id:\"CVE-2018-20482\"){Results{RepoName%20Tag}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 422) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListForCVE(id:\"CVE-2018-20482\"){ame%20Tags}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListForCVE(id:\"CVE-2018-20482\"){ame%20Tags}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 422) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(reo:\"zot-test:1.0.0\"){Tag%20CVEList{Id%20Description%20Severity}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={CVEListForImage(reo:\"zot-test:1.0.0\"){Tag%20CVEList{Id%20Description%20Severity}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 422) - resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListForCVE(id:\"" + cveid + "\"){Results{RepoName%20Tag}}}") + resp, _ = resty.R().SetBasicAuth(username, password).Get(baseURL + constants.FullSearchPrefix + "?query={ImageListForCVE(id:\"" + cveid + "\"){Results{RepoName%20Tag}}}") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, 200) }) @@ -1615,8 +1614,8 @@ func TestFixedTags(t *testing.T) { func TestFixedTagsWithIndex(t *testing.T) { Convey("Test fixed tags", t, func() { tempDir := t.TempDir() - port := GetFreePort() - baseURL := GetBaseURL(port) + port := test.GetFreePort() + baseURL := test.GetBaseURL(port) conf := config.New() conf.HTTP.Port = port defaultVal := true @@ -1644,7 +1643,7 @@ func TestFixedTagsWithIndex(t *testing.T) { ctlr := api.NewController(conf) ctlr.Log.Logger = ctlr.Log.Output(writers) - cm := NewControllerManager(ctlr) + cm := test.NewControllerManager(ctlr) cm.StartAndWait(port) defer cm.StopServer() // push index with 2 manifests: one with vulns and one without @@ -1681,7 +1680,7 @@ func TestFixedTagsWithIndex(t *testing.T) { So(err, ShouldBeNil) // Wait for trivy db to download - found, err := ReadLogFileAndSearchString(logPath, "DB update completed, next update scheduled", 180*time.Second) + found, err := test.ReadLogFileAndSearchString(logPath, "DB update completed, next update scheduled", 180*time.Second) So(err, ShouldBeNil) So(found, ShouldBeTrue) diff --git a/pkg/extensions/search/userprefs_test.go b/pkg/extensions/search/userprefs_test.go index 7d0fda85c5..017239826a 100644 --- a/pkg/extensions/search/userprefs_test.go +++ b/pkg/extensions/search/userprefs_test.go @@ -11,7 +11,6 @@ import ( "testing" . "github.com/smartystreets/goconvey/convey" - "golang.org/x/crypto/bcrypt" "gopkg.in/resty.v1" "zotregistry.io/zot/pkg/api" @@ -23,7 +22,7 @@ import ( "zotregistry.io/zot/pkg/log" "zotregistry.io/zot/pkg/storage" "zotregistry.io/zot/pkg/storage/local" - . "zotregistry.io/zot/pkg/test/common" + test "zotregistry.io/zot/pkg/test/common" "zotregistry.io/zot/pkg/test/deprecated" . "zotregistry.io/zot/pkg/test/image-utils" ) @@ -31,8 +30,8 @@ import ( //nolint:dupl func TestUserData(t *testing.T) { Convey("Test user stars and bookmarks", t, func(c C) { - port := GetFreePort() - baseURL := GetBaseURL(port) + port := test.GetFreePort() + baseURL := test.GetBaseURL(port) defaultVal := true accessibleRepo := "accessible-repo" @@ -44,10 +43,10 @@ func TestUserData(t *testing.T) { simpleUser := "test" simpleUserPassword := "test123" - twoCredTests := fmt.Sprintf("%s\n%s\n\n", getCredString(adminUser, adminPassword), - getCredString(simpleUser, simpleUserPassword)) + twoCredTests := fmt.Sprintf("%s\n%s\n\n", test.GetCredString(adminUser, adminPassword), + test.GetCredString(simpleUser, simpleUserPassword)) - htpasswdPath := MakeHtpasswdFileFromString(twoCredTests) + htpasswdPath := test.MakeHtpasswdFileFromString(twoCredTests) defer os.Remove(htpasswdPath) conf := config.New() @@ -94,7 +93,7 @@ func TestUserData(t *testing.T) { ctlr := api.NewController(conf) - ctlrManager := NewControllerManager(ctlr) + ctlrManager := test.NewControllerManager(ctlr) ctlrManager.StartAndWait(port) defer ctlrManager.StopServer() @@ -458,8 +457,8 @@ func TestUserData(t *testing.T) { } func TestChangingRepoState(t *testing.T) { - port := GetFreePort() - baseURL := GetBaseURL(port) + port := test.GetFreePort() + baseURL := test.GetBaseURL(port) defaultVal := true simpleUser := "test" @@ -468,9 +467,9 @@ func TestChangingRepoState(t *testing.T) { forbiddenRepo := "forbidden" accesibleRepo := "accesible" - credTests := fmt.Sprintf("%s\n\n", getCredString(simpleUser, simpleUserPassword)) + credTests := fmt.Sprintf("%s\n\n", test.GetCredString(simpleUser, simpleUserPassword)) - htpasswdPath := MakeHtpasswdFileFromString(credTests) + htpasswdPath := test.MakeHtpasswdFileFromString(credTests) defer os.Remove(htpasswdPath) conf := config.New() @@ -562,7 +561,7 @@ func TestChangingRepoState(t *testing.T) { t.FailNow() } - ctlrManager := NewControllerManager(ctlr) + ctlrManager := test.NewControllerManager(ctlr) ctlrManager.StartAndWait(port) @@ -622,17 +621,17 @@ func TestChangingRepoState(t *testing.T) { func TestGlobalSearchWithUserPrefFiltering(t *testing.T) { Convey("Bookmarks and Stars filtering", t, func() { dir := t.TempDir() - port := GetFreePort() - baseURL := GetBaseURL(port) + port := test.GetFreePort() + baseURL := test.GetBaseURL(port) conf := config.New() conf.HTTP.Port = port conf.Storage.RootDirectory = dir simpleUser := "simpleUser" simpleUserPassword := "simpleUserPass" - credTests := fmt.Sprintf("%s\n\n", getCredString(simpleUser, simpleUserPassword)) + credTests := fmt.Sprintf("%s\n\n", test.GetCredString(simpleUser, simpleUserPassword)) - htpasswdPath := MakeHtpasswdFileFromString(credTests) + htpasswdPath := test.MakeHtpasswdFileFromString(credTests) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ @@ -664,7 +663,7 @@ func TestGlobalSearchWithUserPrefFiltering(t *testing.T) { ctlr := api.NewController(conf) - ctlrManager := NewControllerManager(ctlr) + ctlrManager := test.NewControllerManager(ctlr) ctlrManager.StartAndWait(port) defer ctlrManager.StopServer() @@ -750,8 +749,8 @@ func TestGlobalSearchWithUserPrefFiltering(t *testing.T) { So(foundRepos, ShouldContain, common.RepoSummary{Name: sbRepo, IsStarred: true, IsBookmarked: true}) // Filter by IsStarred = true && IsBookmarked = false - query = `{ - GlobalSearch(query:"repo", filter:{ IsStarred:true, IsBookmarked:false }) { + query = `{ + GlobalSearch(query:"repo", filter:{ IsStarred:true, IsBookmarked:false }) { Repos { Name IsStarred IsBookmarked } } }` @@ -771,8 +770,8 @@ func TestGlobalSearchWithUserPrefFiltering(t *testing.T) { So(foundRepos, ShouldContain, common.RepoSummary{Name: sRepo, IsStarred: true, IsBookmarked: false}) // Filter by IsBookmarked = true - query = `{ - GlobalSearch(query:"repo", filter:{ IsBookmarked:true }) { + query = `{ + GlobalSearch(query:"repo", filter:{ IsBookmarked:true }) { Repos { Name IsStarred IsBookmarked } } }` @@ -793,8 +792,8 @@ func TestGlobalSearchWithUserPrefFiltering(t *testing.T) { So(foundRepos, ShouldContain, common.RepoSummary{Name: sbRepo, IsStarred: true, IsBookmarked: true}) // Filter by IsBookmarked = true && IsStarred = false - query = `{ - GlobalSearch(query:"repo", filter:{ IsBookmarked:true, IsStarred:false }) { + query = `{ + GlobalSearch(query:"repo", filter:{ IsBookmarked:true, IsStarred:false }) { Repos { Name IsStarred IsBookmarked } } }` @@ -818,17 +817,17 @@ func TestGlobalSearchWithUserPrefFiltering(t *testing.T) { func TestExpandedRepoInfoWithUserPrefs(t *testing.T) { Convey("ExpandedRepoInfo with User Prefs", t, func() { dir := t.TempDir() - port := GetFreePort() - baseURL := GetBaseURL(port) + port := test.GetFreePort() + baseURL := test.GetBaseURL(port) conf := config.New() conf.HTTP.Port = port conf.Storage.RootDirectory = dir simpleUser := "simpleUser" simpleUserPassword := "simpleUserPass" - credTests := fmt.Sprintf("%s\n\n", getCredString(simpleUser, simpleUserPassword)) + credTests := fmt.Sprintf("%s\n\n", test.GetCredString(simpleUser, simpleUserPassword)) - htpasswdPath := MakeHtpasswdFileFromString(credTests) + htpasswdPath := test.MakeHtpasswdFileFromString(credTests) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ @@ -860,7 +859,7 @@ func TestExpandedRepoInfoWithUserPrefs(t *testing.T) { ctlr := api.NewController(conf) - ctlrManager := NewControllerManager(ctlr) + ctlrManager := test.NewControllerManager(ctlr) ctlrManager.StartAndWait(port) defer ctlrManager.StopServer() @@ -888,7 +887,7 @@ func TestExpandedRepoInfoWithUserPrefs(t *testing.T) { { ExpandedRepoInfo(repo:"sbrepo"){ Summary { - Name IsStarred IsBookmarked + Name IsStarred IsBookmarked } } }` @@ -923,7 +922,7 @@ func TestExpandedRepoInfoWithUserPrefs(t *testing.T) { { ExpandedRepoInfo(repo:"srepo"){ Summary { - Name IsStarred IsBookmarked + Name IsStarred IsBookmarked } } }` @@ -958,7 +957,7 @@ func TestExpandedRepoInfoWithUserPrefs(t *testing.T) { { ExpandedRepoInfo(repo:"brepo"){ Summary { - Name IsStarred IsBookmarked + Name IsStarred IsBookmarked } } }` @@ -989,7 +988,7 @@ func TestExpandedRepoInfoWithUserPrefs(t *testing.T) { { ExpandedRepoInfo(repo:"repo"){ Summary { - Name IsStarred IsBookmarked + Name IsStarred IsBookmarked } } }` @@ -1017,14 +1016,3 @@ func PutRepoStarURL(repo string) string { func PutRepoBookmarkURL(repo string) string { return fmt.Sprintf("?repo=%s&action=toggleBookmark", repo) } - -func getCredString(username, password string) string { - hash, err := bcrypt.GenerateFromPassword([]byte(password), 10) - if err != nil { - panic(err) - } - - usernameAndHash := fmt.Sprintf("%s:%s", username, string(hash)) - - return usernameAndHash -} diff --git a/pkg/extensions/sync/sync_test.go b/pkg/extensions/sync/sync_test.go index 52b5dcd737..37a4a99578 100644 --- a/pkg/extensions/sync/sync_test.go +++ b/pkg/extensions/sync/sync_test.go @@ -69,6 +69,8 @@ const ( ) var ( + username = test.GenerateRandomString() //nolint: gochecknoglobals + password = test.GenerateRandomString() //nolint: gochecknoglobals errSync = errors.New("sync error, src oci repo differs from dest one") errBadStatus = errors.New("bad http status") ) @@ -127,7 +129,7 @@ func makeUpstreamServer( var htpasswdPath string if basicAuth { - htpasswdPath = test.MakeHtpasswdFile() + htpasswdPath = test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) srcConfig.HTTP.Auth = &config.AuthConfig{ HTPasswd: config.AuthHTPasswd{ Path: htpasswdPath, @@ -2376,7 +2378,8 @@ func TestBasicAuth(t *testing.T) { defer scm.StopServer() registryName := sync.StripRegistryTransport(srcBaseURL) - credentialsFile := makeCredentialsFile(fmt.Sprintf(`{"%s":{"username": "test", "password": "test"}}`, registryName)) + credentialsFile := makeCredentialsFile(fmt.Sprintf(`{"%s":{"username": "%s", "password": "%s"}}`, + registryName, username, password)) var tlsVerify bool @@ -2408,7 +2411,7 @@ func TestBasicAuth(t *testing.T) { var srcTagsList TagsList var destTagsList TagsList - resp, _ := srcClient.R().SetBasicAuth("test", "test").Get(srcBaseURL + "/v2/" + testImage + "/tags/list") + resp, _ := srcClient.R().SetBasicAuth(username, password).Get(srcBaseURL + "/v2/" + testImage + "/tags/list") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -2474,8 +2477,8 @@ func TestBasicAuth(t *testing.T) { registryName := sync.StripRegistryTransport(srcBaseURL) - credentialsFile := makeCredentialsFile(fmt.Sprintf(`{"%s":{"username": "test", "password": "invalid"}}`, - registryName)) + credentialsFile := makeCredentialsFile(fmt.Sprintf(`{"%s":{"username": "%s", "password": "invalid"}}`, + registryName, username)) var tlsVerify bool @@ -2541,8 +2544,8 @@ func TestBasicAuth(t *testing.T) { registryName := sync.StripRegistryTransport(srcBaseURL) - credentialsFile := makeCredentialsFile(fmt.Sprintf(`{"%s":{"username": "test", "password": "test"}}`, - registryName)) + credentialsFile := makeCredentialsFile(fmt.Sprintf(`{"%s":{"username": "%s", "password": "%s"}}`, + registryName, username, password)) err := os.Chmod(credentialsFile, 0o000) So(err, ShouldBeNil) @@ -2614,7 +2617,8 @@ func TestBasicAuth(t *testing.T) { defer scm.StopServer() registryName := sync.StripRegistryTransport(srcBaseURL) - credentialsFile := makeCredentialsFile(fmt.Sprintf(`{"%s":{"username": "test", "password": "test"}}`, registryName)) + credentialsFile := makeCredentialsFile(fmt.Sprintf(`{"%s":{"username": "%s", "password": "%s"}}`, + registryName, username, password)) defaultValue := false syncRegistryConfig := syncconf.RegistryConfig{ @@ -2654,7 +2658,7 @@ func TestBasicAuth(t *testing.T) { var srcTagsList TagsList var destTagsList TagsList - resp, _ := srcClient.R().SetBasicAuth("test", "test").Get(srcBaseURL + "/v2/" + testImage + "/tags/list") + resp, _ := srcClient.R().SetBasicAuth(username, password).Get(srcBaseURL + "/v2/" + testImage + "/tags/list") So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) diff --git a/pkg/log/log_test.go b/pkg/log/log_test.go index 6a9fa0e32c..55ee12d6e8 100644 --- a/pkg/log/log_test.go +++ b/pkg/log/log_test.go @@ -24,14 +24,7 @@ import ( "zotregistry.io/zot/pkg/api/config" "zotregistry.io/zot/pkg/api/constants" "zotregistry.io/zot/pkg/log" - . "zotregistry.io/zot/pkg/test/common" -) - -const ( - username = "test" - passphrase = "test" - AuthorizedNamespace = "everyone/isallowed" - UnauthorizedNamespace = "fortknox/notallowed" + test "zotregistry.io/zot/pkg/test/common" ) type AuditLog struct { @@ -49,8 +42,8 @@ func TestAuditLogMessages(t *testing.T) { Convey("Make a new controller", t, func() { dir := t.TempDir() - port := GetFreePort() - baseURL := GetBaseURL(port) + port := test.GetFreePort() + baseURL := test.GetBaseURL(port) conf := config.New() outputPath := dir + "/zot.log" @@ -59,7 +52,9 @@ func TestAuditLogMessages(t *testing.T) { conf.HTTP.Port = port - htpasswdPath := MakeHtpasswdFile() + username := test.GenerateRandomString() + password := test.GenerateRandomString() + htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(username, password)) defer os.Remove(htpasswdPath) conf.HTTP.Auth = &config.AuthConfig{ HTPasswd: config.AuthHTPasswd{ @@ -70,7 +65,7 @@ func TestAuditLogMessages(t *testing.T) { ctlr := api.NewController(conf) ctlr.Config.Storage.RootDirectory = dir - ctlrManager := NewControllerManager(ctlr) + ctlrManager := test.NewControllerManager(ctlr) ctlrManager.StartAndWait(port) defer ctlrManager.StopServer() @@ -83,7 +78,7 @@ func TestAuditLogMessages(t *testing.T) { defer auditFile.Close() Convey("Test GET request", func() { - resp, err := resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/v2/") + resp, err := resty.R().SetBasicAuth(username, password).Get(baseURL + "/v2/") So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) @@ -93,8 +88,9 @@ func TestAuditLogMessages(t *testing.T) { }) Convey("Test POST request", func() { - path := "/v2/" + AuthorizedNamespace + "/blobs/uploads/" - resp, err := resty.R().SetBasicAuth(username, passphrase).Post(baseURL + path) + repoName := "everyone/isallowed" + path := "/v2/" + repoName + "/blobs/uploads/" + resp, err := resty.R().SetBasicAuth(username, password).Post(baseURL + path) So(err, ShouldBeNil) So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusAccepted) @@ -124,10 +120,10 @@ func TestAuditLogMessages(t *testing.T) { Convey("Test PUT and DELETE request", func() { // create upload path := "/v2/repo/blobs/uploads/" - resp, err := resty.R().SetBasicAuth(username, passphrase).Post(baseURL + path) + resp, err := resty.R().SetBasicAuth(username, password).Post(baseURL + path) So(err, ShouldBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusAccepted) - loc := Location(baseURL, resp) + loc := test.Location(baseURL, resp) So(loc, ShouldNotBeEmpty) location := resp.Header().Get("Location") So(location, ShouldNotBeEmpty) @@ -159,11 +155,11 @@ func TestAuditLogMessages(t *testing.T) { // blob upload resp, err = resty.R().SetQueryParam("digest", digest.String()). - SetBasicAuth(username, passphrase). + SetBasicAuth(username, password). SetHeader("Content-Type", "application/octet-stream").SetBody(content).Put(loc) So(err, ShouldBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusCreated) - blobLoc := Location(baseURL, resp) + blobLoc := test.Location(baseURL, resp) So(blobLoc, ShouldNotBeEmpty) So(resp.Header().Get(constants.DistContentDigestKey), ShouldNotBeEmpty) @@ -190,7 +186,7 @@ func TestAuditLogMessages(t *testing.T) { So(auditLog.Object, ShouldEqual, putPath) // delete this blob - resp, err = resty.R().SetBasicAuth(username, passphrase).Delete(blobLoc) + resp, err = resty.R().SetBasicAuth(username, password).Delete(blobLoc) So(err, ShouldBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusAccepted) So(resp.Header().Get("Content-Length"), ShouldEqual, "0") @@ -220,10 +216,10 @@ func TestAuditLogMessages(t *testing.T) { Convey("Test PATCH request", func() { path := "/v2/repo/blobs/uploads/" - resp, err := resty.R().SetBasicAuth(username, passphrase).Post(baseURL + path) + resp, err := resty.R().SetBasicAuth(username, password).Post(baseURL + path) So(err, ShouldBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusAccepted) - loc := Location(baseURL, resp) + loc := test.Location(baseURL, resp) So(loc, ShouldNotBeEmpty) location := resp.Header().Get("Location") So(location, ShouldNotBeEmpty) @@ -257,7 +253,7 @@ func TestAuditLogMessages(t *testing.T) { // write a chunk contentRange := fmt.Sprintf("%d-%d", 0, len(chunk)-1) - resp, err = resty.R().SetBasicAuth(username, passphrase). + resp, err = resty.R().SetBasicAuth(username, password). SetHeader("Content-Type", "application/octet-stream"). SetHeader("Content-Range", contentRange).SetBody(chunk).Patch(loc) So(err, ShouldBeNil) diff --git a/pkg/storage/cache_benchmark_test.go b/pkg/storage/cache_benchmark_test.go index 962eab9ebf..8792f85733 100644 --- a/pkg/storage/cache_benchmark_test.go +++ b/pkg/storage/cache_benchmark_test.go @@ -11,6 +11,7 @@ import ( "zotregistry.io/zot/pkg/log" "zotregistry.io/zot/pkg/storage" "zotregistry.io/zot/pkg/storage/cache" + test "zotregistry.io/zot/pkg/test/common" ) const ( @@ -20,32 +21,19 @@ const ( datasetSize int = 5000 ) -func generateRandomString() string { - //nolint: gosec - seededRand := rand.New(rand.NewSource(time.Now().UnixNano())) - charset := "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - - randomBytes := make([]byte, 10) - for i := range randomBytes { - randomBytes[i] = charset[seededRand.Intn(len(charset))] - } - - return string(randomBytes) -} - func generateData() map[godigest.Digest]string { dataMap := make(map[godigest.Digest]string, datasetSize) //nolint: gosec seededRand := rand.New(rand.NewSource(time.Now().UnixNano())) for i := 0; i < datasetSize; i++ { - randomString := generateRandomString() + randomString := test.GenerateRandomString() counter := 0 for seededRand.Float32() < 0.5 && counter < 5 { counter++ randomString += "/" - randomString += generateRandomString() + randomString += test.GenerateRandomString() } digest := godigest.FromString(randomString) dataMap[digest] = randomString @@ -209,7 +197,7 @@ func BenchmarkMixLocal(b *testing.B) { func BenchmarkPutLocalstack(b *testing.B) { log := log.NewLogger("error", "") - tableName := generateRandomString() + tableName := test.GenerateRandomString() // Create Table _, err := exec.Command("aws", "dynamodb", "--region", region, "--endpoint-url", localEndpoint, "create-table", @@ -234,7 +222,7 @@ func BenchmarkPutLocalstack(b *testing.B) { func BenchmarkDeleteLocalstack(b *testing.B) { log := log.NewLogger("error", "") - tableName := generateRandomString() + tableName := test.GenerateRandomString() // Create Table _, err := exec.Command("aws", "dynamodb", "--region", region, "--endpoint-url", localEndpoint, "create-table", @@ -263,7 +251,7 @@ func BenchmarkDeleteLocalstack(b *testing.B) { func BenchmarkHasLocalstack(b *testing.B) { log := log.NewLogger("error", "") - tableName := generateRandomString() + tableName := test.GenerateRandomString() // Create Table _, err := exec.Command("aws", "dynamodb", "--region", region, "--endpoint-url", localEndpoint, "create-table", @@ -292,7 +280,7 @@ func BenchmarkHasLocalstack(b *testing.B) { func BenchmarkGetLocalstack(b *testing.B) { log := log.NewLogger("error", "") - tableName := generateRandomString() + tableName := test.GenerateRandomString() // Create Table _, err := exec.Command("aws", "dynamodb", "--region", region, "--endpoint-url", localEndpoint, "create-table", @@ -331,7 +319,7 @@ func BenchmarkGetLocalstack(b *testing.B) { func BenchmarkMixLocalstack(b *testing.B) { log := log.NewLogger("error", "") - tableName := generateRandomString() + tableName := test.GenerateRandomString() // Create Table _, err := exec.Command("aws", "dynamodb", "--region", region, "--endpoint-url", localEndpoint, "create-table", @@ -367,7 +355,7 @@ func BenchmarkMixLocalstack(b *testing.B) { func BenchmarkPutAWS(b *testing.B) { log := log.NewLogger("error", "") - tableName := generateRandomString() + tableName := test.GenerateRandomString() // Create Table _, err := exec.Command("aws", "dynamodb", "--region", region, "--endpoint-url", awsEndpoint, "create-table", @@ -392,7 +380,7 @@ func BenchmarkPutAWS(b *testing.B) { func BenchmarkDeleteAWS(b *testing.B) { log := log.NewLogger("error", "") - tableName := generateRandomString() + tableName := test.GenerateRandomString() // Create Table _, err := exec.Command("aws", "dynamodb", "--region", region, "--endpoint-url", awsEndpoint, "create-table", @@ -421,7 +409,7 @@ func BenchmarkDeleteAWS(b *testing.B) { func BenchmarkHasAWS(b *testing.B) { log := log.NewLogger("error", "") - tableName := generateRandomString() + tableName := test.GenerateRandomString() // Create Table _, err := exec.Command("aws", "dynamodb", "--region", region, "--endpoint-url", awsEndpoint, "create-table", @@ -450,7 +438,7 @@ func BenchmarkHasAWS(b *testing.B) { func BenchmarkGetAWS(b *testing.B) { log := log.NewLogger("error", "") - tableName := generateRandomString() + tableName := test.GenerateRandomString() // Create Table _, err := exec.Command("aws", "dynamodb", "--region", region, "--endpoint-url", awsEndpoint, "create-table", @@ -489,7 +477,7 @@ func BenchmarkGetAWS(b *testing.B) { func BenchmarkMixAWS(b *testing.B) { log := log.NewLogger("error", "") - tableName := generateRandomString() + tableName := test.GenerateRandomString() // Create Table _, err := exec.Command("aws", "dynamodb", "--region", region, "--endpoint-url", awsEndpoint, "create-table", diff --git a/pkg/test/common/fs.go b/pkg/test/common/fs.go index 7319b1abfc..fe7eb016e2 100644 --- a/pkg/test/common/fs.go +++ b/pkg/test/common/fs.go @@ -212,20 +212,13 @@ func ReadLogFileAndCountStringOccurence(logPath string, stringToMatch string, } } -func MakeHtpasswdFile() string { - // bcrypt(username="test", passwd="test") - content := "test:$2y$05$hlbSXDp6hzDLu6VwACS39ORvVRpr3OMR4RlJ31jtlaOEGnPjKZI1m\n" - - return MakeHtpasswdFileFromString(content) -} - func GetCredString(username, password string) string { hash, err := bcrypt.GenerateFromPassword([]byte(password), 10) if err != nil { panic(err) } - usernameAndHash := fmt.Sprintf("%s:%s", username, string(hash)) + usernameAndHash := fmt.Sprintf("%s:%s\n", username, string(hash)) return usernameAndHash } @@ -236,7 +229,6 @@ func MakeHtpasswdFileFromString(fileContent string) string { panic(err) } - // bcrypt(username="test", passwd="test") content := []byte(fileContent) if err := os.WriteFile(htpasswdFile.Name(), content, 0o600); err != nil { //nolint:gomnd panic(err) diff --git a/pkg/test/common/utils.go b/pkg/test/common/utils.go index 43c6102ae5..e0df8b505b 100644 --- a/pkg/test/common/utils.go +++ b/pkg/test/common/utils.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "math/rand" "net/http" "net/url" "os" @@ -15,9 +16,10 @@ import ( ) const ( - BaseURL = "http://127.0.0.1:%s" - BaseSecureURL = "https://127.0.0.1:%s" - SleepTime = 100 * time.Millisecond + BaseURL = "http://127.0.0.1:%s" + BaseSecureURL = "https://127.0.0.1:%s" + SleepTime = 100 * time.Millisecond + AuthorizationAllRepos = "**" ) type isser interface { @@ -177,3 +179,31 @@ func CustomRedirectPolicy(noOfRedirect int) resty.RedirectPolicy { return nil }) } + +// Generates a random string with length 10 from lower case & upper case characters. +func GenerateRandomString() string { + //nolint: gosec + seededRand := rand.New(rand.NewSource(time.Now().UnixNano())) + charset := "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + randomBytes := make([]byte, 10) + for i := range randomBytes { + randomBytes[i] = charset[seededRand.Intn(len(charset))] + } + + return string(randomBytes) +} + +// Generates a random string with length 10 from lower case characters and digits. +func GenerateRandomName() string { + //nolint: gosec + seededRand := rand.New(rand.NewSource(time.Now().UnixNano())) + charset := "abcdefghijklmnopqrstuvwxyz" + "0123456789" + + randomBytes := make([]byte, 10) + for i := range randomBytes { + randomBytes[i] = charset[seededRand.Intn(len(charset))] + } + + return string(randomBytes) +} diff --git a/pkg/test/skip/skip_test.go b/pkg/test/skip/skip_test.go new file mode 100644 index 0000000000..b266f11cdb --- /dev/null +++ b/pkg/test/skip/skip_test.go @@ -0,0 +1,37 @@ +package skip_test + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + + tskip "zotregistry.io/zot/pkg/test/skip" +) + +// for code coverage. +func TestSkipS3(t *testing.T) { + envName := "S3MOCK_ENDPOINT" + envVal := os.Getenv(envName) + + if len(envVal) > 0 { + defer os.Setenv(envName, envVal) + err := os.Unsetenv(envName) + assert.Equal(t, err, nil, "Error should be nil") + } + + tskip.SkipS3(t) +} + +func TestSkipDynamo(t *testing.T) { + envName := "DYNAMODBMOCK_ENDPOINT" + envVal := os.Getenv(envName) + + if len(envVal) > 0 { + defer os.Setenv(envName, envVal) + err := os.Unsetenv(envName) + assert.Equal(t, err, nil, "Error should be nil") + } + + tskip.SkipDynamo(t) +} diff --git a/test/blackbox/helpers_metrics.bash b/test/blackbox/helpers_metrics.bash index cce55e5b84..4c225568b8 100644 --- a/test/blackbox/helpers_metrics.bash +++ b/test/blackbox/helpers_metrics.bash @@ -1,3 +1,6 @@ +METRICS_USER=observability +METRICS_PASS=MySecreTPa55 + function metrics_route_check () { local servername="http://127.0.0.1:${1}/metrics" status_code=$(curl --write-out '%{http_code}' ${2} --silent --output /dev/null ${servername}) diff --git a/test/blackbox/metrics.bats b/test/blackbox/metrics.bats index 0d392ac2cf..9a39c664dd 100644 --- a/test/blackbox/metrics.bats +++ b/test/blackbox/metrics.bats @@ -32,6 +32,7 @@ function setup_file() { zot_config_file=${BATS_FILE_TMPDIR}/zot_config.json zot_htpasswd_file=${BATS_FILE_TMPDIR}/zot_htpasswd htpasswd -Bbn ${AUTH_USER} ${AUTH_PASS} >> ${zot_htpasswd_file} + htpasswd -Bbn ${METRICS_USER} ${METRICS_PASS} >> ${zot_htpasswd_file} mkdir -p ${zot_root_dir} touch ${zot_log_file} @@ -48,6 +49,20 @@ function setup_file() { "htpasswd": { "path": "${zot_htpasswd_file}" } + }, + "accessControl": { + "metrics":{ + "users": ["${METRICS_USER}"] + }, + "repositories": { + "**": { + "anonymousPolicy": [ + "read", + "create" + ], + "defaultPolicy": ["read"] + } + } } }, "log": { @@ -80,14 +95,20 @@ function teardown_file() { } @test "unauthorized request to metrics" { +# anonymous policy: metrics endpoint should not be available +# 401 - http.StatusUnauthorized run metrics_route_check 8080 "" 401 [ "$status" -eq 0 ] +# user is not in htpasswd run metrics_route_check 8080 "-u unlucky:wrongpass" 401 [ "$status" -eq 0 ] +# proper user/pass tuple from htpasswd, but user not allowed to access metrics +# 403 - http.StatusForbidden + run metrics_route_check 8080 "-u ${AUTH_USER}:${AUTH_PASS}" 403 + [ "$status" -eq 0 ] } @test "authorized request: metrics enabled" { - run metrics_route_check 8080 "-u ${AUTH_USER}:${AUTH_PASS}" 200 + run metrics_route_check 8080 "-u ${METRICS_USER}:${METRICS_PASS}" 200 [ "$status" -eq 0 ] } - diff --git a/test/blackbox/metrics_minimal.bats b/test/blackbox/metrics_minimal.bats index c693f64ec5..352498840f 100644 --- a/test/blackbox/metrics_minimal.bats +++ b/test/blackbox/metrics_minimal.bats @@ -32,6 +32,7 @@ function setup_file() { zot_config_file=${BATS_FILE_TMPDIR}/zot_config.json zot_htpasswd_file=${BATS_FILE_TMPDIR}/zot_htpasswd htpasswd -Bbn ${AUTH_USER} ${AUTH_PASS} >> ${zot_htpasswd_file} + htpasswd -Bbn ${METRICS_USER} ${METRICS_PASS} >> ${zot_htpasswd_file} mkdir -p ${zot_root_dir} touch ${zot_log_file} @@ -48,6 +49,20 @@ function setup_file() { "htpasswd": { "path": "${zot_htpasswd_file}" } + }, + "accessControl": { + "metrics":{ + "users": ["${METRICS_USER}"] + }, + "repositories": { + "**": { + "anonymousPolicy": [ + "read", + "create" + ], + "defaultPolicy": ["read"] + } + } } }, "log": { @@ -72,13 +87,20 @@ function teardown_file() { } @test "unauthorized request to metrics" { +# anonymous policy: metrics endpoint should not be available +# 401 - http.StatusUnauthorized run metrics_route_check 8080 "" 401 [ "$status" -eq 0 ] +# user is not in htpasswd run metrics_route_check 8080 "-u test:wrongpass" 401 [ "$status" -eq 0 ] +# proper user/pass tuple from htpasswd, but user not allowed to access metrics +# 403 - http.StatusForbidden + run metrics_route_check 8080 "-u ${AUTH_USER}:${AUTH_PASS}" 403 + [ "$status" -eq 0 ] } @test "authorized request: metrics enabled" { - run metrics_route_check 8080 "-u ${AUTH_USER}:${AUTH_PASS}" 200 + run metrics_route_check 8080 "-u ${METRICS_USER}:${METRICS_PASS}" 200 [ "$status" -eq 0 ] -} \ No newline at end of file +}