zotregistry.io/zot@v1.4.4-0.20231124084042-02a8ed785457/pkg/debug/pprof/pprof_test.go (about)

     1  //go:build profile
     2  // +build profile
     3  
     4  package pprof_test
     5  
     6  import (
     7  	"net/http"
     8  	"os"
     9  	"testing"
    10  
    11  	. "github.com/smartystreets/goconvey/convey"
    12  	"gopkg.in/resty.v1"
    13  
    14  	"zotregistry.io/zot/pkg/api"
    15  	"zotregistry.io/zot/pkg/api/config"
    16  	"zotregistry.io/zot/pkg/api/constants"
    17  	debugConstants "zotregistry.io/zot/pkg/debug/constants"
    18  	test "zotregistry.io/zot/pkg/test/common"
    19  )
    20  
    21  func TestProfilingAuthz(t *testing.T) {
    22  	Convey("Make a new controller", t, func() {
    23  		port := test.GetFreePort()
    24  		baseURL := test.GetBaseURL(port)
    25  		adminUsername, seedAdminUser := test.GenerateRandomString()
    26  		adminPassword, seedAdminPass := test.GenerateRandomString()
    27  		username, seedUser := test.GenerateRandomString()
    28  		password, seedPass := test.GenerateRandomString()
    29  		authorizationAllRepos := test.AuthorizationAllRepos
    30  
    31  		testCreds := test.GetCredString(adminUsername, adminPassword) +
    32  			test.GetCredString(username, password)
    33  		htpasswdPath := test.MakeHtpasswdFileFromString(testCreds)
    34  		defer os.Remove(htpasswdPath)
    35  
    36  		conf := config.New()
    37  		conf.HTTP.Port = port
    38  		conf.Storage.RootDirectory = t.TempDir()
    39  
    40  		Convey("Test with no access control", func() {
    41  			ctlr := api.NewController(conf)
    42  			cm := test.NewControllerManager(ctlr)
    43  			cm.StartAndWait(port)
    44  			defer cm.StopServer()
    45  
    46  			// unauthenticated clients should have access to /v2/
    47  			resp, err := resty.R().Get(baseURL + "/v2/")
    48  			So(err, ShouldBeNil)
    49  			So(resp, ShouldNotBeNil)
    50  			So(resp.StatusCode(), ShouldEqual, http.StatusOK)
    51  
    52  			// unauthenticated clients should have access to the profiling endpoints
    53  			resp, err = resty.R().Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint + "trace")
    54  			So(err, ShouldBeNil)
    55  			So(resp, ShouldNotBeNil)
    56  			So(resp.StatusCode(), ShouldEqual, http.StatusOK)
    57  
    58  			resp, err = resty.R().SetQueryParam("seconds", "1").
    59  				Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint + "profile")
    60  			So(err, ShouldBeNil)
    61  			So(resp, ShouldNotBeNil)
    62  			So(resp.StatusCode(), ShouldEqual, http.StatusOK)
    63  
    64  			resp, err = resty.R().Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint + "goroutine")
    65  			So(err, ShouldBeNil)
    66  			So(resp, ShouldNotBeNil)
    67  			So(resp.StatusCode(), ShouldEqual, http.StatusOK)
    68  
    69  			// test building the index
    70  			resp, err = resty.R().Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint)
    71  			So(err, ShouldBeNil)
    72  			So(resp, ShouldNotBeNil)
    73  			So(resp.StatusCode(), ShouldEqual, http.StatusOK)
    74  		})
    75  
    76  		Convey("Test with authenticated users and no anonymous policy", func() {
    77  			conf.HTTP.Auth = &config.AuthConfig{
    78  				HTPasswd: config.AuthHTPasswd{
    79  					Path: htpasswdPath,
    80  				},
    81  			}
    82  			conf.HTTP.AccessControl = &config.AccessControlConfig{
    83  				Repositories: config.Repositories{
    84  					authorizationAllRepos: config.PolicyGroup{
    85  						Policies: []config.Policy{
    86  							{
    87  								Users:   []string{username},
    88  								Actions: []string{"read", "create"},
    89  							},
    90  						},
    91  						DefaultPolicy: []string{},
    92  					},
    93  				},
    94  				AdminPolicy: config.Policy{
    95  					Users:   []string{adminUsername},
    96  					Actions: []string{},
    97  				},
    98  			}
    99  
   100  			ctlr := api.NewController(conf)
   101  			ctlr.Log.Info().Int64("seedAdminUser", seedAdminUser).Int64("seedAdminPass", seedAdminPass).
   102  				Msg("random seed for admin username & password")
   103  			ctlr.Log.Info().Int64("seedUser", seedUser).Int64("seedPass", seedPass).Msg("random seed for username & password")
   104  			cm := test.NewControllerManager(ctlr)
   105  			cm.StartAndWait(port)
   106  			defer cm.StopServer()
   107  
   108  			// unauthenticated clients should not have access to /v2/
   109  			resp, err := resty.R().Get(baseURL + "/v2/")
   110  			So(err, ShouldBeNil)
   111  			So(resp, ShouldNotBeNil)
   112  			So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
   113  
   114  			// unauthenticated clients should not have access to the profiling endpoint
   115  			resp, err = resty.R().Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint + "trace")
   116  			So(err, ShouldBeNil)
   117  			So(resp, ShouldNotBeNil)
   118  			So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
   119  
   120  			// authenticated clients without permissions should not have access to the profiling endpoint
   121  			resp, err = resty.R().SetBasicAuth(username, password).
   122  				Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint + "trace")
   123  			So(err, ShouldBeNil)
   124  			So(resp, ShouldNotBeNil)
   125  			So(resp.StatusCode(), ShouldEqual, http.StatusForbidden)
   126  
   127  			// authenticated clients with admin permissions should have access to the profiling endpoint
   128  			resp, err = resty.R().SetBasicAuth(adminUsername, adminPassword).
   129  				Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint + "trace")
   130  			So(err, ShouldBeNil)
   131  			So(resp, ShouldNotBeNil)
   132  			So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   133  		})
   134  
   135  		Convey("Test with authenticated users and anonymous policy", func() {
   136  			conf.HTTP.Auth = &config.AuthConfig{
   137  				HTPasswd: config.AuthHTPasswd{
   138  					Path: htpasswdPath,
   139  				},
   140  			}
   141  			conf.HTTP.AccessControl = &config.AccessControlConfig{
   142  				Repositories: config.Repositories{
   143  					authorizationAllRepos: config.PolicyGroup{
   144  						Policies: []config.Policy{
   145  							{
   146  								Users:   []string{username},
   147  								Actions: []string{"read", "create"},
   148  							},
   149  						},
   150  						DefaultPolicy:   []string{},
   151  						AnonymousPolicy: []string{"read"},
   152  					},
   153  				},
   154  				AdminPolicy: config.Policy{
   155  					Users:   []string{adminUsername},
   156  					Actions: []string{},
   157  				},
   158  			}
   159  
   160  			ctlr := api.NewController(conf)
   161  			cm := test.NewControllerManager(ctlr)
   162  			cm.StartAndWait(port)
   163  			defer cm.StopServer()
   164  
   165  			// unauthenticated clients should have access to /v2/
   166  			resp, err := resty.R().Get(baseURL + "/v2/")
   167  			So(err, ShouldBeNil)
   168  			So(resp, ShouldNotBeNil)
   169  			So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   170  
   171  			// unauthenticated clients should not have access to the profiling endpoint
   172  			resp, err = resty.R().Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint + "trace")
   173  			So(err, ShouldBeNil)
   174  			So(resp, ShouldNotBeNil)
   175  			So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
   176  
   177  			// authenticated clients without permissions should not have access to the profiling endpoint
   178  			resp, err = resty.R().SetBasicAuth(username, password).
   179  				Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint + "trace")
   180  			So(err, ShouldBeNil)
   181  			So(resp, ShouldNotBeNil)
   182  			So(resp.StatusCode(), ShouldEqual, http.StatusForbidden)
   183  
   184  			// authenticated clients with admin permissions should have access to the profiling endpoint
   185  			resp, err = resty.R().SetBasicAuth(adminUsername, adminPassword).
   186  				Get(baseURL + constants.RoutePrefix + debugConstants.ProfilingEndpoint + "trace")
   187  			So(err, ShouldBeNil)
   188  			So(resp, ShouldNotBeNil)
   189  			So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   190  		})
   191  	})
   192  }