Add support ticket fixed roles to cloud role sync (#90864)

* Add support ticket fixed roles to cloud role sync

* Adding tests

* Fix the linter
This commit is contained in:
Vardan Torosyan
2024-07-24 17:58:21 +02:00
committed by GitHub
parent f1c3c55983
commit 82236976ae
3 changed files with 136 additions and 18 deletions
+4
View File
@@ -33,6 +33,10 @@ const (
FixedCloudViewerRole = "fixed:cloud:viewer"
FixedCloudEditorRole = "fixed:cloud:editor"
FixedCloudAdminRole = "fixed:cloud:admin"
FixedCloudSupportTicketReader = "fixed:cloud:supportticket:reader"
FixedCloudSupportTicketEditor = "fixed:cloud:supportticket:editor"
FixedCloudSupportTicketAdmin = "fixed:cloud:supportticket:admin"
)
// Roles definition
+41 -17
View File
@@ -97,10 +97,44 @@ func (s *RBACSync) fetchPermissions(ctx context.Context, ident *authn.Identity)
return permissions, nil
}
var fixedCloudRoles = map[org.RoleType]string{
org.RoleViewer: accesscontrol.FixedCloudViewerRole,
org.RoleEditor: accesscontrol.FixedCloudEditorRole,
org.RoleAdmin: accesscontrol.FixedCloudAdminRole,
func cloudRolesToAddAndRemove(ident *authn.Identity) ([]string, []string, error) {
const (
expectedRolesToAddCount = 2
rolesToRemoveInitialCap = 4
)
// Since Cloud Admin/Editor/Viewer roles are not yet implemented one-to-one in the Grafana, it becomes a confusing experience for users,
// therefore we are doing granular mapping of all available functionality in the Grafana temporary.
var fixedCloudRoles = map[org.RoleType][]string{
org.RoleViewer: {accesscontrol.FixedCloudViewerRole, accesscontrol.FixedCloudSupportTicketReader},
org.RoleEditor: {accesscontrol.FixedCloudEditorRole, accesscontrol.FixedCloudSupportTicketAdmin},
org.RoleAdmin: {accesscontrol.FixedCloudAdminRole, accesscontrol.FixedCloudSupportTicketAdmin},
}
rolesToAdd := make([]string, 0, expectedRolesToAddCount)
rolesToRemove := make([]string, 0, rolesToRemoveInitialCap)
currentRole := ident.GetOrgRole()
_, validRole := fixedCloudRoles[currentRole]
if !validRole {
return nil, nil, errInvalidCloudRole.Errorf("invalid role: %s", currentRole)
}
for role, fixedRoles := range fixedCloudRoles {
for _, fixedRole := range fixedRoles {
if role == currentRole {
rolesToAdd = append(rolesToAdd, fixedRole)
} else {
rolesToRemove = append(rolesToRemove, fixedRole)
}
}
}
if len(rolesToAdd) != expectedRolesToAddCount {
return nil, nil, errInvalidCloudRole.Errorf("invalid role: %s", currentRole)
}
return rolesToAdd, rolesToRemove, nil
}
func (s *RBACSync) SyncCloudRoles(ctx context.Context, ident *authn.Identity, r *authn.Request) error {
@@ -122,19 +156,9 @@ func (s *RBACSync) SyncCloudRoles(ctx context.Context, ident *authn.Identity, r
return err
}
rolesToAdd := make([]string, 0, 1)
rolesToRemove := make([]string, 0, 2)
for role, fixedRole := range fixedCloudRoles {
if role == ident.GetOrgRole() {
rolesToAdd = append(rolesToAdd, fixedRole)
} else {
rolesToRemove = append(rolesToRemove, fixedRole)
}
}
if len(rolesToAdd) != 1 {
return errInvalidCloudRole.Errorf("invalid role: %s", ident.GetOrgRole())
rolesToAdd, rolesToRemove, err := cloudRolesToAddAndRemove(ident)
if err != nil {
return err
}
return s.ac.SyncUserRoles(ctx, ident.GetOrgID(), accesscontrol.SyncUserRolesCommand{
@@ -136,12 +136,102 @@ func TestRBACSync_SyncCloudRoles(t *testing.T) {
req.SetMeta(authn.MetaKeyAuthModule, tt.module)
err := s.SyncCloudRoles(context.Background(), tt.identity, req)
assert.ErrorIs(t, err, tt.expectedErr)
assert.ErrorIs(t, tt.expectedErr, err)
assert.Equal(t, tt.expectedCalled, called)
})
}
}
func TestRBACSync_cloudRolesToAddAndRemove(t *testing.T) {
type testCase struct {
desc string
identity *authn.Identity
expectedErr error
expectedRolesToAdd []string
expectedRolesToRemove []string
}
tests := []testCase{
{
desc: "should map Cloud Viewer to Grafana Cloud Viewer and Support ticket reader",
identity: &authn.Identity{
ID: authn.NewNamespaceID(authn.NamespaceUser, 1),
OrgID: 1,
OrgRoles: map[int64]org.RoleType{1: org.RoleViewer},
},
expectedErr: nil,
expectedRolesToAdd: []string{
accesscontrol.FixedCloudViewerRole,
accesscontrol.FixedCloudSupportTicketReader,
},
expectedRolesToRemove: []string{
accesscontrol.FixedCloudEditorRole,
accesscontrol.FixedCloudSupportTicketAdmin,
accesscontrol.FixedCloudAdminRole,
accesscontrol.FixedCloudSupportTicketAdmin,
},
},
{
desc: "should map Cloud Editor to Grafana Cloud Editor and Support ticket admin",
identity: &authn.Identity{
ID: authn.NewNamespaceID(authn.NamespaceUser, 1),
OrgID: 1,
OrgRoles: map[int64]org.RoleType{1: org.RoleEditor},
},
expectedErr: nil,
expectedRolesToAdd: []string{
accesscontrol.FixedCloudEditorRole,
accesscontrol.FixedCloudSupportTicketAdmin,
},
expectedRolesToRemove: []string{
accesscontrol.FixedCloudViewerRole,
accesscontrol.FixedCloudSupportTicketReader,
accesscontrol.FixedCloudAdminRole,
accesscontrol.FixedCloudSupportTicketAdmin,
},
},
{
desc: "should map Cloud Admin to Grafana Cloud Admin and Support ticket admin",
identity: &authn.Identity{
ID: authn.NewNamespaceID(authn.NamespaceUser, 1),
OrgID: 1,
OrgRoles: map[int64]org.RoleType{1: org.RoleAdmin},
},
expectedErr: nil,
expectedRolesToAdd: []string{
accesscontrol.FixedCloudAdminRole,
accesscontrol.FixedCloudSupportTicketAdmin,
},
expectedRolesToRemove: []string{
accesscontrol.FixedCloudViewerRole,
accesscontrol.FixedCloudSupportTicketReader,
accesscontrol.FixedCloudEditorRole,
accesscontrol.FixedCloudSupportTicketAdmin,
},
},
{
desc: "should return an error for not supported role",
identity: &authn.Identity{
ID: authn.NewNamespaceID(authn.NamespaceUser, 1),
OrgID: 1,
OrgRoles: map[int64]org.RoleType{1: org.RoleNone},
},
expectedErr: errInvalidCloudRole,
expectedRolesToAdd: []string{},
expectedRolesToRemove: []string{},
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
rolesToAdd, rolesToRemove, err := cloudRolesToAddAndRemove(tt.identity)
assert.ErrorIs(t, tt.expectedErr, err)
assert.ElementsMatch(t, tt.expectedRolesToAdd, rolesToAdd)
assert.ElementsMatch(t, tt.expectedRolesToRemove, rolesToRemove)
})
}
}
func setupTestEnv() *RBACSync {
acMock := &acmock.Mock{
GetUserPermissionsFunc: func(ctx context.Context, siu authn.Requester, o accesscontrol.Options) ([]accesscontrol.Permission, error) {