mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
411 lines
18 KiB
Go
411 lines
18 KiB
Go
package accesscontrol
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
|
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
|
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
|
"github.com/grafana/grafana/pkg/services/org"
|
|
)
|
|
|
|
func TestReceiverAccess(t *testing.T) {
|
|
recv1 := models.ReceiverGen(models.ReceiverMuts.WithName("test receiver 1"), models.ReceiverMuts.WithValidIntegration("slack"))()
|
|
recv2 := models.ReceiverGen(models.ReceiverMuts.WithName("test receiver 2"), models.ReceiverMuts.WithValidIntegration("email"))()
|
|
recv3 := models.ReceiverGen(models.ReceiverMuts.WithName("test receiver 3"), models.ReceiverMuts.WithValidIntegration("webhook"))()
|
|
|
|
allReceivers := []*models.Receiver{
|
|
&recv1,
|
|
&recv2,
|
|
&recv3,
|
|
}
|
|
|
|
permissions := func(perms ...models.ReceiverPermission) models.ReceiverPermissionSet {
|
|
set := models.NewReceiverPermissionSet()
|
|
for _, v := range models.ReceiverPermissions() {
|
|
set.Set(v, false)
|
|
}
|
|
for _, v := range perms {
|
|
set.Set(v, true)
|
|
}
|
|
return set
|
|
}
|
|
|
|
testCases := []struct {
|
|
name string
|
|
user identity.Requester
|
|
expected map[string]models.ReceiverPermissionSet
|
|
expectedWithProvisioning map[string]models.ReceiverPermissionSet
|
|
}{
|
|
// Legacy read.
|
|
{
|
|
name: "legacy global reader should have no elevated permissions",
|
|
user: newEmptyUser(ac.Permission{Action: ac.ActionAlertingNotificationsRead}),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(),
|
|
recv2.UID: permissions(),
|
|
recv3.UID: permissions(),
|
|
},
|
|
},
|
|
{
|
|
name: "legacy global notifications provisioning reader should have no elevated permissions",
|
|
user: newEmptyUser(ac.Permission{Action: ac.ActionAlertingNotificationsProvisioningRead}),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(),
|
|
recv2.UID: permissions(),
|
|
recv3.UID: permissions(),
|
|
},
|
|
},
|
|
{
|
|
name: "legacy global provisioning reader should have no elevated permissions",
|
|
user: newEmptyUser(ac.Permission{Action: ac.ActionAlertingProvisioningRead}),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(),
|
|
recv2.UID: permissions(),
|
|
recv3.UID: permissions(),
|
|
},
|
|
},
|
|
{
|
|
name: "legacy global provisioning secret reader should have secret permissions on provisioning only",
|
|
user: newEmptyUser(ac.Permission{Action: ac.ActionAlertingProvisioningReadSecrets}),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(),
|
|
recv2.UID: permissions(),
|
|
recv3.UID: permissions(),
|
|
},
|
|
expectedWithProvisioning: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(models.ReceiverPermissionReadSecret),
|
|
recv2.UID: permissions(models.ReceiverPermissionReadSecret),
|
|
recv3.UID: permissions(models.ReceiverPermissionReadSecret),
|
|
},
|
|
},
|
|
// Receiver read.
|
|
{
|
|
name: "global receiver reader should have no elevated permissions",
|
|
user: newEmptyUser(ac.Permission{Action: ac.ActionAlertingReceiversRead, Scope: ScopeReceiversAll}),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(),
|
|
recv2.UID: permissions(),
|
|
recv3.UID: permissions(),
|
|
},
|
|
},
|
|
{
|
|
name: "global receiver secret reader should have secret permissions",
|
|
user: newEmptyUser(ac.Permission{Action: ac.ActionAlertingReceiversReadSecrets, Scope: ScopeReceiversAll}),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(models.ReceiverPermissionReadSecret),
|
|
recv2.UID: permissions(models.ReceiverPermissionReadSecret),
|
|
recv3.UID: permissions(models.ReceiverPermissionReadSecret),
|
|
},
|
|
},
|
|
{
|
|
name: "per-receiver secret reader should have per-receiver",
|
|
user: newEmptyUser(
|
|
ac.Permission{Action: ac.ActionAlertingReceiversReadSecrets, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversReadSecrets, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv3.UID)},
|
|
),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(models.ReceiverPermissionReadSecret),
|
|
recv2.UID: permissions(),
|
|
recv3.UID: permissions(models.ReceiverPermissionReadSecret),
|
|
},
|
|
},
|
|
// Legacy write.
|
|
{
|
|
name: "legacy global writer should have full write",
|
|
user: newViewUser(ac.Permission{Action: ac.ActionAlertingNotificationsWrite}),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(models.ReceiverPermissionWrite, models.ReceiverPermissionDelete),
|
|
recv2.UID: permissions(models.ReceiverPermissionWrite, models.ReceiverPermissionDelete),
|
|
recv3.UID: permissions(models.ReceiverPermissionWrite, models.ReceiverPermissionDelete),
|
|
},
|
|
},
|
|
{
|
|
name: "legacy writers should require read",
|
|
user: newEmptyUser(ac.Permission{Action: ac.ActionAlertingNotificationsWrite}),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(),
|
|
recv2.UID: permissions(),
|
|
recv3.UID: permissions(),
|
|
},
|
|
},
|
|
//{
|
|
// name: "legacy global notifications provisioning writer should have full write on provisioning only",
|
|
// user: newViewUser(ac.Permission{Action: ac.ActionAlertingNotificationsProvisioningWrite}),
|
|
// expected: map[string]models.ReceiverPermissionSet{
|
|
// recv1.UID: permissions(),
|
|
// recv2.UID: permissions(),
|
|
// recv3.UID: permissions(),
|
|
// },
|
|
// expectedWithProvisioning: map[string]models.ReceiverPermissionSet{
|
|
// recv1.UID: permissions(models.ReceiverPermissionWrite, models.ReceiverPermissionDelete),
|
|
// recv2.UID: permissions(models.ReceiverPermissionWrite, models.ReceiverPermissionDelete),
|
|
// recv3.UID: permissions(models.ReceiverPermissionWrite, models.ReceiverPermissionDelete),
|
|
// },
|
|
//},
|
|
//{
|
|
// name: "legacy global provisioning writer should have full write on provisioning only",
|
|
// user: newViewUser(ac.Permission{Action: ac.ActionAlertingProvisioningWrite}),
|
|
// expected: map[string]models.ReceiverPermissionSet{
|
|
// recv1.UID: permissions(),
|
|
// recv2.UID: permissions(),
|
|
// recv3.UID: permissions(),
|
|
// },
|
|
// expectedWithProvisioning: map[string]models.ReceiverPermissionSet{
|
|
// recv1.UID: permissions(models.ReceiverPermissionWrite, models.ReceiverPermissionDelete),
|
|
// recv2.UID: permissions(models.ReceiverPermissionWrite, models.ReceiverPermissionDelete),
|
|
// recv3.UID: permissions(models.ReceiverPermissionWrite, models.ReceiverPermissionDelete),
|
|
// },
|
|
//},
|
|
// Receiver create
|
|
{
|
|
name: "receiver create should not have write",
|
|
user: newEmptyUser(ac.Permission{Action: ac.ActionAlertingReceiversCreate}),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(),
|
|
recv2.UID: permissions(),
|
|
recv3.UID: permissions(),
|
|
},
|
|
},
|
|
// Receiver update.
|
|
{
|
|
name: "global receiver update should have write but no delete",
|
|
user: newViewUser(ac.Permission{Action: ac.ActionAlertingReceiversUpdate, Scope: ScopeReceiversAll}),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(models.ReceiverPermissionWrite),
|
|
recv2.UID: permissions(models.ReceiverPermissionWrite),
|
|
recv3.UID: permissions(models.ReceiverPermissionWrite),
|
|
},
|
|
},
|
|
{
|
|
name: "per-receiver update should have per-receiver write but no delete",
|
|
user: newViewUser(
|
|
ac.Permission{Action: ac.ActionAlertingReceiversUpdate, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversUpdate, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv3.UID)},
|
|
),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(models.ReceiverPermissionWrite),
|
|
recv2.UID: permissions(),
|
|
recv3.UID: permissions(models.ReceiverPermissionWrite),
|
|
},
|
|
},
|
|
{
|
|
name: "per-receiver update should require read",
|
|
user: newEmptyUser(
|
|
ac.Permission{Action: ac.ActionAlertingReceiversUpdate, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversUpdate, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv3.UID)},
|
|
),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(),
|
|
recv2.UID: permissions(),
|
|
recv3.UID: permissions(),
|
|
},
|
|
},
|
|
// Receiver delete.
|
|
{
|
|
name: "global receiver delete should have delete but no write",
|
|
user: newViewUser(ac.Permission{Action: ac.ActionAlertingReceiversDelete, Scope: ScopeReceiversAll}),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(models.ReceiverPermissionDelete),
|
|
recv2.UID: permissions(models.ReceiverPermissionDelete),
|
|
recv3.UID: permissions(models.ReceiverPermissionDelete),
|
|
},
|
|
},
|
|
{
|
|
name: "per-receiver delete should have per-receiver delete but no write",
|
|
user: newViewUser(
|
|
ac.Permission{Action: ac.ActionAlertingReceiversDelete, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversDelete, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv3.UID)},
|
|
),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(models.ReceiverPermissionDelete),
|
|
recv2.UID: permissions(),
|
|
recv3.UID: permissions(models.ReceiverPermissionDelete),
|
|
},
|
|
},
|
|
{
|
|
name: "per-receiver delete should require read",
|
|
user: newEmptyUser(
|
|
ac.Permission{Action: ac.ActionAlertingReceiversDelete, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversDelete, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv3.UID)},
|
|
),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(),
|
|
recv2.UID: permissions(),
|
|
recv3.UID: permissions(),
|
|
},
|
|
},
|
|
// Receiver admin.
|
|
{
|
|
name: "receiver read permissions alone can't admin",
|
|
user: newViewUser(ac.Permission{Action: ac.ActionAlertingReceiversPermissionsRead, Scope: ScopeReceiversAll}),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(),
|
|
recv2.UID: permissions(),
|
|
recv3.UID: permissions(),
|
|
},
|
|
},
|
|
{
|
|
name: "receiver write permissions alone can't admin",
|
|
user: newViewUser(ac.Permission{Action: ac.ActionAlertingReceiversPermissionsWrite, Scope: ScopeReceiversAll}),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(),
|
|
recv2.UID: permissions(),
|
|
recv3.UID: permissions(),
|
|
},
|
|
},
|
|
{
|
|
name: "global receiver read + write permissions can admin",
|
|
user: newViewUser(
|
|
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsRead, Scope: ScopeReceiversAll},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsWrite, Scope: ScopeReceiversAll},
|
|
),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(models.ReceiverPermissionAdmin),
|
|
recv2.UID: permissions(models.ReceiverPermissionAdmin),
|
|
recv3.UID: permissions(models.ReceiverPermissionAdmin),
|
|
},
|
|
},
|
|
{
|
|
name: "per-receiver read + write permissions should have per-receiver admin",
|
|
user: newViewUser(
|
|
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsRead, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsWrite, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsRead, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv3.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsWrite, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv3.UID)},
|
|
),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(models.ReceiverPermissionAdmin),
|
|
recv2.UID: permissions(),
|
|
recv3.UID: permissions(models.ReceiverPermissionAdmin),
|
|
},
|
|
},
|
|
{
|
|
name: "per-receiver admin should require read",
|
|
user: newEmptyUser(
|
|
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsRead, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsWrite, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsRead, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv3.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversPermissionsWrite, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv3.UID)},
|
|
),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(),
|
|
recv2.UID: permissions(),
|
|
recv3.UID: permissions(),
|
|
},
|
|
},
|
|
// Mixed permissions.
|
|
{
|
|
name: "legacy provisioning secret read, receiver write",
|
|
user: newViewUser(
|
|
ac.Permission{Action: ac.ActionAlertingProvisioningReadSecrets},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversUpdate, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv2.UID)},
|
|
),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(),
|
|
recv2.UID: permissions(models.ReceiverPermissionWrite),
|
|
recv3.UID: permissions(),
|
|
},
|
|
expectedWithProvisioning: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(models.ReceiverPermissionReadSecret),
|
|
recv2.UID: permissions(models.ReceiverPermissionReadSecret, models.ReceiverPermissionWrite),
|
|
recv3.UID: permissions(models.ReceiverPermissionReadSecret),
|
|
},
|
|
},
|
|
{
|
|
name: "legacy provisioning secret read, receiver delete",
|
|
user: newViewUser(
|
|
ac.Permission{Action: ac.ActionAlertingProvisioningReadSecrets},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversDelete, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv2.UID)},
|
|
),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(),
|
|
recv2.UID: permissions(models.ReceiverPermissionDelete),
|
|
recv3.UID: permissions(),
|
|
},
|
|
expectedWithProvisioning: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(models.ReceiverPermissionReadSecret),
|
|
recv2.UID: permissions(models.ReceiverPermissionReadSecret, models.ReceiverPermissionDelete),
|
|
recv3.UID: permissions(models.ReceiverPermissionReadSecret),
|
|
},
|
|
},
|
|
{
|
|
name: "legacy write, receiver secret",
|
|
user: newViewUser(
|
|
ac.Permission{Action: ac.ActionAlertingNotificationsWrite},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversReadSecrets, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv2.UID)},
|
|
),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(models.ReceiverPermissionWrite, models.ReceiverPermissionDelete),
|
|
recv2.UID: permissions(models.ReceiverPermissionReadSecret, models.ReceiverPermissionWrite, models.ReceiverPermissionDelete),
|
|
recv3.UID: permissions(models.ReceiverPermissionWrite, models.ReceiverPermissionDelete),
|
|
},
|
|
},
|
|
{
|
|
name: "mixed secret / delete / write",
|
|
user: newViewUser(
|
|
ac.Permission{Action: ac.ActionAlertingReceiversReadSecrets, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversReadSecrets, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv3.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversUpdate, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversUpdate, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv2.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversDelete, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv2.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversDelete, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv3.UID)},
|
|
),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(models.ReceiverPermissionReadSecret, models.ReceiverPermissionWrite),
|
|
recv2.UID: permissions(models.ReceiverPermissionWrite, models.ReceiverPermissionDelete),
|
|
recv3.UID: permissions(models.ReceiverPermissionReadSecret, models.ReceiverPermissionDelete),
|
|
},
|
|
},
|
|
{
|
|
name: "mixed requires read",
|
|
user: newEmptyUser(
|
|
ac.Permission{Action: ac.ActionAlertingReceiversReadSecrets, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversReadSecrets, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv3.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversUpdate, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversUpdate, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv2.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversDelete, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv2.UID)},
|
|
ac.Permission{Action: ac.ActionAlertingReceiversDelete, Scope: ScopeReceiversProvider.GetResourceScopeUID(recv3.UID)},
|
|
),
|
|
expected: map[string]models.ReceiverPermissionSet{
|
|
recv1.UID: permissions(models.ReceiverPermissionReadSecret, models.ReceiverPermissionWrite),
|
|
recv2.UID: permissions(),
|
|
recv3.UID: permissions(models.ReceiverPermissionReadSecret, models.ReceiverPermissionDelete),
|
|
},
|
|
},
|
|
}
|
|
for _, testCase := range testCases {
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
svc := NewReceiverAccess[*models.Receiver](&recordingAccessControlFake{}, false)
|
|
|
|
actual, err := svc.Access(context.Background(), testCase.user, allReceivers...)
|
|
|
|
assert.NoError(t, err)
|
|
assert.Equalf(t, testCase.expected, actual, "expected: %v, actual: %v", testCase.expected, actual)
|
|
|
|
provisioningPerms := testCase.expected
|
|
if testCase.expectedWithProvisioning != nil {
|
|
provisioningPerms = testCase.expectedWithProvisioning
|
|
}
|
|
svc = NewReceiverAccess[*models.Receiver](&recordingAccessControlFake{}, true)
|
|
actual, err = svc.Access(context.Background(), testCase.user, allReceivers...)
|
|
assert.NoError(t, err)
|
|
assert.Equalf(t, provisioningPerms, actual, "expectedWithProvisioning: %v, actual: %v", provisioningPerms, actual)
|
|
})
|
|
}
|
|
}
|
|
|
|
func newEmptyUser(permissions ...ac.Permission) identity.Requester {
|
|
return ac.BackgroundUser("test", orgID, org.RoleNone, permissions)
|
|
}
|
|
|
|
func newViewUser(permissions ...ac.Permission) identity.Requester {
|
|
return ac.BackgroundUser("test", orgID, org.RoleNone, append([]ac.Permission{
|
|
{Action: ac.ActionAlertingReceiversRead, Scope: ScopeReceiversAll},
|
|
{Action: ac.ActionAlertingNotificationsRead},
|
|
}, permissions...))
|
|
}
|