From 36b4c0df5d92a620c3b162b1033adab7f4683d9e Mon Sep 17 00:00:00 2001 From: Tomas Touceda Date: Wed, 29 Sep 2021 14:07:10 -0300 Subject: [PATCH] Allow team maintainers to read global policies and schedule (#2282) * Allow team maintainers to read global policies and schedules * Update docs --- docs/01-Using-Fleet/09-Permissions.md | 2 + server/authz/policy.rego | 18 +++++ server/service/global_policies_test.go | 4 +- .../service/service_global_schedule_test.go | 69 +++++++++++++++++++ 4 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 server/service/service_global_schedule_test.go diff --git a/docs/01-Using-Fleet/09-Permissions.md b/docs/01-Using-Fleet/09-Permissions.md index 317cd0ffe0..2315c56a6a 100644 --- a/docs/01-Using-Fleet/09-Permissions.md +++ b/docs/01-Using-Fleet/09-Permissions.md @@ -82,3 +82,5 @@ The following table depicts various permissions levels in a team. | Delete hosts belonging to member team | | ✅ | | Edit queries they authored | | ✅ | | Delete queries they authored | | ✅ | +| Browse global policies | | ✅ | +| Browse global schedules | | ✅ | diff --git a/server/authz/policy.rego b/server/authz/policy.rego index 10c38999d4..e9ef5bdaf1 100644 --- a/server/authz/policy.rego +++ b/server/authz/policy.rego @@ -361,6 +361,15 @@ allow { subject.global_role == maintainer action == [read, write][_] } + +# Team maintainers can read global packs +allow { + is_null(object.team_ids) + object.type == "pack" + team_role(subject, subject.teams[_].id) == maintainer + action == read +} + allow { object.team_ids[_] == subject.teams[_].id object.type == "pack" @@ -419,6 +428,15 @@ allow { action == [read, write][_] } +# Team maintainers can read global policies + +allow { + is_null(object.team_id) + object.type == "policy" + team_role(subject, subject.teams[_].id) == maintainer + action == read +} + # Team Observer can read policies allow { not is_null(object.team_id) diff --git a/server/service/global_policies_test.go b/server/service/global_policies_test.go index 284cccb4eb..231c486a4a 100644 --- a/server/service/global_policies_test.go +++ b/server/service/global_policies_test.go @@ -55,10 +55,10 @@ func TestGlobalPoliciesAuth(t *testing.T) { "team maintainer", &fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 1}, Role: fleet.RoleMaintainer}}}, true, - true, + false, }, { - "team observer, belongs to team", + "team observer", &fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 1}, Role: fleet.RoleObserver}}}, true, true, diff --git a/server/service/service_global_schedule_test.go b/server/service/service_global_schedule_test.go new file mode 100644 index 0000000000..f6041cb9db --- /dev/null +++ b/server/service/service_global_schedule_test.go @@ -0,0 +1,69 @@ +package service + +import ( + "context" + "testing" + + "github.com/fleetdm/fleet/v4/server/contexts/viewer" + "github.com/fleetdm/fleet/v4/server/fleet" + "github.com/fleetdm/fleet/v4/server/mock" + "github.com/fleetdm/fleet/v4/server/ptr" +) + +func TestGlobalScheduleAuth(t *testing.T) { + ds := new(mock.Store) + svc := newTestService(ds, nil, nil) + + ds.ListScheduledQueriesInPackFunc = func(ctx context.Context, id uint, opts fleet.ListOptions) ([]*fleet.ScheduledQuery, error) { + return nil, nil + } + ds.EnsureGlobalPackFunc = func(ctx context.Context) (*fleet.Pack, error) { + return &fleet.Pack{}, nil + } + + var testCases = []struct { + name string + user *fleet.User + shouldFailWrite bool + shouldFailRead bool + }{ + { + "global admin", + &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}, + false, + false, + }, + { + "global maintainer", + &fleet.User{GlobalRole: ptr.String(fleet.RoleMaintainer)}, + false, + false, + }, + { + "global observer", + &fleet.User{GlobalRole: ptr.String(fleet.RoleObserver)}, + true, + true, + }, + { + "team maintainer", + &fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 1}, Role: fleet.RoleMaintainer}}}, + true, + false, + }, + { + "team observer", + &fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 1}, Role: fleet.RoleObserver}}}, + true, + true, + }, + } + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + ctx := viewer.NewContext(context.Background(), viewer.Viewer{User: tt.user}) + + _, err := svc.GetGlobalScheduledQueries(ctx, fleet.ListOptions{}) + checkAuthErr(t, tt.shouldFailRead, err) + }) + } +}