graphql: Apply authorization on /_search endpoint

- AccessControlContext now resides in a separate package from where it can be imported,
along with the contextKey that will be used to set and retrieve this context value.

- AccessControlContext has a new field called Username, that will be of use for future
implementations in graphQL resolvers.

- GlobalSearch resolver now uses this context to filter repos available to the logged user.

- moved logic for uploading images in tests so that it can be used in every package

- tests were added for multiple request scenarios, when zot-server requires authz
on specific repos

- added tests with injected errors for extended coverage

- added tests for status code error injection utilities

Closes https://github.com/project-zot/zot/issues/615

Signed-off-by: Alex Stan <alexandrustan96@yahoo.ro>
This commit is contained in:
Alex Stan
2022-08-16 11:57:09 +03:00
committed by Andrei Aaron
parent 5450139ba1
commit 49e8167dbe
15 changed files with 763 additions and 165 deletions
+18 -17
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"net/http"
"strings"
"time"
glob "github.com/bmatcuk/doublestar/v4"
@@ -12,19 +13,15 @@ import (
"zotregistry.io/zot/pkg/api/constants"
"zotregistry.io/zot/pkg/common"
"zotregistry.io/zot/pkg/log"
localCtx "zotregistry.io/zot/pkg/requestcontext"
)
type contextKey int
const (
// actions.
CREATE = "create"
READ = "read"
UPDATE = "update"
DELETE = "delete"
// request-local context key.
authzCtxKey contextKey = 0
)
// AccessController authorizes users to act on resources.
@@ -33,12 +30,6 @@ type AccessController struct {
Log log.Logger
}
// AccessControlContext context passed down to http.Handlers.
type AccessControlContext struct {
globPatterns map[string]bool
isAdmin bool
}
func NewAccessController(config *config.Config) *AccessController {
return &AccessController{
Config: config.AccessControl,
@@ -111,14 +102,18 @@ func (ac *AccessController) isAdmin(username string) bool {
// getContext builds ac context(allowed to read repos and if user is admin) and returns it.
func (ac *AccessController) getContext(username string, request *http.Request) context.Context {
readGlobPatterns := ac.getReadGlobPatterns(username)
acCtx := AccessControlContext{globPatterns: readGlobPatterns}
if ac.isAdmin(username) {
acCtx.isAdmin = true
} else {
acCtx.isAdmin = false
acCtx := localCtx.AccessControlContext{
GlobPatterns: readGlobPatterns,
Username: username,
}
if ac.isAdmin(username) {
acCtx.IsAdmin = true
} else {
acCtx.IsAdmin = false
}
authzCtxKey := localCtx.GetContextKey()
ctx := context.WithValue(request.Context(), authzCtxKey, acCtx)
return ctx
@@ -227,6 +222,12 @@ func AuthzHandler(ctlr *Controller) mux.MiddlewareFunc {
return
}
if strings.Contains(request.RequestURI, constants.ExtSearchPrefix) {
next.ServeHTTP(response, request.WithContext(ctx))
return
}
var action string
if request.Method == http.MethodGet || request.Method == http.MethodHead {
action = READ