2023-09-18 16:05:41 -05:00
|
|
|
//go:build profile
|
|
|
|
// +build profile
|
|
|
|
|
|
|
|
package pprof_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
. "github.com/smartystreets/goconvey/convey"
|
|
|
|
"gopkg.in/resty.v1"
|
|
|
|
|
2024-01-31 23:34:07 -05:00
|
|
|
"zotregistry.dev/zot/pkg/api"
|
|
|
|
"zotregistry.dev/zot/pkg/api/config"
|
|
|
|
"zotregistry.dev/zot/pkg/api/constants"
|
|
|
|
debugConstants "zotregistry.dev/zot/pkg/debug/constants"
|
|
|
|
test "zotregistry.dev/zot/pkg/test/common"
|
2023-09-18 16:05:41 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestProfilingAuthz(t *testing.T) {
|
|
|
|
Convey("Make a new controller", t, func() {
|
|
|
|
port := test.GetFreePort()
|
|
|
|
baseURL := test.GetBaseURL(port)
|
2023-10-26 03:20:39 -05:00
|
|
|
adminUsername, seedAdminUser := test.GenerateRandomString()
|
|
|
|
adminPassword, seedAdminPass := test.GenerateRandomString()
|
|
|
|
username, seedUser := test.GenerateRandomString()
|
|
|
|
password, seedPass := test.GenerateRandomString()
|
|
|
|
authorizationAllRepos := test.AuthorizationAllRepos
|
2023-09-18 16:05:41 -05:00
|
|
|
|
|
|
|
testCreds := test.GetCredString(adminUsername, adminPassword) +
|
2023-10-26 03:20:39 -05:00
|
|
|
test.GetCredString(username, password)
|
2023-09-18 16:05:41 -05:00
|
|
|
htpasswdPath := test.MakeHtpasswdFileFromString(testCreds)
|
2024-07-29 12:32:51 -05:00
|
|
|
|
2023-09-18 16:05:41 -05:00
|
|
|
defer os.Remove(htpasswdPath)
|
|
|
|
|
|
|
|
conf := config.New()
|
|
|
|
conf.HTTP.Port = port
|
|
|
|
conf.Storage.RootDirectory = t.TempDir()
|
|
|
|
|
|
|
|
Convey("Test with no access control", func() {
|
|
|
|
ctlr := api.NewController(conf)
|
|
|
|
cm := test.NewControllerManager(ctlr)
|
|
|
|
cm.StartAndWait(port)
|
2024-07-29 12:32:51 -05:00
|
|
|
|
2023-09-18 16:05:41 -05:00
|
|
|
defer cm.StopServer()
|
|
|
|
|
|
|
|
// unauthenticated clients should have access to /v2/
|
|
|
|
resp, err := resty.R().Get(baseURL + "/v2/")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(resp, ShouldNotBeNil)
|
|
|
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
|
|
|
|
|
|
// unauthenticated clients should have access to the profiling endpoints
|
|
|
|
resp, err = resty.R().Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint + "trace")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(resp, ShouldNotBeNil)
|
|
|
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
|
|
|
|
|
|
resp, err = resty.R().SetQueryParam("seconds", "1").
|
|
|
|
Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint + "profile")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(resp, ShouldNotBeNil)
|
|
|
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
|
|
|
|
|
|
resp, err = resty.R().Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint + "goroutine")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(resp, ShouldNotBeNil)
|
|
|
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
|
|
|
|
|
|
// test building the index
|
|
|
|
resp, err = resty.R().Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(resp, ShouldNotBeNil)
|
|
|
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Test with authenticated users and no anonymous policy", func() {
|
|
|
|
conf.HTTP.Auth = &config.AuthConfig{
|
|
|
|
HTPasswd: config.AuthHTPasswd{
|
|
|
|
Path: htpasswdPath,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
conf.HTTP.AccessControl = &config.AccessControlConfig{
|
|
|
|
Repositories: config.Repositories{
|
|
|
|
authorizationAllRepos: config.PolicyGroup{
|
|
|
|
Policies: []config.Policy{
|
|
|
|
{
|
|
|
|
Users: []string{username},
|
|
|
|
Actions: []string{"read", "create"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
DefaultPolicy: []string{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
AdminPolicy: config.Policy{
|
|
|
|
Users: []string{adminUsername},
|
|
|
|
Actions: []string{},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
ctlr := api.NewController(conf)
|
2023-10-26 03:20:39 -05:00
|
|
|
ctlr.Log.Info().Int64("seedAdminUser", seedAdminUser).Int64("seedAdminPass", seedAdminPass).
|
|
|
|
Msg("random seed for admin username & password")
|
|
|
|
ctlr.Log.Info().Int64("seedUser", seedUser).Int64("seedPass", seedPass).Msg("random seed for username & password")
|
2023-09-18 16:05:41 -05:00
|
|
|
cm := test.NewControllerManager(ctlr)
|
|
|
|
cm.StartAndWait(port)
|
2024-07-29 12:32:51 -05:00
|
|
|
|
2023-09-18 16:05:41 -05:00
|
|
|
defer cm.StopServer()
|
|
|
|
|
|
|
|
// unauthenticated clients should not have access to /v2/
|
|
|
|
resp, err := resty.R().Get(baseURL + "/v2/")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(resp, ShouldNotBeNil)
|
|
|
|
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
|
|
|
|
|
|
|
|
// unauthenticated clients should not have access to the profiling endpoint
|
|
|
|
resp, err = resty.R().Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint + "trace")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(resp, ShouldNotBeNil)
|
|
|
|
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
|
|
|
|
|
|
|
|
// authenticated clients without permissions should not have access to the profiling endpoint
|
|
|
|
resp, err = resty.R().SetBasicAuth(username, password).
|
|
|
|
Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint + "trace")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(resp, ShouldNotBeNil)
|
|
|
|
So(resp.StatusCode(), ShouldEqual, http.StatusForbidden)
|
|
|
|
|
|
|
|
// authenticated clients with admin permissions should have access to the profiling endpoint
|
|
|
|
resp, err = resty.R().SetBasicAuth(adminUsername, adminPassword).
|
|
|
|
Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint + "trace")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(resp, ShouldNotBeNil)
|
|
|
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Test with authenticated users and anonymous policy", func() {
|
|
|
|
conf.HTTP.Auth = &config.AuthConfig{
|
|
|
|
HTPasswd: config.AuthHTPasswd{
|
|
|
|
Path: htpasswdPath,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
conf.HTTP.AccessControl = &config.AccessControlConfig{
|
|
|
|
Repositories: config.Repositories{
|
|
|
|
authorizationAllRepos: config.PolicyGroup{
|
|
|
|
Policies: []config.Policy{
|
|
|
|
{
|
|
|
|
Users: []string{username},
|
|
|
|
Actions: []string{"read", "create"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
DefaultPolicy: []string{},
|
|
|
|
AnonymousPolicy: []string{"read"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
AdminPolicy: config.Policy{
|
|
|
|
Users: []string{adminUsername},
|
|
|
|
Actions: []string{},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
ctlr := api.NewController(conf)
|
|
|
|
cm := test.NewControllerManager(ctlr)
|
|
|
|
cm.StartAndWait(port)
|
2024-07-29 12:32:51 -05:00
|
|
|
|
2023-09-18 16:05:41 -05:00
|
|
|
defer cm.StopServer()
|
|
|
|
|
|
|
|
// unauthenticated clients should have access to /v2/
|
|
|
|
resp, err := resty.R().Get(baseURL + "/v2/")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(resp, ShouldNotBeNil)
|
|
|
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
|
|
|
|
|
|
// unauthenticated clients should not have access to the profiling endpoint
|
|
|
|
resp, err = resty.R().Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint + "trace")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(resp, ShouldNotBeNil)
|
|
|
|
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
|
|
|
|
|
|
|
|
// authenticated clients without permissions should not have access to the profiling endpoint
|
|
|
|
resp, err = resty.R().SetBasicAuth(username, password).
|
|
|
|
Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint + "trace")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(resp, ShouldNotBeNil)
|
|
|
|
So(resp.StatusCode(), ShouldEqual, http.StatusForbidden)
|
|
|
|
|
|
|
|
// authenticated clients with admin permissions should have access to the profiling endpoint
|
|
|
|
resp, err = resty.R().SetBasicAuth(adminUsername, adminPassword).
|
|
|
|
Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint + "trace")
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(resp, ShouldNotBeNil)
|
|
|
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|