The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/services/ngalert/accesscontrol/receivers_test.go

410 lines
18 KiB

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...))
}