diff --git a/auth/auth.go b/auth/auth.go index 8bd545f..a64346e 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -70,19 +70,24 @@ const ( Volumes Subject = "volumes" ) -func (ra RoleAuthorizer) GetWorkspacePermissions(wsp string, usr user.User) (bool, bool, error) { - wss, err := ra.Workspaces.ListWorkspaces(context.TODO(), usr) - if err != nil { - return false, false, errors.Wrap(err, "could not get workspace permissions") - } +type AccessLevel struct { + User bool + Admin bool +} + +func (ra RoleAuthorizer) GetWorkspacePermissions(wsp string, usr user.User) (AccessLevel, error) { + wss := ra.Workspaces.ListWorkspaces() for _, ws := range wss { + var al AccessLevel if ws.Name == wsp { - return ws.UserHasAccess(usr), ws.UserHasAdminAccess(usr), nil + al.User = ws.UserHasAccess(usr) + al.Admin = ws.UserHasAdminAccess(usr) + return al, nil } } - return false, false, nil + return AccessLevel{}, nil } func (ra RoleAuthorizer) GetSecretPermissions(usr user.User, data any) (map[Action]bool, error) { @@ -93,16 +98,16 @@ func (ra RoleAuthorizer) GetSecretPermissions(usr user.User, data any) (map[Acti return map[Action]bool{}, errors.Errorf("could not decode the workspace variable") } - userAccess, adminAccess, err := ra.GetWorkspacePermissions(workspace, usr) + al, err := ra.GetWorkspacePermissions(workspace, usr) if err != nil { return map[Action]bool{}, errors.Wrap(err, "could not get secret permissions") } // this is where access levels map to actions. - p[Read] = userAccess || adminAccess - p[List] = userAccess || adminAccess - p[Write] = adminAccess - p[Delete] = adminAccess + p[Read] = al.User || al.Admin + p[List] = al.User || al.Admin + p[Write] = al.Admin + p[Delete] = al.Admin return p, nil } @@ -115,16 +120,16 @@ func (ra RoleAuthorizer) GetVolumePermissions(usr user.User, data any) (map[Acti return map[Action]bool{}, errors.Errorf("could not decode the workspace variable") } - userAccess, adminAccess, err := ra.GetWorkspacePermissions(workspace, usr) + al, err := ra.GetWorkspacePermissions(workspace, usr) if err != nil { return map[Action]bool{}, errors.Wrap(err, "could not get secret permissions") } // this is where access levels map to actions. - p[Read] = userAccess || adminAccess - p[List] = userAccess || adminAccess - p[Write] = adminAccess - p[Delete] = adminAccess + p[Read] = al.User || al.Admin + p[List] = al.Admin || al.User + p[Write] = al.Admin + p[Delete] = al.Admin return p, nil } diff --git a/e2etest/e2e_test.go b/e2etest/e2e_test.go index b118201..e6a9b9e 100644 --- a/e2etest/e2e_test.go +++ b/e2etest/e2e_test.go @@ -46,32 +46,33 @@ var mockUser fuser.User = fuser.MockUser{ Uid: "0", Name: "Auth Disabled", Email: "auth@disabled", - Roles: []fuser.Role{"tester", "dummy"}, + Roles: []fuser.Role{"tester", "dummy", "sandbox-developer"}, } -var testWorkspace string = ` ---- -# Namespace 'sandbox-project-a' -apiVersion: v1 -kind: Namespace -metadata: - labels: - app.kubernetes.io/part-of: "flowify" - name: "test" - ---- -# Developer workspace environment -apiVersion: v1 -kind: ConfigMap -metadata: - labels: - app.kubernetes.io/component: "workspace-config" - app.kubernetes.io/part-of: "flowify" - name: "test" - namespace: "test" -data: - roles: "[[\"tester\"]]" -` +// TODO: not in use, add clean workspace for e2e tests in k8s +// var testWorkspace string = ` +// --- +// # Namespace 'sandbox-project-a' +// apiVersion: v1 +// kind: Namespace +// metadata: +// labels: +// app.kubernetes.io/part-of: "flowify" +// name: "test" + +// --- +// # Developer workspace environment +// apiVersion: v1 +// kind: ConfigMap +// metadata: +// labels: +// app.kubernetes.io/component: "workspace-config" +// app.kubernetes.io/part-of: "flowify" +// name: "test" +// namespace: "test" +// data: +// roles: "[[\"tester\"]]" +// ` var configString = []byte(` db: @@ -380,7 +381,7 @@ func (s *e2eTestSuite) Test_Roundtrip_Workflow() { resp, err := requestor(server_addr+"/api/v1/workflows/", http.MethodPost, wfReq) s.NoError(err) - require.Equal(s.T(), http.StatusCreated, resp.StatusCode) + require.Equal(s.T(), http.StatusCreated, resp.StatusCode, BodyStringer{resp.Body}) var wfResp models.Workflow err = marshalResponse(ResponseBodyBytes(resp), &wfResp) @@ -445,7 +446,7 @@ func (s *e2eTestSuite) Test_Roundtrip_Job() { resp2, err := requestor(fmt.Sprintf(server_addr+"/api/v1/jobs/%s", wfResp.Metadata.Uid.String()), http.MethodGet, wfReq) s.NoError(err) - var wfResp2 models.Workflow + var wfResp2 models.Job err = marshalResponse(ResponseBodyBytes(resp2), &wfResp2) s.NoError(err) s.Equal(wfResp, wfResp2, "expect roundtrip equality") diff --git a/e2etest/workspace_test.go b/e2etest/workspace_test.go index c8057d1..69fedeb 100644 --- a/e2etest/workspace_test.go +++ b/e2etest/workspace_test.go @@ -15,7 +15,7 @@ func (s *e2eTestSuite) Test_Workspaces() { require.Equal(s.T(), http.StatusOK, resp.StatusCode, BodyStringer{resp.Body}) type WorkspaceList struct { - Items []workspace.Workspace `json:"items"` + Items []workspace.WorkspaceGetRequest `json:"items"` } var list WorkspaceList err = marshalResponse(ResponseBodyBytes(resp), &list) diff --git a/models/examples/minimal-any-workflow.json b/models/examples/minimal-any-workflow.json index d478572..4753787 100644 --- a/models/examples/minimal-any-workflow.json +++ b/models/examples/minimal-any-workflow.json @@ -9,5 +9,5 @@ "type": "any" } }, - "workspace": "test" + "workspace": "sandbox-project-a" } diff --git a/models/spec/workspace.schema.json b/models/spec/workspace.schema.json index 0d73353..3e3cd3d 100644 --- a/models/spec/workspace.schema.json +++ b/models/spec/workspace.schema.json @@ -5,32 +5,21 @@ "description": "The name of the workspace", "type": "string" }, - "hasAccess": { - "description": "Is access granted?", - "type": "boolean" + "description": { + "description": "The description of the workspace", + "type": "string" }, - "missingRoles": { - "description": "The roles a user needs in order to get access.", + "roles": { + "description": "The access roles user has for the workspace (user or admin).", "type": "array", "minItems": 0, "uniqueItems": true, "items": { - "schema": { - "type": "object", - "properties": { - "name": { - "description": "The name of the missing role", - "type": "string" - }, - "description": { - "description": "The description of the missing role", - "type": "string" - } - } - } + "type": "string", + "pattern": "^(user|admin)$" } } }, "additionalProperties": false, - "required": ["name", "hasAccess", "missingRoles"] + "required": ["name", "description", "roles"] } diff --git a/pkg/workspace/workspace.go b/pkg/workspace/workspace.go index d7ac074..f0a2025 100644 --- a/pkg/workspace/workspace.go +++ b/pkg/workspace/workspace.go @@ -1,7 +1,6 @@ package workspace import ( - "context" "encoding/json" "strings" "sync" @@ -36,14 +35,11 @@ type Workspace struct { // the list of required roles for access Roles [][]userpkg.Role `json:"roles,omitempty"` - - HasAccess bool `json:"hasAccess"` - MissingRoles [][]MissingRole `json:"missingRoles,omitempty"` } type WorkspaceClient interface { // list the workspaces visible to a specific user - ListWorkspaces(ctx context.Context, user userpkg.User) ([]Workspace, error) + ListWorkspaces() []Workspace GetNamespace() string } @@ -122,17 +118,6 @@ type MissingRole struct { Description string `json:"description"` } -// queries the access list for a matching access and returns true if found, else false -func HasAccess(ws []Workspace, ns string) bool { - for _, w := range ws { - if w.Name == ns && w.HasAccess { - return true - } - } - - return false -} - func listWorkspaceConfigMaps(namespace string, cmInformer v1.ConfigMapInformer) ([]Workspace, error) { // the lister finds all configmaps in the given namespace with the 'workspace-config' label @@ -271,34 +256,12 @@ func getAccessTokens(cm *core.ConfigMap) ([][]userpkg.Role, error) { } } -func (wimpl *workspaceImpl) ListWorkspaces(ctx context.Context, user userpkg.User) ([]Workspace, error) { - // make a copy of the workspaces - // append only those that have read rights or are not hidden - aws := make([]Workspace, 0, len(wimpl.ws)) - for _, w := range wimpl.ws { - aw := w - // set hasaccess for this particular user - aw.HasAccess = w.UserHasAccess(user) - if aw.HasAccess || !aw.HideForUnauthorized { - - if !aw.HasAccess { - // append the missing roles - missingRoles := [][]MissingRole{} - for _, group := range aw.Roles { - missing := []MissingRole{} - for _, r := range group { - if !userpkg.UserHasRole(user, r) { - missing = append(missing, MissingRole{Name: r, Description: wimpl.roleDescriptions[string(r)]}) - } - } - missingRoles = append(missingRoles, missing) - } - aw.MissingRoles = missingRoles - } - aws = append(aws, aw) - } - } +func (wimpl *workspaceImpl) ListWorkspaces() []Workspace { + return wimpl.ws +} - // return authorized list - return aws, nil +type WorkspaceGetRequest struct { + Name string `json:"name"` + Description string `json:"description"` + Roles []string `json:"roles"` } diff --git a/pkg/workspace/workspace_test.go b/pkg/workspace/workspace_test.go index 7d3e2d3..f417e71 100644 --- a/pkg/workspace/workspace_test.go +++ b/pkg/workspace/workspace_test.go @@ -5,9 +5,7 @@ import ( "encoding/json" "testing" - "github.com/equinor/flowify-workflows-server/auth" "github.com/equinor/flowify-workflows-server/pkg/workspace" - "github.com/equinor/flowify-workflows-server/user" "github.com/stretchr/testify/require" core "k8s.io/api/core/v1" "k8s.io/client-go/kubernetes/fake" @@ -117,32 +115,12 @@ func getClient() workspace.WorkspaceClient { func Test_WorkspaceClientListWorkspaces(t *testing.T) { client := getClient() - ws, err := client.ListWorkspaces(ctx, auth.AzureTokenUser{Roles: []user.Role{"token1", "token4", "token3", "token2"}}) - require.NoError(t, err) + ws := client.ListWorkspaces() // Should return both workspaces require.Len(t, ws, 2) - - ws, err = client.ListWorkspaces(ctx, auth.AzureTokenUser{Roles: []user.Role{"token1", "token2"}}) - require.NoError(t, err) - - // Should return one workspace with no access - require.Len(t, ws, 1) - require.Equal(t, "workspace-xyz", ws[0].Name) - require.Equal(t, false, ws[0].HasAccess) - require.Len(t, ws[0].MissingRoles, 1) - require.Equal(t, user.Role("token4"), ws[0].MissingRoles[0][0].Name) - require.Equal(t, "Only given to the bravest", ws[0].MissingRoles[0][0].Description) - - ws, err = client.ListWorkspaces(ctx, auth.AzureTokenUser{Roles: []user.Role{"token1", "token4"}}) - require.NoError(t, err) - - // Should return one workspace that can be accessed - require.Len(t, ws, 2) - for _, w := range ws { require.Contains(t, []string{"workspace-xyz", "workspace-abc"}, w.Name) - require.Equal(t, true, w.HasAccess) } } @@ -154,16 +132,11 @@ func Test_WorkspaceNoRoleConfigMap(t *testing.T) { client := workspace.NewWorkspaceClient(fake.NewSimpleClientset(&cm1, &cm2), namespace) - ws, err := client.ListWorkspaces(ctx, auth.AzureTokenUser{Roles: []user.Role{"token1", "token2"}}) - require.NoError(t, err) + ws := client.ListWorkspaces() - // Should return one workspace with no access - require.Len(t, ws, 1) - require.Equal(t, "workspace-xyz", ws[0].Name) - require.Equal(t, false, ws[0].HasAccess) - require.Len(t, ws[0].MissingRoles, 1) - require.Equal(t, user.Role("token4"), ws[0].MissingRoles[0][0].Name) - require.Len(t, ws[0].MissingRoles[0][0].Description, 0, "no descriptions for any roles") - - require.Nil(t, err) + // Should return both workspaces + require.Len(t, ws, 2) + for _, w := range ws { + require.Contains(t, []string{"workspace-xyz", "workspace-abc"}, w.Name) + } } diff --git a/rest/components.go b/rest/components.go index 93eb119..32ebc42 100644 --- a/rest/components.go +++ b/rest/components.go @@ -356,8 +356,9 @@ func InitializeMetadata(ctx context.Context, meta *models.Metadata) error { id := models.NewComponentReference() meta.Uid = id TouchMetadata(ctx, meta) + err := meta.Version.InitializeNew() - return nil + return err } func TouchMetadata(ctx context.Context, meta *models.Metadata) { diff --git a/rest/handlers_test.go b/rest/handlers_test.go index 078001c..2ba25c5 100644 --- a/rest/handlers_test.go +++ b/rest/handlers_test.go @@ -46,17 +46,36 @@ var ( wf1, _ = os.ReadFile("../models/examples/minimal-any-workflow.json") wfReq = []byte(fmt.Sprintf(` -{ - "options": {}, - "workflow": %s -}`, wf1)) + { + "options": {}, + "workflow": %s + }`, wf1)) ) +// implement a mock workspace client +type workspaceClient struct { + mock.Mock +} + +func NewMockWorkspaceClient() *workspaceClient { + return &workspaceClient{} +} + // implement a mock client/db for testing type componentClient struct { mock.Mock } +func (c *workspaceClient) ListWorkspaces() []workspace.Workspace { + args := c.Called() + return args.Get(0).([]workspace.Workspace) +} + +func (c *workspaceClient) GetNamespace() string { + args := c.Called() + return args.Get(0).(string) +} + func NewMockClient() *componentClient { return &componentClient{} } @@ -588,19 +607,56 @@ func Test_JobDeleteHandler(t *testing.T) { // Workspace client can be mocked using context injection func Test_WorkspacesHTTPHandler(t *testing.T) { + wss := []workspace.Workspace{ + {Name: "test1", HideForUnauthorized: false, Roles: [][]user.Role{{"test-dev"}}}, + {Name: "test2", HideForUnauthorized: true, Roles: [][]user.Role{{"test-dev"}}}, + {Name: "test3", HideForUnauthorized: false, Roles: [][]user.Role{{"test3"}}}, + } + client := NewMockWorkspaceClient() + client.On("ListWorkspaces").Return(wss) + mux := gmux.NewRouter() + mux.Use(NewAuthorizationContext(client)) RegisterWorkspaceRoutes(mux.PathPrefix("/api/v1")) + accessUser := user.MockUser{Uid: "0", Email: "test@author.com"} type testCase struct { Name string - GivenAccess []workspace.Workspace + UserRoles []user.Role + ExpectedWss []workspace.WorkspaceGetRequest } testcases := []testCase{ - {Name: "list empty workspaces", - GivenAccess: []workspace.Workspace{}}, - {Name: "list workspaces with access", - GivenAccess: []workspace.Workspace{{Name: "test", HasAccess: true, MissingRoles: nil}}}, + { + Name: "list visible workspaces (no access)", + UserRoles: []user.Role{"no-access"}, + ExpectedWss: []workspace.WorkspaceGetRequest{ + {Name: "test1", Roles: []string{}}, {Name: "test3", Roles: []string{}}}, + }, + { + Name: "list workspaces with access test-dev (user only)", + UserRoles: []user.Role{"test-dev"}, + ExpectedWss: []workspace.WorkspaceGetRequest{ + {Name: "test1", Roles: []string{"user"}}, {Name: "test2", Roles: []string{"user"}}, {Name: "test3", Roles: []string{}}}, + }, + { + Name: "list workspaces with access test3-admin", + UserRoles: []user.Role{"test3", "test3-admin"}, + ExpectedWss: []workspace.WorkspaceGetRequest{ + {Name: "test1", Roles: []string{}}, {Name: "test3", Roles: []string{"user", "admin"}}}, + }, + { + Name: "list workspaces with access test-dev test3", + UserRoles: []user.Role{"test-dev", "test3"}, + ExpectedWss: []workspace.WorkspaceGetRequest{ + {Name: "test1", Roles: []string{"user"}}, {Name: "test2", Roles: []string{"user"}}, {Name: "test3", Roles: []string{"user"}}}, + }, + { + Name: "list workspaces with access test-dev-admin test3-admin", + UserRoles: []user.Role{"test-dev", "test-dev-admin", "test3", "test3-admin"}, + ExpectedWss: []workspace.WorkspaceGetRequest{ + {Name: "test1", Roles: []string{"user", "admin"}}, {Name: "test2", Roles: []string{"user", "admin"}}, {Name: "test3", Roles: []string{"user", "admin"}}}, + }, } for _, test := range testcases { @@ -618,7 +674,10 @@ func Test_WorkspacesHTTPHandler(t *testing.T) { request := httptest.NewRequest(http.MethodGet, "/api/v1/workspaces/", nil) // inject test context here ctx := request.Context() - ctx = context.WithValue(ctx, workspace.WorkspaceKey, test.GivenAccess) + usr := accessUser + usr.Roles = test.UserRoles + ctx = context.WithValue(ctx, user.UserKey, usr) + ctx = context.WithValue(ctx, workspace.WorkspaceKey, wss) request = request.WithContext(ctx) w := httptest.NewRecorder() @@ -630,12 +689,12 @@ func Test_WorkspacesHTTPHandler(t *testing.T) { require.NoError(t, err) type WorkspaceAccessList struct { - Items []workspace.Workspace `json:"items"` + Items []workspace.WorkspaceGetRequest `json:"items"` } ac := WorkspaceAccessList{} err = json.Unmarshal(payload, &ac) require.Nil(t, err) - require.Equal(t, test.GivenAccess, ac.Items, string(payload)) + require.Equal(t, test.ExpectedWss, ac.Items) }) } diff --git a/rest/rest.go b/rest/rest.go index b273653..5f06e9d 100644 --- a/rest/rest.go +++ b/rest/rest.go @@ -225,12 +225,17 @@ func NewAuthorizationContext(wsclient workspace.WorkspaceClient) mux.MiddlewareF return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ws, err := wsclient.ListWorkspaces(r.Context(), user.GetUser(r.Context())) - if err != nil { - WriteErrorResponse(w, APIError{http.StatusInternalServerError, "error retrieving component", err.Error()}, "authzmiddleware") - return + wss := wsclient.ListWorkspaces() + usr := user.GetUser(r.Context()) + aws := []workspace.Workspace{} + for _, ws := range wss { + aw := ws + hasAccess := aw.UserHasAccess(usr) + if hasAccess || !aw.HideForUnauthorized { + aws = append(aws, aw) + } } - next.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), workspace.WorkspaceKey, ws))) + next.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), workspace.WorkspaceKey, aws))) }) } } diff --git a/rest/workspaces.go b/rest/workspaces.go index 60e58ac..cde4aef 100644 --- a/rest/workspaces.go +++ b/rest/workspaces.go @@ -4,6 +4,7 @@ import ( "net/http" "github.com/equinor/flowify-workflows-server/pkg/workspace" + "github.com/equinor/flowify-workflows-server/user" "github.com/gorilla/mux" ) @@ -22,10 +23,24 @@ func RegisterWorkspaceRoutes(r *mux.Route) { func WorkspacesListHandler() http.HandlerFunc { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ws := GetWorkspaceAccess(r.Context()) + wss := GetWorkspaceAccess(r.Context()) + lst := []workspace.WorkspaceGetRequest{} + usr := user.GetUser(r.Context()) + for _, ws := range wss { + wsgr := workspace.WorkspaceGetRequest{Name: ws.Name, Description: ws.Description} + roles := []string{} + if ws.UserHasAccess(usr) { + roles = append(roles, "user") + } + if ws.UserHasAdminAccess(usr) { + roles = append(roles, "admin") + } + wsgr.Roles = roles + lst = append(lst, wsgr) + } WriteResponse(w, http.StatusOK, nil, struct { - Items []workspace.Workspace `json:"items"` - }{Items: ws}, "workspace") + Items []workspace.WorkspaceGetRequest `json:"items"` + }{Items: lst}, "workspace") }) } diff --git a/storage/mongo.go b/storage/mongo.go index 75c0d20..cdb0174 100644 --- a/storage/mongo.go +++ b/storage/mongo.go @@ -11,6 +11,7 @@ import ( "github.com/equinor/flowify-workflows-server/models" "github.com/equinor/flowify-workflows-server/pkg/workspace" + "github.com/equinor/flowify-workflows-server/user" "github.com/mitchellh/mapstructure" "github.com/pkg/errors" @@ -365,15 +366,25 @@ func (c *MongoStorageClient) deleteCallback(ctx context.Context, documentKind Do return result, err } -// Some of the db-accessors below require an authenticated context -func GetWorkspaceAccess(ctx context.Context) []workspace.Workspace { +func getWorkspacesFromContext(ctx context.Context) []workspace.Workspace { val := ctx.Value(workspace.WorkspaceKey) - if val == nil { return []workspace.Workspace{} - } else { - return val.([]workspace.Workspace) } + return val.([]workspace.Workspace) +} + +// Some of the db-accessors below require an authenticated context +// TODO: method should be removed and replaced by granularity access control method +func CheckWorkspaceAccess(ctx context.Context, ns string) bool { + // get all 'visible' workspaces + wss := getWorkspacesFromContext(ctx) + for _, w := range wss { + if w.Name == ns { + return w.UserHasAccess(user.GetUser(ctx)) + } + } + return false } func (c *MongoStorageClient) getCRefVersion(ctx context.Context, id interface{}, getter getCollection) (models.CRefVersion, error) { @@ -825,8 +836,8 @@ func (c *MongoStorageClient) ListComponentVersionsMetadata(ctx context.Context, func (c *MongoStorageClient) CreateWorkflow(ctx context.Context, node models.Workflow) error { // make sure we have authz - wsAccess := GetWorkspaceAccess(ctx) - if !workspace.HasAccess(wsAccess, node.Workspace) { + hasWsAccess := CheckWorkspaceAccess(ctx, node.Workspace) + if !hasWsAccess { return fmt.Errorf("user has no access to workspace (%s)", node.Workspace) } @@ -882,9 +893,6 @@ func (c *MongoStorageClient) PatchWorkflow(ctx context.Context, node models.Work } func (c *MongoStorageClient) GetWorkflow(ctx context.Context, id interface{}) (models.Workflow, error) { - // make sure we have authz - wsAccess := GetWorkspaceAccess(ctx) - coll := c.getWorkflowCollection() var result models.Workflow vcref, err := c.getCRefVersion(ctx, id, c.getWorkflowCollection) @@ -904,7 +912,9 @@ func (c *MongoStorageClient) GetWorkflow(ctx context.Context, id interface{}) (m return models.Workflow{}, errors.Wrapf(err, "Error getting workflow {uid: %s, version: %s} from storage", vcref.Uid.String(), vcref.Version.String()) } - if !workspace.HasAccess(wsAccess, result.Workspace) { + // make sure we have authz + hasWsAccess := CheckWorkspaceAccess(ctx, result.Workspace) + if !hasWsAccess { return models.Workflow{}, fmt.Errorf("user has no access to workspace (%s)", result.Workspace) } @@ -947,11 +957,9 @@ func ProjectionFromBsonTags(fields []reflect.StructField) []bson.E { } func createWorkspaceFilter(wsAccesses []workspace.Workspace, wsFieldPath string) bson.D { - ws := make([]string, 0) + ws := []string{} for _, s := range wsAccesses { - if s.HasAccess { - ws = append(ws, s.Name) - } + ws = append(ws, s.Name) } wsFilter := bson.D{{Key: wsFieldPath, Value: bson.D{{Key: "$in", Value: ws}}}} return wsFilter @@ -959,9 +967,15 @@ func createWorkspaceFilter(wsAccesses []workspace.Workspace, wsFieldPath string) func (c *MongoStorageClient) ListWorkflowsMetadata(ctx context.Context, pagination Pagination, filterstrings []string, sorts []string) (models.MetadataWorkspaceList, error) { // make sure we have authz - wsAccess := GetWorkspaceAccess(ctx) + usr := user.GetUser(ctx) + wss := getWorkspacesFromContext(ctx) + wsAccess := []workspace.Workspace{} + for _, ws := range wss { + if ws.UserHasAccess(usr) { + wsAccess = append(wsAccess, ws) + } + } if len(wsAccess) == 0 { - // just an early access every item is secured below return models.MetadataWorkspaceList{}, nil } @@ -1058,16 +1072,15 @@ func (c *MongoStorageClient) ListWorkflowsMetadata(ctx context.Context, paginati } func (c *MongoStorageClient) ListWorkflowVersionsMetadata(ctx context.Context, id models.ComponentReference, pagination Pagination, sorts []string) (models.MetadataWorkspaceList, error) { - // make sure we have authz - wsAccess := GetWorkspaceAccess(ctx) - if len(wsAccess) == 0 { + wss := getWorkspacesFromContext(ctx) + if len(wss) == 0 { // just an early access every item is secured below return models.MetadataWorkspaceList{}, nil } stages := mongo.Pipeline{} - filter := createWorkspaceFilter(wsAccess, "workspace") + filter := createWorkspaceFilter(wss, "workspace") filter = append(filter, bson.E{Key: "uid", Value: id}) matchStage := bson.D{bson.E{Key: "$match", Value: filter}} stages = append(stages, matchStage) @@ -1179,7 +1192,7 @@ func (c *MongoStorageClient) GetJob(ctx context.Context, id models.ComponentRefe return result, errors.Wrapf(err, "Error getting job %s from storage", id) } - if !workspace.HasAccess(GetWorkspaceAccess(ctx), result.Workflow.Workspace) { + if !CheckWorkspaceAccess(ctx, result.Workflow.Workspace) { return models.Job{}, fmt.Errorf("user has no access to workspace (%s)", result.Workflow.Workspace) } @@ -1188,8 +1201,7 @@ func (c *MongoStorageClient) GetJob(ctx context.Context, id models.ComponentRefe func (c *MongoStorageClient) CreateJob(ctx context.Context, node models.Job) error { // make sure we have authz - wsAccess := GetWorkspaceAccess(ctx) - if !workspace.HasAccess(wsAccess, node.Workflow.Workspace) { + if !CheckWorkspaceAccess(ctx, node.Workflow.Workspace) { return fmt.Errorf("user has no access to workspace (%s)", node.Workflow.Workspace) } @@ -1211,7 +1223,14 @@ func (c *MongoStorageClient) CreateJob(ctx context.Context, node models.Job) err func (c *MongoStorageClient) ListJobsMetadata(ctx context.Context, pagination Pagination, filterstrings []string, sorts []string) (models.MetadataWorkspaceList, error) { // make sure we have authz - wsAccess := GetWorkspaceAccess(ctx) + usr := user.GetUser(ctx) + wss := getWorkspacesFromContext(ctx) + wsAccess := []workspace.Workspace{} + for _, ws := range wss { + if ws.UserHasAccess(usr) { + wsAccess = append(wsAccess, ws) + } + } if len(wsAccess) == 0 { // just an early access every item is secured below return models.MetadataWorkspaceList{}, nil diff --git a/storage/mongovolumestorage.go b/storage/mongovolumestorage.go index 5e81f49..96ac44b 100644 --- a/storage/mongovolumestorage.go +++ b/storage/mongovolumestorage.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/equinor/flowify-workflows-server/models" - "github.com/equinor/flowify-workflows-server/pkg/workspace" "github.com/pkg/errors" log "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/bson" @@ -97,12 +96,11 @@ func makeFilterSortPipeline(pagination Pagination, filterstrings []string, sorts } func (c *MongoVolumeClientImpl) ListVolumes(ctx context.Context, pagination Pagination, filterstrings []string, sortstrings []string) (models.FlowifyVolumeList, error) { - // make sure we have authz - wsAccess := GetWorkspaceAccess(ctx) + wss := getWorkspacesFromContext(ctx) stages := mongo.Pipeline{} { - wsstage := bson.D{bson.E{Key: "$match", Value: createWorkspaceFilter(wsAccess, "workspace")}} + wsstage := bson.D{bson.E{Key: "$match", Value: createWorkspaceFilter(wss, "workspace")}} stages = append(stages, wsstage) } @@ -162,7 +160,7 @@ func (c *MongoVolumeClientImpl) GetVolume(ctx context.Context, id models.Compone return models.FlowifyVolume{}, errors.Wrapf(err, "Error getting component %s from storage", id) } - if !workspace.HasAccess(GetWorkspaceAccess(ctx), result.Workspace) { + if !CheckWorkspaceAccess(ctx, result.Workspace) { return models.FlowifyVolume{}, ErrNoAccess } @@ -174,7 +172,7 @@ func (c *MongoVolumeClientImpl) PutVolume(ctx context.Context, vol models.Flowif return fmt.Errorf("uid required") } - if !workspace.HasAccess(GetWorkspaceAccess(ctx), vol.Workspace) { + if !CheckWorkspaceAccess(ctx, vol.Workspace) { return ErrNoAccess } @@ -211,7 +209,7 @@ func (c *MongoVolumeClientImpl) DeleteVolume(ctx context.Context, id models.Comp return errors.Wrap(err, "could not delete volume") } - if !workspace.HasAccess(GetWorkspaceAccess(ctx), vol.Workspace) { + if !CheckWorkspaceAccess(ctx, vol.Workspace) { return ErrNoAccess } diff --git a/storage/storage_test.go b/storage/storage_test.go index 0137ebd..bc03d3c 100644 --- a/storage/storage_test.go +++ b/storage/storage_test.go @@ -11,6 +11,7 @@ import ( "github.com/equinor/flowify-workflows-server/models" "github.com/equinor/flowify-workflows-server/pkg/workspace" "github.com/equinor/flowify-workflows-server/storage" + "github.com/equinor/flowify-workflows-server/user" "github.com/pkg/errors" "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus" @@ -75,7 +76,7 @@ func makeComponent(meta *models.Metadata) models.Component { func makeWorkflow(meta *models.Metadata, workspace string) models.Workflow { if meta == nil { - meta = &models.Metadata{Name: "test-component", + meta = &models.Metadata{Name: "test-workflow", ModifiedBy: models.ModifiedBy{Oid: "0", Email: "test@author.com"}, Timestamp: time.Now().In(time.UTC).Truncate(time.Millisecond), Uid: models.NewComponentReference()} @@ -95,7 +96,7 @@ func makeWorkflow(meta *models.Metadata, workspace string) models.Workflow { func makeJob(meta *models.Metadata, workspace string) models.Job { if meta == nil { - meta = &models.Metadata{Name: "test-component", + meta = &models.Metadata{Name: "test-job", ModifiedBy: models.ModifiedBy{Oid: "0", Email: "test@author.com"}, Timestamp: time.Now().In(time.UTC).Truncate(time.Millisecond), Uid: models.NewComponentReference()} @@ -167,7 +168,16 @@ func TestDeleteDocument(t *testing.T) { mclient.Database(test_db_name).Drop(context.TODO()) ws_test := "ws-test" - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, []workspace.Workspace{{Name: ws_test, HasAccess: true}}) + mockUserAccess := user.MockUser{ + Uid: "0", + Email: "test@author.com", + Roles: []user.Role{"tester"}, + } + mockUserNoAccess := mockUserAccess + mockUserNoAccess.Roles = []user.Role{"dummy"} + userNoAccessCtx := context.WithValue(context.TODO(), user.UserKey, mockUserNoAccess) + userAccessCtx := context.WithValue(context.TODO(), user.UserKey, mockUserAccess) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, []workspace.Workspace{{Name: ws_test, Roles: [][]user.Role{{"tester"}}}}) cmp := makeComponent(nil) { // first add component to get @@ -193,8 +203,8 @@ func TestDeleteDocument(t *testing.T) { assert.Nil(t, err) } - // cmp_v1, err := cstorage.GetComponent(context.TODO(), models.CRefVersion{Uid: cmp.Metadata.Uid, Version: models.VersionInit}) - // assert.Nil(t, err) + _, err = cstorage.GetComponent(context.TODO(), models.CRefVersion{Uid: cmp.Metadata.Uid, Version: models.VersionInit}) + assert.Nil(t, err) cmp_v2, err := cstorage.GetComponent(context.TODO(), models.CRefVersion{Uid: cmp.Metadata.Uid, Version: models.VersionInit + 1}) assert.Nil(t, err) wf_v1, err := cstorage.GetWorkflow(authzCtx, models.CRefVersion{Uid: wf.Metadata.Uid, Version: models.VersionInit}) @@ -219,7 +229,7 @@ func TestDeleteDocument(t *testing.T) { Name: "Delete component, bad uid", Kind: storage.ComponentKind, Id: models.CRefVersion{}, - AuthzContext: context.TODO(), + AuthzContext: authzCtx, ExpectedResult: models.CRefVersion{}, ErrorExpected: true, ExpectedDbDocCount: 2, @@ -228,7 +238,7 @@ func TestDeleteDocument(t *testing.T) { Name: "Delete component v.2", Kind: storage.ComponentKind, Id: models.CRefVersion{Uid: cmp_v2.Uid, Version: cmp_v2.Version.Current}, - AuthzContext: context.TODO(), + AuthzContext: authzCtx, ExpectedResult: models.CRefVersion{Uid: cmp_v2.Uid, Version: cmp_v2.Version.Current}, ErrorExpected: false, ExpectedDbDocCount: 1, @@ -237,7 +247,7 @@ func TestDeleteDocument(t *testing.T) { Name: "Delete workflow, no access", Kind: storage.WorkflowKind, Id: models.CRefVersion{Uid: wf_v1.Uid, Version: wf_v1.Version.Current}, - AuthzContext: context.WithValue(context.TODO(), workspace.WorkspaceKey, []workspace.Workspace{{Name: "test", HasAccess: true}}), + AuthzContext: userNoAccessCtx, ExpectedResult: models.CRefVersion{}, ErrorExpected: true, ExpectedDbDocCount: 2, @@ -273,7 +283,7 @@ func TestDeleteDocument(t *testing.T) { Name: "Delete job, no access", Kind: storage.JobKind, Id: models.CRefVersion{Uid: job.Uid}, - AuthzContext: context.WithValue(context.TODO(), workspace.WorkspaceKey, []workspace.Workspace{{Name: "test", HasAccess: true}}), + AuthzContext: userNoAccessCtx, ExpectedResult: models.CRefVersion{}, ErrorExpected: true, ExpectedDbDocCount: 1, @@ -295,6 +305,7 @@ func TestDeleteDocument(t *testing.T) { if test.ErrorExpected { assert.Error(t, err) } else { + assert.NoError(t, err) assert.Equal(t, test.ExpectedResult, result) } switch test.Kind { @@ -524,29 +535,30 @@ func TestCreateWorkflow(t *testing.T) { ExpectedError error } + userAccessCtx := context.WithValue(context.TODO(), user.UserKey, user.MockUser{Uid: "0", Email: "test@author.com", Roles: []user.Role{"tester"}}) testCases := []testCase{ {Name: "No authz context", WorkspaceAccess: []workspace.Workspace{{}}, Workspace: "test", ExpectedError: fmt.Errorf("user has no access to workspace (%s)", "test")}, {Name: "Good authz context", - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}}, Workspace: "test", ExpectedError: nil}, {Name: "Authz context with name but no access", - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: false}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"dummy"}}}}, Workspace: "test", ExpectedError: fmt.Errorf("user has no access to workspace (%s)", "test")}, {Name: "Authz context with similar name/access", - WorkspaceAccess: []workspace.Workspace{{Name: "tes", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "tes", Roles: [][]user.Role{{"tester"}}}}, Workspace: "test", ExpectedError: fmt.Errorf("user has no access to workspace (%s)", "test")}, {Name: "Authz context with similar name/access", - WorkspaceAccess: []workspace.Workspace{{Name: "test ", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test ", Roles: [][]user.Role{{"tester"}}}}, Workspace: "test", ExpectedError: fmt.Errorf("user has no access to workspace (%s)", "test")}, {Name: "Authz context with subset name/access", - WorkspaceAccess: []workspace.Workspace{{Name: "testt", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "testt", Roles: [][]user.Role{{"tester"}}}}, Workspace: "test", ExpectedError: fmt.Errorf("user has no access to workspace (%s)", "test")}, } @@ -558,10 +570,10 @@ func TestCreateWorkflow(t *testing.T) { t.Run(test.Name, func(t *testing.T) { log.Info("Test: ", test.Name, test.WorkspaceAccess, test.Workspace) - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, test.WorkspaceAccess) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, test.WorkspaceAccess) wf := models.Workflow{Metadata: models.Metadata{Name: test.Name}, Component: makeComponent(nil), Workspace: test.Workspace} err := cstorage.CreateWorkflow(authzCtx, wf) - assert.Equal(t, err, test.ExpectedError) + assert.Equal(t, test.ExpectedError, err) }) } } @@ -574,10 +586,11 @@ func TestGetWorkflow(t *testing.T) { Metadata: models.Metadata{Name: "test-wf", Uid: models.NewComponentReference(), Version: models.Version{Current: models.VersionInit, Tags: []string{"latest"}}}, Component: makeComponent(nil), Workspace: "test"} + userAccessCtx := context.WithValue(context.TODO(), user.UserKey, user.MockUser{Uid: "0", Email: "test@author.com", Roles: []user.Role{"tester"}}) { // create context with access - ws := []workspace.Workspace{{Name: "test", HasAccess: true}} - authCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, ws) + ws := []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}} + authCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, ws) err := cstorage.CreateWorkflow(authCtx, wf) assert.Nil(t, err) } @@ -593,21 +606,21 @@ func TestGetWorkflow(t *testing.T) { WorkspaceAccess: []workspace.Workspace{{}}, ExpectedError: fmt.Errorf("user has no access to workspace (%s)", "test")}, {Name: "Good authz context", - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: nil}, {Name: "Authz context with name but no access", - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: false}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test"}}, ExpectedError: fmt.Errorf("user has no access to workspace (%s)", "test")}, {Name: "Authz context with similar name/access", - WorkspaceAccess: []workspace.Workspace{{Name: "tes", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "tes", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: fmt.Errorf("user has no access to workspace (%s)", "test")}, } for _, test := range testCases { t.Run(test.Name, func(t *testing.T) { - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, test.WorkspaceAccess) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, test.WorkspaceAccess) wf_out, err := cstorage.GetWorkflow(authzCtx, wf.Metadata.Uid) - assert.Equal(t, err, test.ExpectedError) + assert.Equal(t, test.ExpectedError, err) if err == nil { // make sure the roundtrip works when auth is good assert.Equal(t, wf, wf_out) @@ -622,10 +635,11 @@ func TestPutWorkflow(t *testing.T) { wf := models.Workflow{Metadata: models.Metadata{Name: "test-wf", Uid: models.NewComponentReference()}, Component: makeComponent(nil), Workspace: "test"} + userAccessCtx := context.WithValue(context.TODO(), user.UserKey, user.MockUser{Uid: "0", Email: "test@author.com", Roles: []user.Role{"tester"}}) { // create context with access - ws := []workspace.Workspace{{Name: "test", HasAccess: true}} - authCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, ws) + ws := []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}} + authCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, ws) err := cstorage.CreateWorkflow(authCtx, wf) assert.Nil(t, err) } @@ -640,27 +654,27 @@ func TestPutWorkflow(t *testing.T) { testCases := []testCase{ {Name: "No authz context", - WorkspaceAccess: []workspace.Workspace{{}}, + WorkspaceAccess: []workspace.Workspace{{Roles: [][]user.Role{{"tester"}}}}, Workspace: "test", ExpectedFail: true, ExpectedError: errors.Wrap(fmt.Errorf("user has no access to workspace (%s)", "test"), "could not access workflow for storage")}, {Name: "Good authz context", - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}}, Workspace: "test", ExpectedFail: false, ExpectedError: nil}, {Name: "Good authz context, try moving ws", - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}}, Workspace: "test2", ExpectedFail: true, ExpectedError: fmt.Errorf("cannot move workflows from workspace (%s)", "test")}, {Name: "Authz context with name but no access", - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: false}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"dummy"}}}}, Workspace: "test", ExpectedFail: true, ExpectedError: errors.Wrap(fmt.Errorf("user has no access to workspace (%s)", "test"), "could not access workflow for storage")}, {Name: "Authz context with similar name/access", - WorkspaceAccess: []workspace.Workspace{{Name: "tes", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "tes", Roles: [][]user.Role{{"tester"}}}}, Workspace: "test", ExpectedFail: true, ExpectedError: errors.Wrap(fmt.Errorf("user has no access to workspace (%s)", "test"), "could not access workflow for storage")}, @@ -671,7 +685,7 @@ func TestPutWorkflow(t *testing.T) { twf := wf twf.Description = test.Name twf.Workspace = test.Workspace - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, test.WorkspaceAccess) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, test.WorkspaceAccess) err := cstorage.PutWorkflow(authzCtx, twf) if test.ExpectedFail { assert.NotNil(t, err) @@ -687,6 +701,7 @@ func TestListWorkflows(t *testing.T) { cstorage, err := storage.NewMongoStorageClientFromConfig(cfg, mclient) require.NoError(t, err) + userAccessCtx := context.WithValue(context.TODO(), user.UserKey, user.MockUser{Uid: "0", Email: "test@author.com", Roles: []user.Role{"tester"}}) Day := time.Duration(time.Hour * 24) Days := func(i int) time.Duration { return time.Duration(i) * Day } { @@ -695,7 +710,7 @@ func TestListWorkflows(t *testing.T) { // first add components to list for i := 0; i < 5; i++ { - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, []workspace.Workspace{{Name: "test", HasAccess: true}}) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}}) err := cstorage.CreateWorkflow(authzCtx, makeWorkflow(&models.Metadata{Name: fmt.Sprintf("test-%d", i), ModifiedBy: models.ModifiedBy{Oid: "0", Email: "flow@flowify.io"}, Uid: models.NewComponentReference(), @@ -703,7 +718,7 @@ func TestListWorkflows(t *testing.T) { assert.Nil(t, err) } for i := 5; i < 10; i++ { - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, []workspace.Workspace{{Name: "test-2", HasAccess: true}}) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, []workspace.Workspace{{Name: "test-2", Roles: [][]user.Role{{"tester"}}}}) err := cstorage.CreateWorkflow(authzCtx, makeWorkflow(&models.Metadata{Name: fmt.Sprintf("test-%d", i), ModifiedBy: models.ModifiedBy{Oid: "1", Email: "swirl@flowify.io"}, Uid: models.NewComponentReference(), @@ -711,7 +726,7 @@ func TestListWorkflows(t *testing.T) { assert.Nil(t, err) } for i := 10; i < 15; i++ { - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, []workspace.Workspace{{Name: "test-3", HasAccess: true}}) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, []workspace.Workspace{{Name: "test-3", Roles: [][]user.Role{{"tester"}}}}) err := cstorage.CreateWorkflow(authzCtx, makeWorkflow(&models.Metadata{Name: fmt.Sprintf("test-%d", i), ModifiedBy: models.ModifiedBy{Oid: "2", Email: "snow@google.com"}, Uid: models.NewComponentReference(), @@ -742,49 +757,49 @@ func TestListWorkflows(t *testing.T) { {Name: "Everything sorted chronologically ascending", Filters: nil, Sorting: []string{"+timestamp"}, - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}, {Name: "test-2", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}, {Name: "test-2", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: nil, ExpectedSize: 10, ExpectedFrontAuthor: "flow@flowify.io"}, {Name: "Everything sorted chronologically descending", Filters: nil, Sorting: []string{"-timestamp"}, - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}, {Name: "test-2", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}, {Name: "test-2", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: nil, ExpectedSize: 10, ExpectedFrontAuthor: "swirl@flowify.io"}, {Name: "Good authz context but only search for test ws", Filters: []string{"workspace[==]=test"}, Sorting: nil, - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}, {Name: "test-2", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}, {Name: "test-2", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: nil, ExpectedSize: 5, ExpectedFrontAuthor: "flow@flowify.io"}, {Name: "Good authz context (not test-3), regexp for test*, descending", Filters: []string{"workspace[search]=test.*"}, Sorting: []string{"-timestamp"}, - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}, {Name: "test-2", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}, {Name: "test-2", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: nil, ExpectedSize: 10, ExpectedFrontAuthor: "swirl@flowify.io"}, {Name: "Good authz context sort by author", Filters: nil, Sorting: []string{"+modifiedBy"}, - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}, {Name: "test-2", HasAccess: true}, {Name: "test-3", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}, {Name: "test-2", Roles: [][]user.Role{{"tester"}}}, {Name: "test-3", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: nil, ExpectedSize: 15, ExpectedFrontAuthor: "flow@flowify.io"}, {Name: "Authz context with name but no access", Filters: nil, Sorting: nil, - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: false}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"dummy"}}}}, ExpectedError: nil, ExpectedSize: 0, ExpectedFrontAuthor: ""}, {Name: "Authz context with similar name/access", Filters: []string{}, Sorting: nil, - WorkspaceAccess: []workspace.Workspace{{Name: "tes", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "tes", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: nil, ExpectedSize: 0, ExpectedFrontAuthor: "", @@ -793,7 +808,7 @@ func TestListWorkflows(t *testing.T) { for _, test := range testCases { t.Run(test.Name, func(t *testing.T) { - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, test.WorkspaceAccess) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, test.WorkspaceAccess) list, err := cstorage.ListWorkflowsMetadata(authzCtx, storage.Pagination{20, 0}, test.Filters, test.Sorting) assert.Equal(t, err, test.ExpectedError) assert.Equal(t, test.ExpectedSize, len(list.Items)) @@ -809,6 +824,7 @@ func TestListWorkflows(t *testing.T) { // Jobs func TestCreateJob(t *testing.T) { + userAccessCtx := context.WithValue(context.TODO(), user.UserKey, user.MockUser{Uid: "0", Email: "test@author.com", Roles: []user.Role{"tester"}}) type testCase struct { Name string @@ -819,27 +835,27 @@ func TestCreateJob(t *testing.T) { testCases := []testCase{ {Name: "No authz context", - WorkspaceAccess: []workspace.Workspace{{}}, + WorkspaceAccess: []workspace.Workspace{{Roles: [][]user.Role{{"dummy"}}}}, Workspace: "test", ExpectedError: fmt.Errorf("user has no access to workspace (%s)", "test")}, {Name: "Good authz context", - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}}, Workspace: "test", ExpectedError: nil}, {Name: "Authz context with name but no access", - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: false}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"dummy"}}}}, Workspace: "test", ExpectedError: fmt.Errorf("user has no access to workspace (%s)", "test")}, {Name: "Authz context with similar name/access", - WorkspaceAccess: []workspace.Workspace{{Name: "tes", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "tes", Roles: [][]user.Role{{"tester"}}}}, Workspace: "test", ExpectedError: fmt.Errorf("user has no access to workspace (%s)", "test")}, {Name: "Authz context with similar name/access", - WorkspaceAccess: []workspace.Workspace{{Name: "test ", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test ", Roles: [][]user.Role{{"tester"}}}}, Workspace: "test", ExpectedError: fmt.Errorf("user has no access to workspace (%s)", "test")}, {Name: "Authz context with subset name/access", - WorkspaceAccess: []workspace.Workspace{{Name: "testing", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "testing", Roles: [][]user.Role{{"tester"}}}}, Workspace: "test", ExpectedError: fmt.Errorf("user has no access to workspace (%s)", "test")}, } @@ -851,7 +867,7 @@ func TestCreateJob(t *testing.T) { t.Run(test.Name, func(t *testing.T) { log.Info("Test: ", test.Name, test.WorkspaceAccess, test.Workspace) - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, test.WorkspaceAccess) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, test.WorkspaceAccess) job := models.Job{Metadata: models.Metadata{Name: "no uid"}, Workflow: models.Workflow{Metadata: models.Metadata{Name: test.Name}, Component: makeComponent(nil), Workspace: test.Workspace}} err := cstorage.CreateJob(authzCtx, job) assert.Equal(t, test.ExpectedError, err) @@ -862,14 +878,15 @@ func TestCreateJob(t *testing.T) { func TestGetJob(t *testing.T) { cstorage, err := storage.NewMongoStorageClientFromConfig(cfg, mclient) require.NoError(t, err) + userAccessCtx := context.WithValue(context.TODO(), user.UserKey, user.MockUser{Uid: "0", Email: "test@author.com", Roles: []user.Role{"tester"}}) id := models.NewComponentReference() name := "test-job-" + id.String()[:4] job := models.Job{Metadata: models.Metadata{Name: name, Uid: id}, Workflow: models.Workflow{Metadata: models.Metadata{Name: "test-wf", Uid: models.NewComponentReference()}, Component: makeComponent(nil), Workspace: "test"}} { // create context with access - ws := []workspace.Workspace{{Name: "test", HasAccess: true}} - authCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, ws) + ws := []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}} + authCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, ws) err := cstorage.CreateJob(authCtx, job) assert.Nil(t, err) } @@ -885,19 +902,19 @@ func TestGetJob(t *testing.T) { WorkspaceAccess: []workspace.Workspace{{}}, ExpectedError: fmt.Errorf("user has no access to workspace (%s)", "test")}, {Name: "Good authz context", - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: nil}, {Name: "Authz context with name but no access", - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: false}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"dummy"}}}}, ExpectedError: fmt.Errorf("user has no access to workspace (%s)", "test")}, {Name: "Authz context with similar name/access", - WorkspaceAccess: []workspace.Workspace{{Name: "tes", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "tes", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: fmt.Errorf("user has no access to workspace (%s)", "test")}, } for _, test := range testCases { t.Run(test.Name, func(t *testing.T) { - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, test.WorkspaceAccess) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, test.WorkspaceAccess) job_out, err := cstorage.GetJob(authzCtx, job.Metadata.Uid) assert.Equal(t, err, test.ExpectedError) if err == nil { @@ -911,6 +928,7 @@ func TestGetJob(t *testing.T) { func TestListJobs(t *testing.T) { cstorage, err := storage.NewMongoStorageClientFromConfig(cfg, mclient) require.NoError(t, err) + userAccessCtx := context.WithValue(context.TODO(), user.UserKey, user.MockUser{Uid: "0", Email: "test@author.com", Roles: []user.Role{"tester"}}) Day := time.Duration(time.Hour * 24) Days := func(i int) time.Duration { return time.Duration(i) * Day } @@ -920,7 +938,7 @@ func TestListJobs(t *testing.T) { // first add components to list for i := 0; i < 5; i++ { - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, []workspace.Workspace{{Name: "test", HasAccess: true}}) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}}) err := cstorage.CreateJob(authzCtx, makeJob(&models.Metadata{Name: fmt.Sprintf("test-%d", i), ModifiedBy: models.ModifiedBy{Oid: "0", Email: "flow@flowify.io"}, Uid: models.NewComponentReference(), @@ -928,7 +946,7 @@ func TestListJobs(t *testing.T) { assert.Nil(t, err) } for i := 5; i < 10; i++ { - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, []workspace.Workspace{{Name: "test-2", HasAccess: true}}) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, []workspace.Workspace{{Name: "test-2", Roles: [][]user.Role{{"tester"}}}}) err := cstorage.CreateJob(authzCtx, makeJob(&models.Metadata{Name: fmt.Sprintf("test-%d", i), ModifiedBy: models.ModifiedBy{Oid: "1", Email: "swirl@flowify.io"}, Uid: models.NewComponentReference(), @@ -936,7 +954,7 @@ func TestListJobs(t *testing.T) { assert.Nil(t, err) } for i := 10; i < 15; i++ { - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, []workspace.Workspace{{Name: "test-3", HasAccess: true}}) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, []workspace.Workspace{{Name: "test-3", Roles: [][]user.Role{{"tester"}}}}) err := cstorage.CreateJob(authzCtx, makeJob(&models.Metadata{Name: fmt.Sprintf("test-%d", i), ModifiedBy: models.ModifiedBy{Oid: "0", Email: "snow@google.com"}, Uid: models.NewComponentReference(), @@ -968,42 +986,42 @@ func TestListJobs(t *testing.T) { Filters: nil, Sorting: nil, Pagination: storage.Pagination{10, 0}, - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: nil, ExpectedSize: 5}, {Name: "All authz contexts", Filters: nil, Sorting: nil, Pagination: storage.Pagination{20, 0}, - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}, {Name: "test-2", HasAccess: true}, {Name: "test-3", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}, {Name: "test-2", Roles: [][]user.Role{{"tester"}}}, {Name: "test-3", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: nil, ExpectedSize: 15}, {Name: "All authz contexts, offset", Filters: nil, Sorting: nil, Pagination: storage.Pagination{10, 5}, - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}, {Name: "test-2", HasAccess: true}, {Name: "test-3", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}, {Name: "test-2", Roles: [][]user.Role{{"tester"}}}, {Name: "test-3", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: nil, ExpectedSize: 10}, {Name: "Good authz context and filter", Filters: []string{"workflow.workspace[==]=test-2"}, Sorting: nil, Pagination: storage.Pagination{10, 0}, - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}, {Name: "test-2", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}, {Name: "test-2", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: nil, ExpectedSize: 5}, {Name: "Authz context with name but no access", Filters: nil, Sorting: nil, Pagination: storage.Pagination{10, 0}, - WorkspaceAccess: []workspace.Workspace{{Name: "test-2", HasAccess: false}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test-2", Roles: [][]user.Role{{"dummy"}}}}, ExpectedError: nil, ExpectedSize: 0}, {Name: "Authz context with similar name/access", Filters: []string{}, Sorting: nil, Pagination: storage.Pagination{10, 0}, - WorkspaceAccess: []workspace.Workspace{{Name: "tes", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "tes", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: nil, ExpectedSize: 0, }, @@ -1012,13 +1030,13 @@ func TestListJobs(t *testing.T) { for _, test := range testCases { t.Run(test.Name, func(t *testing.T) { log.Info("Test: ", test.Name, test.WorkspaceAccess, test.ExpectedError) - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, test.WorkspaceAccess) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, test.WorkspaceAccess) metaList, err := cstorage.ListJobsMetadata(authzCtx, test.Pagination, test.Filters, test.Sorting) assert.Equal(t, err, test.ExpectedError) assert.Equal(t, test.ExpectedSize, len(metaList.Items)) assert.GreaterOrEqual(t, metaList.PageInfo.TotalNumber, test.ExpectedSize, test.Name) for _, j := range metaList.Items { - assert.Contains(t, test.WorkspaceAccess, workspace.Workspace{Name: j.Workspace, HasAccess: true}) + assert.Contains(t, test.WorkspaceAccess, workspace.Workspace{Name: j.Workspace, Roles: [][]user.Role{{"tester"}}}) } }) } diff --git a/storage/volumestorage_test.go b/storage/volumestorage_test.go index 56cca2e..e4d583d 100644 --- a/storage/volumestorage_test.go +++ b/storage/volumestorage_test.go @@ -8,6 +8,7 @@ import ( "github.com/equinor/flowify-workflows-server/models" "github.com/equinor/flowify-workflows-server/pkg/workspace" "github.com/equinor/flowify-workflows-server/storage" + "github.com/equinor/flowify-workflows-server/user" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" @@ -16,6 +17,9 @@ import ( func TestDeleteVolume(t *testing.T) { c, err := storage.NewMongoVolumeClientFromConfig(cfg, mclient) require.NoError(t, err) + userAccessCtx := context.WithValue(context.TODO(), user.UserKey, user.MockUser{Uid: "0", Email: "test@author.com", Roles: []user.Role{"tester"}}) + ws := []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}} + authCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, ws) vol := models.FlowifyVolume{ Workspace: "test", @@ -24,15 +28,11 @@ func TestDeleteVolume(t *testing.T) { { // first add component to get // create context with access - ws := []workspace.Workspace{{Name: "test", HasAccess: true}} - authCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, ws) err := c.PutVolume(authCtx, vol) assert.Nil(t, err) } { - ws := []workspace.Workspace{{Name: "test", HasAccess: true}} - authCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, ws) vol_out, err := c.GetVolume(authCtx, vol.Uid) assert.Nil(t, err) assert.Equal(t, vol, vol_out) @@ -48,8 +48,8 @@ func TestDeleteVolume(t *testing.T) { assert.ErrorContains(t, err, storage.ErrNoAccess.Error()) // get access - ws := []workspace.Workspace{{Name: vol.Workspace, HasAccess: true}} - authCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, ws) + ws := []workspace.Workspace{{Name: vol.Workspace, Roles: [][]user.Role{{"tester"}}}} + authCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, ws) err = c.DeleteVolume(authCtx, vol.Uid) assert.Nil(t, err) @@ -67,6 +67,7 @@ func TestDeleteVolume(t *testing.T) { func TestGetVolume(t *testing.T) { c, err := storage.NewMongoVolumeClientFromConfig(cfg, mclient) require.NoError(t, err) + userAccessCtx := context.WithValue(context.TODO(), user.UserKey, user.MockUser{Uid: "0", Email: "test@author.com", Roles: []user.Role{"tester"}}) vol := models.FlowifyVolume{ Workspace: "test", @@ -75,8 +76,8 @@ func TestGetVolume(t *testing.T) { { // create context with access - ws := []workspace.Workspace{{Name: "test", HasAccess: true}} - authCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, ws) + ws := []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}} + authCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, ws) err := c.PutVolume(authCtx, vol) assert.Nil(t, err) } @@ -95,25 +96,25 @@ func TestGetVolume(t *testing.T) { ExpectedError: storage.ErrNoAccess}, {Name: "Good authz context", CRef: vol.Uid, - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: nil}, {Name: "Good authz context, bad ref", CRef: models.NewComponentReference(), - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: storage.ErrNotFound}, {Name: "Authz context with name but no access", CRef: vol.Uid, - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: false}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"dummy"}}}}, ExpectedError: storage.ErrNoAccess}, {Name: "Authz context with similar name/access", CRef: vol.Uid, - WorkspaceAccess: []workspace.Workspace{{Name: "tes", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "tes", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: storage.ErrNoAccess}, } for _, test := range testCases { t.Run(test.Name, func(t *testing.T) { - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, test.WorkspaceAccess) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, test.WorkspaceAccess) vol_out, err := c.GetVolume(authzCtx, test.CRef) assert.Equal(t, err, test.ExpectedError) if err == nil { @@ -127,6 +128,7 @@ func TestGetVolume(t *testing.T) { func TestPutVolume(t *testing.T) { c, err := storage.NewMongoVolumeClientFromConfig(cfg, mclient) require.NoError(t, err) + userAccessCtx := context.WithValue(context.TODO(), user.UserKey, user.MockUser{Uid: "0", Email: "test@author.com", Roles: []user.Role{"tester"}}) vol := models.FlowifyVolume{ Workspace: "test", @@ -134,8 +136,8 @@ func TestPutVolume(t *testing.T) { Volume: corev1.Volume{Name: "test1-for-overwrite"}} { // create context with access - ws := []workspace.Workspace{{Name: "test", HasAccess: true}} - authCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, ws) + ws := []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}} + authCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, ws) err := c.PutVolume(authCtx, vol) assert.Nil(t, err) } @@ -157,37 +159,37 @@ func TestPutVolume(t *testing.T) { ExpectedFail: true, ExpectedError: storage.ErrNoAccess}, {Name: "No authz context (explicit)", - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: false}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"dummy"}}}}, CRef: vol.Uid, Workspace: "test", ExpectedFail: true, ExpectedError: storage.ErrNoAccess}, {Name: "Good authz context", - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}}, CRef: vol.Uid, Workspace: "test", ExpectedFail: false, ExpectedError: nil}, {Name: "Good authz context, try moving to unauth ws", - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}}, CRef: vol.Uid, Workspace: "test2", ExpectedFail: true, ExpectedError: storage.ErrNoAccess}, {Name: "Good authz context, try moving to new ws", - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: true}, {Name: "test2", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"tester"}}}, {Name: "test2", Roles: [][]user.Role{{"tester"}}}}, CRef: vol.Uid, Workspace: "test2", ExpectedFail: false, ExpectedError: nil}, {Name: "Authz context with name but no access", - WorkspaceAccess: []workspace.Workspace{{Name: "test", HasAccess: false}}, + WorkspaceAccess: []workspace.Workspace{{Name: "test", Roles: [][]user.Role{{"dummy"}}}}, CRef: vol.Uid, Workspace: "test", ExpectedFail: true, ExpectedError: storage.ErrNoAccess}, {Name: "Authz context with similar name/access", - WorkspaceAccess: []workspace.Workspace{{Name: "tes", HasAccess: true}}, + WorkspaceAccess: []workspace.Workspace{{Name: "tes", Roles: [][]user.Role{{"tester"}}}}, CRef: vol.Uid, Workspace: "test", ExpectedFail: true, @@ -199,7 +201,7 @@ func TestPutVolume(t *testing.T) { tVol := vol tVol.Workspace = test.Workspace tVol.Uid = test.CRef - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, test.WorkspaceAccess) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, test.WorkspaceAccess) err := c.PutVolume(authzCtx, tVol) if test.ExpectedFail { assert.NotNil(t, err) @@ -214,6 +216,7 @@ func TestPutVolume(t *testing.T) { func TestListVolumes(t *testing.T) { c, err := storage.NewMongoVolumeClientFromConfig(cfg, mclient) require.NoError(t, err) + userAccessCtx := context.WithValue(context.TODO(), user.UserKey, user.MockUser{Uid: "0", Email: "test@author.com", Roles: []user.Role{"tester"}}) { // drop db to make sure that at the end DB will contain one components @@ -221,7 +224,7 @@ func TestListVolumes(t *testing.T) { // first add components to list for i := 0; i < 5; i++ { - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, []workspace.Workspace{{Name: "ws-1", HasAccess: true}}) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, []workspace.Workspace{{Name: "ws-1", Roles: [][]user.Role{{"tester"}}}}) err := c.PutVolume(authzCtx, models.FlowifyVolume{ Uid: models.NewComponentReference(), @@ -230,7 +233,7 @@ func TestListVolumes(t *testing.T) { assert.Nil(t, err) } for i := 5; i < 10; i++ { - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, []workspace.Workspace{{Name: "ws-2", HasAccess: true}}) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, []workspace.Workspace{{Name: "ws-2", Roles: [][]user.Role{{"tester"}}}}) err := c.PutVolume(authzCtx, models.FlowifyVolume{ Uid: models.NewComponentReference(), @@ -239,7 +242,7 @@ func TestListVolumes(t *testing.T) { assert.Nil(t, err) } for i := 10; i < 15; i++ { - authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, []workspace.Workspace{{Name: "ws-3", HasAccess: true}}) + authzCtx := context.WithValue(userAccessCtx, workspace.WorkspaceKey, []workspace.Workspace{{Name: "ws-3", Roles: [][]user.Role{{"tester"}}}}) err := c.PutVolume(authzCtx, models.FlowifyVolume{ Uid: models.NewComponentReference(), @@ -271,9 +274,9 @@ func TestListVolumes(t *testing.T) { Filters: nil, Sorting: nil, WorkspaceAccess: []workspace.Workspace{ - {Name: "ws-1", HasAccess: true}, - {Name: "ws-2", HasAccess: true}, - {Name: "ws-3", HasAccess: true}}, + {Name: "ws-1", Roles: [][]user.Role{{"tester"}}}, + {Name: "ws-2", Roles: [][]user.Role{{"tester"}}}, + {Name: "ws-3", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: nil, ExpectedSize: 15, }, @@ -281,9 +284,9 @@ func TestListVolumes(t *testing.T) { Filters: []string{"workspace[==]=ws-2"}, Sorting: nil, WorkspaceAccess: []workspace.Workspace{ - {Name: "ws-1", HasAccess: true}, - {Name: "ws-2", HasAccess: true}, - {Name: "ws-3", HasAccess: true}}, + {Name: "ws-1", Roles: [][]user.Role{{"tester"}}}, + {Name: "ws-2", Roles: [][]user.Role{{"tester"}}}, + {Name: "ws-3", Roles: [][]user.Role{{"tester"}}}}, ExpectedError: nil, ExpectedSize: 5, }, @@ -291,7 +294,7 @@ func TestListVolumes(t *testing.T) { Filters: nil, Sorting: nil, WorkspaceAccess: []workspace.Workspace{ - {Name: "ws-2", HasAccess: true}, + {Name: "ws-2", Roles: [][]user.Role{{"tester"}}}, }, ExpectedError: nil, ExpectedSize: 5, @@ -303,8 +306,6 @@ func TestListVolumes(t *testing.T) { authzCtx := context.WithValue(context.TODO(), workspace.WorkspaceKey, test.WorkspaceAccess) list, err := c.ListVolumes(authzCtx, storage.Pagination{20, 0}, test.Filters, test.Sorting) assert.Equal(t, err, test.ExpectedError) - if err == nil { - } assert.Equal(t, test.ExpectedSize, len(list.Items)) assert.Equal(t, test.ExpectedSize, list.PageInfo.TotalNumber)