mirror of https://github.com/portainer/portainer
				
				
				
			feat(unit-testing): add a mock for the RequestBouncer EE-5610 (#9089)
							parent
							
								
									933e764a13
								
							
						
					
					
						commit
						f7dd73b0f7
					
				| 
						 | 
				
			
			@ -27,7 +27,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage authentication operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer, rateLimiter *security.RateLimiter, passwordStrengthChecker security.PasswordStrengthChecker) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService, rateLimiter *security.RateLimiter, passwordStrengthChecker security.PasswordStrengthChecker) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:                  mux.NewRouter(),
 | 
			
		||||
		passwordStrengthChecker: passwordStrengthChecker,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,8 @@ import (
 | 
			
		|||
	"github.com/portainer/portainer/api/crypto"
 | 
			
		||||
	"github.com/portainer/portainer/api/demo"
 | 
			
		||||
	"github.com/portainer/portainer/api/http/offlinegate"
 | 
			
		||||
	i "github.com/portainer/portainer/api/internal/testhelpers"
 | 
			
		||||
	"github.com/portainer/portainer/api/internal/testhelpers"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +49,14 @@ func Test_backupHandlerWithoutPassword_shouldCreateATarballArchive(t *testing.T)
 | 
			
		|||
	gate := offlinegate.NewOfflineGate()
 | 
			
		||||
	adminMonitor := adminmonitor.New(time.Hour, nil, context.Background())
 | 
			
		||||
 | 
			
		||||
	handlerErr := NewHandler(nil, i.NewDatastore(), gate, "./test_assets/handler_test", func() {}, adminMonitor, &demo.Service{}).backup(w, r)
 | 
			
		||||
	handlerErr := NewHandler(
 | 
			
		||||
		testhelpers.NewTestRequestBouncer(),
 | 
			
		||||
		testhelpers.NewDatastore(),
 | 
			
		||||
		gate,
 | 
			
		||||
		"./test_assets/handler_test",
 | 
			
		||||
		func() {},
 | 
			
		||||
		adminMonitor,
 | 
			
		||||
		&demo.Service{}).backup(w, r)
 | 
			
		||||
	assert.Nil(t, handlerErr, "Handler should not fail")
 | 
			
		||||
 | 
			
		||||
	response := w.Result()
 | 
			
		||||
| 
						 | 
				
			
			@ -85,7 +93,14 @@ func Test_backupHandlerWithPassword_shouldCreateEncryptedATarballArchive(t *test
 | 
			
		|||
	gate := offlinegate.NewOfflineGate()
 | 
			
		||||
	adminMonitor := adminmonitor.New(time.Hour, nil, nil)
 | 
			
		||||
 | 
			
		||||
	handlerErr := NewHandler(nil, i.NewDatastore(), gate, "./test_assets/handler_test", func() {}, adminMonitor, &demo.Service{}).backup(w, r)
 | 
			
		||||
	handlerErr := NewHandler(
 | 
			
		||||
		testhelpers.NewTestRequestBouncer(),
 | 
			
		||||
		testhelpers.NewDatastore(),
 | 
			
		||||
		gate,
 | 
			
		||||
		"./test_assets/handler_test",
 | 
			
		||||
		func() {},
 | 
			
		||||
		adminMonitor,
 | 
			
		||||
		&demo.Service{}).backup(w, r)
 | 
			
		||||
	assert.Nil(t, handlerErr, "Handler should not fail")
 | 
			
		||||
 | 
			
		||||
	response := w.Result()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,6 @@ import (
 | 
			
		|||
	"context"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/gorilla/mux"
 | 
			
		||||
	httperror "github.com/portainer/libhttp/error"
 | 
			
		||||
	"github.com/portainer/portainer/api/adminmonitor"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices"
 | 
			
		||||
| 
						 | 
				
			
			@ -12,12 +11,14 @@ import (
 | 
			
		|||
	"github.com/portainer/portainer/api/http/middlewares"
 | 
			
		||||
	"github.com/portainer/portainer/api/http/offlinegate"
 | 
			
		||||
	"github.com/portainer/portainer/api/http/security"
 | 
			
		||||
 | 
			
		||||
	"github.com/gorilla/mux"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Handler is an http handler responsible for backup and restore portainer state
 | 
			
		||||
type Handler struct {
 | 
			
		||||
	*mux.Router
 | 
			
		||||
	bouncer         *security.RequestBouncer
 | 
			
		||||
	bouncer         security.BouncerService
 | 
			
		||||
	dataStore       dataservices.DataStore
 | 
			
		||||
	gate            *offlinegate.OfflineGate
 | 
			
		||||
	filestorePath   string
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +28,7 @@ type Handler struct {
 | 
			
		|||
 | 
			
		||||
// NewHandler creates an new instance of backup handler
 | 
			
		||||
func NewHandler(
 | 
			
		||||
	bouncer *security.RequestBouncer,
 | 
			
		||||
	bouncer security.BouncerService,
 | 
			
		||||
	dataStore dataservices.DataStore,
 | 
			
		||||
	gate *offlinegate.OfflineGate,
 | 
			
		||||
	filestorePath string,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,8 @@ import (
 | 
			
		|||
	"github.com/portainer/portainer/api/adminmonitor"
 | 
			
		||||
	"github.com/portainer/portainer/api/demo"
 | 
			
		||||
	"github.com/portainer/portainer/api/http/offlinegate"
 | 
			
		||||
	i "github.com/portainer/portainer/api/internal/testhelpers"
 | 
			
		||||
	"github.com/portainer/portainer/api/internal/testhelpers"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -49,10 +50,21 @@ func Test_restoreArchive_usingCombinationOfPasswords(t *testing.T) {
 | 
			
		|||
 | 
			
		||||
	for _, test := range tests {
 | 
			
		||||
		t.Run(test.name, func(t *testing.T) {
 | 
			
		||||
			datastore := i.NewDatastore(i.WithUsers([]portainer.User{}), i.WithEdgeJobs([]portainer.EdgeJob{}))
 | 
			
		||||
			datastore := testhelpers.NewDatastore(
 | 
			
		||||
				testhelpers.WithUsers([]portainer.User{}),
 | 
			
		||||
				testhelpers.WithEdgeJobs([]portainer.EdgeJob{}),
 | 
			
		||||
			)
 | 
			
		||||
			adminMonitor := adminmonitor.New(time.Hour, datastore, context.Background())
 | 
			
		||||
 | 
			
		||||
			h := NewHandler(nil, datastore, offlinegate.NewOfflineGate(), "./test_assets/handler_test", func() {}, adminMonitor, &demo.Service{})
 | 
			
		||||
			h := NewHandler(
 | 
			
		||||
				testhelpers.NewTestRequestBouncer(),
 | 
			
		||||
				datastore,
 | 
			
		||||
				offlinegate.NewOfflineGate(),
 | 
			
		||||
				"./test_assets/handler_test",
 | 
			
		||||
				func() {},
 | 
			
		||||
				adminMonitor,
 | 
			
		||||
				&demo.Service{},
 | 
			
		||||
			)
 | 
			
		||||
 | 
			
		||||
			//backup
 | 
			
		||||
			archive := backup(t, h, test.backupPassword)
 | 
			
		||||
| 
						 | 
				
			
			@ -72,10 +84,20 @@ func Test_restoreArchive_shouldFailIfSystemWasAlreadyInitialized(t *testing.T) {
 | 
			
		|||
	admin := portainer.User{
 | 
			
		||||
		Role: portainer.AdministratorRole,
 | 
			
		||||
	}
 | 
			
		||||
	datastore := i.NewDatastore(i.WithUsers([]portainer.User{admin}), i.WithEdgeJobs([]portainer.EdgeJob{}))
 | 
			
		||||
	datastore := testhelpers.NewDatastore(
 | 
			
		||||
		testhelpers.WithUsers([]portainer.User{admin}),
 | 
			
		||||
		testhelpers.WithEdgeJobs([]portainer.EdgeJob{}),
 | 
			
		||||
	)
 | 
			
		||||
	adminMonitor := adminmonitor.New(time.Hour, datastore, context.Background())
 | 
			
		||||
 | 
			
		||||
	h := NewHandler(nil, datastore, offlinegate.NewOfflineGate(), "./test_assets/handler_test", func() {}, adminMonitor, &demo.Service{})
 | 
			
		||||
	h := NewHandler(testhelpers.NewTestRequestBouncer(),
 | 
			
		||||
		datastore,
 | 
			
		||||
		offlinegate.NewOfflineGate(),
 | 
			
		||||
		"./test_assets/handler_test",
 | 
			
		||||
		func() {},
 | 
			
		||||
		adminMonitor,
 | 
			
		||||
		&demo.Service{},
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	//backup
 | 
			
		||||
	archive := backup(t, h, "password")
 | 
			
		||||
| 
						 | 
				
			
			@ -106,11 +128,13 @@ func backup(t *testing.T, h *Handler, password string) []byte {
 | 
			
		|||
 | 
			
		||||
func prepareMultipartRequest(password string, file []byte) (*http.Request, error) {
 | 
			
		||||
	var body bytes.Buffer
 | 
			
		||||
 | 
			
		||||
	w := multipart.NewWriter(&body)
 | 
			
		||||
	err := w.WriteField("password", password)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fw, err := w.CreateFormFile("file", "filename")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage environment(endpoint) group operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer, dataStore dataservices.DataStore, fileService portainer.FileService, gitService portainer.GitService) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService, dataStore dataservices.DataStore, fileService portainer.FileService, gitService portainer.GitService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:         mux.NewRouter(),
 | 
			
		||||
		DataStore:      dataStore,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,11 +16,11 @@ type Handler struct {
 | 
			
		|||
	dockerClientFactory *dockerclient.ClientFactory
 | 
			
		||||
	dataStore           dataservices.DataStore
 | 
			
		||||
	containerService    *docker.ContainerService
 | 
			
		||||
	bouncer             *security.RequestBouncer
 | 
			
		||||
	bouncer             security.BouncerService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to process non-proxied requests to docker APIs directly.
 | 
			
		||||
func NewHandler(routePrefix string, bouncer *security.RequestBouncer, dataStore dataservices.DataStore, dockerClientFactory *dockerclient.ClientFactory, containerService *docker.ContainerService) *Handler {
 | 
			
		||||
func NewHandler(routePrefix string, bouncer security.BouncerService, dataStore dataservices.DataStore, dockerClientFactory *dockerclient.ClientFactory, containerService *docker.ContainerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:              mux.NewRouter(),
 | 
			
		||||
		dataStore:           dataStore,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ import (
 | 
			
		|||
// Handler is the HTTP handler which will natively deal with to external environments(endpoints).
 | 
			
		||||
type Handler struct {
 | 
			
		||||
	*mux.Router
 | 
			
		||||
	requestBouncer       *security.RequestBouncer
 | 
			
		||||
	requestBouncer       security.BouncerService
 | 
			
		||||
	dataStore            dataservices.DataStore
 | 
			
		||||
	dockerClientFactory  *dockerclient.ClientFactory
 | 
			
		||||
	authorizationService *authorization.Service
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to process non-proxied requests to docker APIs directly.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer, authorizationService *authorization.Service, dataStore dataservices.DataStore, dockerClientFactory *dockerclient.ClientFactory, containerService *docker.ContainerService) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService, authorizationService *authorization.Service, dataStore dataservices.DataStore, dockerClientFactory *dockerclient.ClientFactory, containerService *docker.ContainerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:               mux.NewRouter(),
 | 
			
		||||
		requestBouncer:       bouncer,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage environment(endpoint) group operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router: mux.NewRouter(),
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage Edge job operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router: mux.NewRouter(),
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ import (
 | 
			
		|||
// Handler is the HTTP handler used to handle environment(endpoint) group operations.
 | 
			
		||||
type Handler struct {
 | 
			
		||||
	*mux.Router
 | 
			
		||||
	requestBouncer     *security.RequestBouncer
 | 
			
		||||
	requestBouncer     security.BouncerService
 | 
			
		||||
	DataStore          dataservices.DataStore
 | 
			
		||||
	FileService        portainer.FileService
 | 
			
		||||
	GitService         portainer.GitService
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ type Handler struct {
 | 
			
		|||
const contextKey = "edgeStack_item"
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage environment(endpoint) group operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer, dataStore dataservices.DataStore, edgeStacksService *edgestackservice.Service) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService, dataStore dataservices.DataStore, edgeStacksService *edgestackservice.Service) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:            mux.NewRouter(),
 | 
			
		||||
		requestBouncer:    bouncer,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,12 +13,12 @@ import (
 | 
			
		|||
// Handler is the HTTP handler used to handle edge environment(endpoint) operations.
 | 
			
		||||
type Handler struct {
 | 
			
		||||
	*mux.Router
 | 
			
		||||
	requestBouncer *security.RequestBouncer
 | 
			
		||||
	requestBouncer security.BouncerService
 | 
			
		||||
	DataStore      dataservices.DataStore
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage environment(endpoint) operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:         mux.NewRouter(),
 | 
			
		||||
		requestBouncer: bouncer,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,14 +15,14 @@ import (
 | 
			
		|||
// Handler is the HTTP handler used to handle edge environment(endpoint) operations.
 | 
			
		||||
type Handler struct {
 | 
			
		||||
	*mux.Router
 | 
			
		||||
	requestBouncer       *security.RequestBouncer
 | 
			
		||||
	requestBouncer       security.BouncerService
 | 
			
		||||
	DataStore            dataservices.DataStore
 | 
			
		||||
	FileService          portainer.FileService
 | 
			
		||||
	ReverseTunnelService portainer.ReverseTunnelService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage environment(endpoint) operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer, dataStore dataservices.DataStore, fileService portainer.FileService, reverseTunnelService portainer.ReverseTunnelService) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService, dataStore dataservices.DataStore, fileService portainer.FileService, reverseTunnelService portainer.ReverseTunnelService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:               mux.NewRouter(),
 | 
			
		||||
		requestBouncer:       bouncer,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage environment(endpoint) group operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router: mux.NewRouter(),
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,13 +13,13 @@ import (
 | 
			
		|||
type Handler struct {
 | 
			
		||||
	*mux.Router
 | 
			
		||||
	DataStore            dataservices.DataStore
 | 
			
		||||
	requestBouncer       *security.RequestBouncer
 | 
			
		||||
	requestBouncer       security.BouncerService
 | 
			
		||||
	ProxyManager         *proxy.Manager
 | 
			
		||||
	ReverseTunnelService portainer.ReverseTunnelService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to proxy requests to external APIs.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:         mux.NewRouter(),
 | 
			
		||||
		requestBouncer: bouncer,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,12 +8,10 @@ import (
 | 
			
		|||
	"testing"
 | 
			
		||||
 | 
			
		||||
	portainer "github.com/portainer/portainer/api"
 | 
			
		||||
	"github.com/portainer/portainer/api/apikey"
 | 
			
		||||
	"github.com/portainer/portainer/api/datastore"
 | 
			
		||||
	"github.com/portainer/portainer/api/demo"
 | 
			
		||||
	"github.com/portainer/portainer/api/http/proxy"
 | 
			
		||||
	"github.com/portainer/portainer/api/http/security"
 | 
			
		||||
	"github.com/portainer/portainer/api/jwt"
 | 
			
		||||
	"github.com/portainer/portainer/api/internal/testhelpers"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestEndpointDeleteEdgeGroupsConcurrently(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -21,26 +19,7 @@ func TestEndpointDeleteEdgeGroupsConcurrently(t *testing.T) {
 | 
			
		|||
 | 
			
		||||
	_, store := datastore.MustNewTestStore(t, true, false)
 | 
			
		||||
 | 
			
		||||
	user := &portainer.User{ID: 2, Username: "admin", Role: portainer.AdministratorRole}
 | 
			
		||||
	err := store.User().Create(user)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("could not create admin user:", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	jwtService, err := jwt.NewService("1h", store)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("could not initialize the JWT service:", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	apiKeyService := apikey.NewAPIKeyService(store.APIKeyRepository(), store.User())
 | 
			
		||||
	rawAPIKey, _, err := apiKeyService.GenerateApiKey(*user, "test")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("could not generate API key:", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bouncer := security.NewRequestBouncer(store, jwtService, apiKeyService)
 | 
			
		||||
 | 
			
		||||
	handler := NewHandler(bouncer, demo.NewService())
 | 
			
		||||
	handler := NewHandler(testhelpers.NewTestRequestBouncer(), demo.NewService())
 | 
			
		||||
	handler.DataStore = store
 | 
			
		||||
	handler.ProxyManager = proxy.NewManager(nil, nil, nil, nil, nil, nil, nil)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +30,7 @@ func TestEndpointDeleteEdgeGroupsConcurrently(t *testing.T) {
 | 
			
		|||
	for i := 0; i < endpointsCount; i++ {
 | 
			
		||||
		endpointID := portainer.EndpointID(i) + 1
 | 
			
		||||
 | 
			
		||||
		err = store.Endpoint().Create(&portainer.Endpoint{
 | 
			
		||||
		err := store.Endpoint().Create(&portainer.Endpoint{
 | 
			
		||||
			ID:   endpointID,
 | 
			
		||||
			Name: "env-" + strconv.Itoa(int(endpointID)),
 | 
			
		||||
			Type: portainer.EdgeAgentOnDockerEnvironment,
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +42,7 @@ func TestEndpointDeleteEdgeGroupsConcurrently(t *testing.T) {
 | 
			
		|||
		endpointIDs = append(endpointIDs, endpointID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = store.EdgeGroup().Create(&portainer.EdgeGroup{
 | 
			
		||||
	err := store.EdgeGroup().Create(&portainer.EdgeGroup{
 | 
			
		||||
		ID:        1,
 | 
			
		||||
		Name:      "edgegroup-1",
 | 
			
		||||
		Endpoints: endpointIDs,
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +65,6 @@ func TestEndpointDeleteEdgeGroupsConcurrently(t *testing.T) {
 | 
			
		|||
				t.Fail()
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			req.Header.Add("X-Api-Key", rawAPIKey)
 | 
			
		||||
 | 
			
		||||
			rec := httptest.NewRecorder()
 | 
			
		||||
			handler.ServeHTTP(rec, req)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@ import (
 | 
			
		|||
	"github.com/portainer/portainer/api/dataservices"
 | 
			
		||||
	"github.com/portainer/portainer/api/demo"
 | 
			
		||||
	"github.com/portainer/portainer/api/http/proxy"
 | 
			
		||||
	"github.com/portainer/portainer/api/http/security"
 | 
			
		||||
	"github.com/portainer/portainer/api/internal/authorization"
 | 
			
		||||
	"github.com/portainer/portainer/api/kubernetes/cli"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -21,21 +22,10 @@ func hideFields(endpoint *portainer.Endpoint) {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This requestBouncer exists because security.RequestBounder is a type and not an interface.
 | 
			
		||||
// Therefore we can not swit	 it out with a dummy bouncer for go tests.  This interface works around it
 | 
			
		||||
type requestBouncer interface {
 | 
			
		||||
	AuthenticatedAccess(h http.Handler) http.Handler
 | 
			
		||||
	AdminAccess(h http.Handler) http.Handler
 | 
			
		||||
	RestrictedAccess(h http.Handler) http.Handler
 | 
			
		||||
	PublicAccess(h http.Handler) http.Handler
 | 
			
		||||
	AuthorizedEndpointOperation(r *http.Request, endpoint *portainer.Endpoint) error
 | 
			
		||||
	AuthorizedEdgeEndpointOperation(r *http.Request, endpoint *portainer.Endpoint) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handler is the HTTP handler used to handle environment(endpoint) operations.
 | 
			
		||||
type Handler struct {
 | 
			
		||||
	*mux.Router
 | 
			
		||||
	requestBouncer       requestBouncer
 | 
			
		||||
	requestBouncer       security.BouncerService
 | 
			
		||||
	demoService          *demo.Service
 | 
			
		||||
	DataStore            dataservices.DataStore
 | 
			
		||||
	FileService          portainer.FileService
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +40,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage environment(endpoint) operations.
 | 
			
		||||
func NewHandler(bouncer requestBouncer, demoService *demo.Service) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService, demoService *demo.Service) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:         mux.NewRouter(),
 | 
			
		||||
		requestBouncer: bouncer,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ type Handler struct {
 | 
			
		|||
	fileService portainer.FileService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer, dataStore dataservices.DataStore, gitService portainer.GitService, fileService portainer.FileService) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService, dataStore dataservices.DataStore, gitService portainer.GitService, fileService portainer.FileService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:      mux.NewRouter(),
 | 
			
		||||
		dataStore:   dataStore,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,14 +14,10 @@ import (
 | 
			
		|||
	"github.com/portainer/portainer/pkg/libhelm/options"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type requestBouncer interface {
 | 
			
		||||
	AuthenticatedAccess(h http.Handler) http.Handler
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handler is the HTTP handler used to handle environment(endpoint) group operations.
 | 
			
		||||
type Handler struct {
 | 
			
		||||
	*mux.Router
 | 
			
		||||
	requestBouncer           requestBouncer
 | 
			
		||||
	requestBouncer           security.BouncerService
 | 
			
		||||
	dataStore                dataservices.DataStore
 | 
			
		||||
	jwtService               dataservices.JWTService
 | 
			
		||||
	kubeClusterAccessService kubernetes.KubeClusterAccessService
 | 
			
		||||
| 
						 | 
				
			
			@ -30,7 +26,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage endpoint group operations.
 | 
			
		||||
func NewHandler(bouncer requestBouncer, dataStore dataservices.DataStore, jwtService dataservices.JWTService, kubernetesDeployer portainer.KubernetesDeployer, helmPackageManager libhelm.HelmPackageManager, kubeClusterAccessService kubernetes.KubeClusterAccessService) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService, dataStore dataservices.DataStore, jwtService dataservices.JWTService, kubernetesDeployer portainer.KubernetesDeployer, helmPackageManager libhelm.HelmPackageManager, kubeClusterAccessService kubernetes.KubeClusterAccessService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:                   mux.NewRouter(),
 | 
			
		||||
		requestBouncer:           bouncer,
 | 
			
		||||
| 
						 | 
				
			
			@ -64,7 +60,7 @@ func NewHandler(bouncer requestBouncer, dataStore dataservices.DataStore, jwtSer
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewTemplateHandler creates a template handler to manage environment(endpoint) group operations.
 | 
			
		||||
func NewTemplateHandler(bouncer requestBouncer, helmPackageManager libhelm.HelmPackageManager) *Handler {
 | 
			
		||||
func NewTemplateHandler(bouncer security.BouncerService, helmPackageManager libhelm.HelmPackageManager) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:             mux.NewRouter(),
 | 
			
		||||
		helmPackageManager: helmPackageManager,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ type Handler struct {
 | 
			
		|||
	FileService portainer.FileService
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer, dataStore dataservices.DataStore, fileService portainer.FileService) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService, dataStore dataservices.DataStore, fileService portainer.FileService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:      mux.NewRouter(),
 | 
			
		||||
		DataStore:   dataStore,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler returns a new Handler
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router: mux.NewRouter(),
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,7 +31,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to process pre-proxied requests to external APIs.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer, authorizationService *authorization.Service, dataStore dataservices.DataStore, jwtService dataservices.JWTService, kubeClusterAccessService kubernetes.KubeClusterAccessService, kubernetesClientFactory *cli.ClientFactory, kubernetesClient portainer.KubeClient) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService, authorizationService *authorization.Service, dataStore dataservices.DataStore, jwtService dataservices.JWTService, kubeClusterAccessService kubernetes.KubeClusterAccessService, kubernetesClientFactory *cli.ClientFactory, kubernetesClient portainer.KubeClient) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:                   mux.NewRouter(),
 | 
			
		||||
		authorizationService:     authorizationService,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler returns a new Handler
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router: mux.NewRouter(),
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler returns a new Handler
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router: mux.NewRouter(),
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ func hideFields(registry *portainer.Registry, hideAccesses bool) {
 | 
			
		|||
// Handler is the HTTP handler used to handle registry operations.
 | 
			
		||||
type Handler struct {
 | 
			
		||||
	*mux.Router
 | 
			
		||||
	requestBouncer   *security.RequestBouncer
 | 
			
		||||
	requestBouncer   security.BouncerService
 | 
			
		||||
	DataStore        dataservices.DataStore
 | 
			
		||||
	FileService      portainer.FileService
 | 
			
		||||
	ProxyManager     *proxy.Manager
 | 
			
		||||
| 
						 | 
				
			
			@ -32,14 +32,14 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage registry operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := newHandler(bouncer)
 | 
			
		||||
	h.initRouter(bouncer)
 | 
			
		||||
 | 
			
		||||
	return h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func newHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	return &Handler{
 | 
			
		||||
		Router:         mux.NewRouter(),
 | 
			
		||||
		requestBouncer: bouncer,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage resource control operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router: mux.NewRouter(),
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage role operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router: mux.NewRouter(),
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,7 +29,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage settings operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer, demoService *demo.Service) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService, demoService *demo.Service) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:      mux.NewRouter(),
 | 
			
		||||
		demoService: demoService,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler returns a new Handler
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router: mux.NewRouter(),
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ import (
 | 
			
		|||
type Handler struct {
 | 
			
		||||
	stackCreationMutex *sync.Mutex
 | 
			
		||||
	stackDeletionMutex *sync.Mutex
 | 
			
		||||
	requestBouncer     *security.RequestBouncer
 | 
			
		||||
	requestBouncer     security.BouncerService
 | 
			
		||||
	*mux.Router
 | 
			
		||||
	DataStore               dataservices.DataStore
 | 
			
		||||
	DockerClientFactory     *dockerclient.ClientFactory
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ func stackExistsError(name string) *httperror.HandlerError {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage stack operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:             mux.NewRouter(),
 | 
			
		||||
		stackCreationMutex: &sync.Mutex{},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,10 +5,11 @@ import (
 | 
			
		|||
	"net/http/httptest"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	portainer "github.com/portainer/portainer/api"
 | 
			
		||||
	"github.com/portainer/portainer/api/datastore"
 | 
			
		||||
	"github.com/portainer/portainer/api/internal/testhelpers"
 | 
			
		||||
 | 
			
		||||
	"github.com/gofrs/uuid"
 | 
			
		||||
	portainer "github.com/portainer/portainer/api"
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +24,7 @@ func TestHandler_webhookInvoke(t *testing.T) {
 | 
			
		|||
		},
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	h := NewHandler(nil)
 | 
			
		||||
	h := NewHandler(testhelpers.NewTestRequestBouncer())
 | 
			
		||||
	h.DataStore = store
 | 
			
		||||
 | 
			
		||||
	t.Run("invalid uuid results in http.StatusBadRequest", func(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -32,12 +33,14 @@ func TestHandler_webhookInvoke(t *testing.T) {
 | 
			
		|||
		h.Router.ServeHTTP(w, req)
 | 
			
		||||
		assert.Equal(t, http.StatusBadRequest, w.Code)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	t.Run("registered webhook ID in http.StatusNoContent", func(t *testing.T) {
 | 
			
		||||
		w := httptest.NewRecorder()
 | 
			
		||||
		req := newRequest(webhookID)
 | 
			
		||||
		h.Router.ServeHTTP(w, req)
 | 
			
		||||
		assert.Equal(t, http.StatusNoContent, w.Code)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	t.Run("unregistered webhook ID in http.StatusNotFound", func(t *testing.T) {
 | 
			
		||||
		w := httptest.NewRecorder()
 | 
			
		||||
		req := newRequest(newGuidString(t))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage status operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer,
 | 
			
		||||
func NewHandler(bouncer security.BouncerService,
 | 
			
		||||
	status *portainer.Status,
 | 
			
		||||
	demoService *demo.Service,
 | 
			
		||||
	dataStore dataservices.DataStore,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage tag operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router: mux.NewRouter(),
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,10 +8,8 @@ import (
 | 
			
		|||
	"testing"
 | 
			
		||||
 | 
			
		||||
	portainer "github.com/portainer/portainer/api"
 | 
			
		||||
	"github.com/portainer/portainer/api/apikey"
 | 
			
		||||
	"github.com/portainer/portainer/api/datastore"
 | 
			
		||||
	"github.com/portainer/portainer/api/http/security"
 | 
			
		||||
	"github.com/portainer/portainer/api/jwt"
 | 
			
		||||
	"github.com/portainer/portainer/api/internal/testhelpers"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestTagDeleteEdgeGroupsConcurrently(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -25,20 +23,7 @@ func TestTagDeleteEdgeGroupsConcurrently(t *testing.T) {
 | 
			
		|||
		t.Fatal("could not create admin user:", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	jwtService, err := jwt.NewService("1h", store)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("could not initialize the JWT service:", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	apiKeyService := apikey.NewAPIKeyService(store.APIKeyRepository(), store.User())
 | 
			
		||||
	rawAPIKey, _, err := apiKeyService.GenerateApiKey(*user, "test")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("could not generate API key:", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bouncer := security.NewRequestBouncer(store, jwtService, apiKeyService)
 | 
			
		||||
 | 
			
		||||
	handler := NewHandler(bouncer)
 | 
			
		||||
	handler := NewHandler(testhelpers.NewTestRequestBouncer())
 | 
			
		||||
	handler.DataStore = store
 | 
			
		||||
 | 
			
		||||
	// Create all the tags and add them to the same edge group
 | 
			
		||||
| 
						 | 
				
			
			@ -82,7 +67,6 @@ func TestTagDeleteEdgeGroupsConcurrently(t *testing.T) {
 | 
			
		|||
				t.Fail()
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			req.Header.Add("X-Api-Key", rawAPIKey)
 | 
			
		||||
 | 
			
		||||
			rec := httptest.NewRecorder()
 | 
			
		||||
			handler.ServeHTTP(rec, req)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage team membership operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router: mux.NewRouter(),
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage team operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router: mux.NewRouter(),
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler returns a new instance of Handler.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router: mux.NewRouter(),
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage upload operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router: mux.NewRouter(),
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,7 +31,7 @@ func hideFields(user *portainer.User) {
 | 
			
		|||
// Handler is the HTTP handler used to handle user operations.
 | 
			
		||||
type Handler struct {
 | 
			
		||||
	*mux.Router
 | 
			
		||||
	bouncer                 *security.RequestBouncer
 | 
			
		||||
	bouncer                 security.BouncerService
 | 
			
		||||
	apiKeyService           apikey.APIKeyService
 | 
			
		||||
	demoService             *demo.Service
 | 
			
		||||
	DataStore               dataservices.DataStore
 | 
			
		||||
| 
						 | 
				
			
			@ -41,7 +41,7 @@ type Handler struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage user operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer, rateLimiter *security.RateLimiter, apiKeyService apikey.APIKeyService, demoService *demo.Service, passwordStrengthChecker security.PasswordStrengthChecker) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService, rateLimiter *security.RateLimiter, apiKeyService apikey.APIKeyService, demoService *demo.Service, passwordStrengthChecker security.PasswordStrengthChecker) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:                  mux.NewRouter(),
 | 
			
		||||
		bouncer:                 bouncer,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,10 +3,9 @@ package webhooks
 | 
			
		|||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	httperror "github.com/portainer/libhttp/error"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices"
 | 
			
		||||
	dockerclient "github.com/portainer/portainer/api/docker/client"
 | 
			
		||||
 | 
			
		||||
	httperror "github.com/portainer/libhttp/error"
 | 
			
		||||
	"github.com/portainer/portainer/api/http/security"
 | 
			
		||||
 | 
			
		||||
	"github.com/gorilla/mux"
 | 
			
		||||
| 
						 | 
				
			
			@ -15,13 +14,13 @@ import (
 | 
			
		|||
// Handler is the HTTP handler used to handle webhook operations.
 | 
			
		||||
type Handler struct {
 | 
			
		||||
	*mux.Router
 | 
			
		||||
	requestBouncer      *security.RequestBouncer
 | 
			
		||||
	requestBouncer      security.BouncerService
 | 
			
		||||
	DataStore           dataservices.DataStore
 | 
			
		||||
	DockerClientFactory *dockerclient.ClientFactory
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage webhooks operations.
 | 
			
		||||
func NewHandler(bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:         mux.NewRouter(),
 | 
			
		||||
		requestBouncer: bouncer,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,13 +18,13 @@ type Handler struct {
 | 
			
		|||
	SignatureService            portainer.DigitalSignatureService
 | 
			
		||||
	ReverseTunnelService        portainer.ReverseTunnelService
 | 
			
		||||
	KubernetesClientFactory     *cli.ClientFactory
 | 
			
		||||
	requestBouncer              *security.RequestBouncer
 | 
			
		||||
	requestBouncer              security.BouncerService
 | 
			
		||||
	connectionUpgrader          websocket.Upgrader
 | 
			
		||||
	kubernetesTokenCacheManager *kubernetes.TokenCacheManager
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a handler to manage websocket operations.
 | 
			
		||||
func NewHandler(kubernetesTokenCacheManager *kubernetes.TokenCacheManager, bouncer *security.RequestBouncer) *Handler {
 | 
			
		||||
func NewHandler(kubernetesTokenCacheManager *kubernetes.TokenCacheManager, bouncer security.BouncerService) *Handler {
 | 
			
		||||
	h := &Handler{
 | 
			
		||||
		Router:                      mux.NewRouter(),
 | 
			
		||||
		connectionUpgrader:          websocket.Upgrader{},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,15 +5,30 @@ import (
 | 
			
		|||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	httperror "github.com/portainer/libhttp/error"
 | 
			
		||||
	portainer "github.com/portainer/portainer/api"
 | 
			
		||||
	"github.com/portainer/portainer/api/apikey"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices"
 | 
			
		||||
	httperrors "github.com/portainer/portainer/api/http/errors"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
	BouncerService interface {
 | 
			
		||||
		PublicAccess(http.Handler) http.Handler
 | 
			
		||||
		AdminAccess(http.Handler) http.Handler
 | 
			
		||||
		RestrictedAccess(http.Handler) http.Handler
 | 
			
		||||
		TeamLeaderAccess(http.Handler) http.Handler
 | 
			
		||||
		AuthenticatedAccess(http.Handler) http.Handler
 | 
			
		||||
		EdgeComputeOperation(http.Handler) http.Handler
 | 
			
		||||
 | 
			
		||||
		AuthorizedEndpointOperation(*http.Request, *portainer.Endpoint) error
 | 
			
		||||
		AuthorizedEdgeEndpointOperation(*http.Request, *portainer.Endpoint) error
 | 
			
		||||
		TrustedEdgeEnvironmentAccess(dataservices.DataStoreTx, *portainer.Endpoint) error
 | 
			
		||||
		JWTAuthLookup(*http.Request) *portainer.TokenData
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// RequestBouncer represents an entity that manages API request accesses
 | 
			
		||||
	RequestBouncer struct {
 | 
			
		||||
		dataStore     dataservices.DataStore
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,10 +4,10 @@ import (
 | 
			
		|||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	portainer "github.com/portainer/portainer/api"
 | 
			
		||||
	"github.com/portainer/portainer/api/dataservices"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type testRequestBouncer struct {
 | 
			
		||||
}
 | 
			
		||||
type testRequestBouncer struct{}
 | 
			
		||||
 | 
			
		||||
// NewTestRequestBouncer creates new mock for requestBouncer
 | 
			
		||||
func NewTestRequestBouncer() *testRequestBouncer {
 | 
			
		||||
| 
						 | 
				
			
			@ -30,6 +30,14 @@ func (testRequestBouncer) PublicAccess(h http.Handler) http.Handler {
 | 
			
		|||
	return h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (testRequestBouncer) TeamLeaderAccess(h http.Handler) http.Handler {
 | 
			
		||||
	return h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (testRequestBouncer) EdgeComputeOperation(h http.Handler) http.Handler {
 | 
			
		||||
	return h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (testRequestBouncer) AuthorizedEndpointOperation(r *http.Request, endpoint *portainer.Endpoint) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -37,3 +45,11 @@ func (testRequestBouncer) AuthorizedEndpointOperation(r *http.Request, endpoint
 | 
			
		|||
func (testRequestBouncer) AuthorizedEdgeEndpointOperation(r *http.Request, endpoint *portainer.Endpoint) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (testRequestBouncer) TrustedEdgeEnvironmentAccess(tx dataservices.DataStoreTx, endpoint *portainer.Endpoint) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (testRequestBouncer) JWTAuthLookup(r *http.Request) *portainer.TokenData {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue