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:
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user