Skip to content

Commit b37bf8d

Browse files
fix: user permissions not merging on same environments (#6167)
* refactoring and bug fix * optimisation * merging rows based
1 parent b7ada49 commit b37bf8d

File tree

7 files changed

+233
-164
lines changed

7 files changed

+233
-164
lines changed

api/bean/UserRequest.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,19 @@ type RoleFilter struct {
7272
Workflow string `json:"workflow"`
7373
}
7474

75+
func (rf RoleFilter) GetTeam() string { return rf.Team }
76+
func (rf RoleFilter) GetEntity() string { return rf.Entity }
77+
func (rf RoleFilter) GetAction() string { return rf.Action }
78+
func (rf RoleFilter) GetAccessType() string { return rf.AccessType }
79+
func (rf RoleFilter) GetEnvironment() string { return rf.Environment }
80+
func (rf RoleFilter) GetCluster() string { return rf.Cluster }
81+
func (rf RoleFilter) GetGroup() string { return rf.Group }
82+
func (rf RoleFilter) GetKind() string { return rf.Kind }
83+
func (rf RoleFilter) GetEntityName() string { return rf.EntityName }
84+
func (rf RoleFilter) GetResource() string { return rf.Resource }
85+
func (rf RoleFilter) GetWorkflow() string { return rf.Workflow }
86+
func (rf RoleFilter) GetNamespace() string { return rf.Namespace }
87+
7588
type Role struct {
7689
Id int `json:"id" validate:"number"`
7790
Role string `json:"role" validate:"required"`

pkg/auth/user/RoleGroupService.go

Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -569,46 +569,11 @@ func (impl RoleGroupServiceImpl) getRoleGroupMetadata(roleGroup *repository.Role
569569
impl.logger.Errorw("No Roles Found for user", "roleGroupId", roleGroup.Id)
570570
}
571571
var roleFilters []bean.RoleFilter
572-
isSuperAdmin := false
573-
roleFilterMap := make(map[string]*bean.RoleFilter)
574-
for _, role := range roles {
575-
key := impl.userCommonService.GetUniqueKeyForAllEntity(*role)
576-
if _, ok := roleFilterMap[key]; ok {
577-
impl.userCommonService.BuildRoleFilterForAllTypes(roleFilterMap, *role, key)
578-
} else {
579-
roleFilterMap[key] = &bean.RoleFilter{
580-
Entity: role.Entity,
581-
Team: role.Team,
582-
Environment: role.Environment,
583-
EntityName: role.EntityName,
584-
Action: role.Action,
585-
AccessType: role.AccessType,
586-
Cluster: role.Cluster,
587-
Namespace: role.Namespace,
588-
Group: role.Group,
589-
Kind: role.Kind,
590-
Resource: role.Resource,
591-
Workflow: role.Workflow,
592-
}
593-
}
594-
if role.Role == bean.SUPERADMIN {
595-
isSuperAdmin = true
596-
}
597-
}
598-
for _, v := range roleFilterMap {
599-
if v.Action == bean2.SUPER_ADMIN {
600-
continue
601-
}
602-
roleFilters = append(roleFilters, *v)
603-
}
604-
for index, roleFilter := range roleFilters {
605-
if roleFilter.Entity == "" {
606-
roleFilters[index].Entity = bean2.ENTITY_APPS
607-
}
608-
if roleFilter.Entity == bean2.ENTITY_APPS && roleFilter.AccessType == "" {
609-
roleFilters[index].AccessType = bean2.DEVTRON_APP
610-
}
611-
}
572+
isSuperAdmin := helper2.CheckIfSuperAdminFromRoles(roles)
573+
// merging considering base as env first
574+
roleFilters = impl.userCommonService.BuildRoleFiltersAfterMerging(ConvertRolesToEntityProcessors(roles), bean2.EnvironmentBasedKey)
575+
// merging role filters based on application now, first took env as base merged, now application as base , merged
576+
roleFilters = impl.userCommonService.BuildRoleFiltersAfterMerging(ConvertRoleFiltersToEntityProcessors(roleFilters), bean2.ApplicationBasedKey)
612577
if len(roleFilters) == 0 {
613578
roleFilters = make([]bean.RoleFilter, 0)
614579
}

pkg/auth/user/UserCommonService.go

Lines changed: 174 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,28 @@ type UserCommonService interface {
4141
RemoveRolesAndReturnEliminatedPoliciesForGroups(request *bean.RoleGroup, existingRoles map[int]*repository.RoleGroupRoleMapping, eliminatedRoles map[int]*repository.RoleGroupRoleMapping, tx *pg.Tx, token string, managerAuth func(resource string, token string, object string) bool) ([]casbin.Policy, []*repository.RoleModel, error)
4242
CheckRbacForClusterEntity(cluster, namespace, group, kind, resource, token string, managerAuth func(resource, token, object string) bool) bool
4343
GetCapacityForRoleFilter(roleFilters []bean.RoleFilter) (int, map[int]int)
44-
BuildRoleFilterForAllTypes(roleFilterMap map[string]*bean.RoleFilter, role repository.RoleModel, key string)
45-
GetUniqueKeyForAllEntity(role repository.RoleModel) string
44+
BuildRoleFilterForAllTypes(roleFilterMap map[string]*bean.RoleFilter, entityProcessor EntityKeyProcessor, key string, basetoConsider bean2.MergingBaseKey)
45+
GetUniqueKeyForAllEntity(entityProcessor EntityKeyProcessor, baseToConsider bean2.MergingBaseKey) string
4646
SetDefaultValuesIfNotPresent(request *bean.ListingRequest, isRoleGroup bool)
4747
DeleteRoleForUserFromCasbin(mappings map[string][]string) bool
4848
DeleteUserForRoleFromCasbin(mappings map[string][]string) bool
49+
BuildRoleFiltersAfterMerging(entityProcessors []EntityKeyProcessor, baseKey bean2.MergingBaseKey) []bean.RoleFilter
50+
}
51+
52+
// Defining a common interface for role and rolefilter
53+
type EntityKeyProcessor interface {
54+
GetTeam() string
55+
GetEntity() string
56+
GetAction() string
57+
GetAccessType() string
58+
GetEnvironment() string
59+
GetCluster() string
60+
GetGroup() string
61+
GetKind() string
62+
GetEntityName() string
63+
GetResource() string
64+
GetWorkflow() string
65+
GetNamespace() string
4966
}
5067

5168
type UserCommonServiceImpl struct {
@@ -615,97 +632,145 @@ func (impl UserCommonServiceImpl) GetCapacityForRoleFilter(roleFilters []bean.Ro
615632
return capacity, m
616633
}
617634

618-
func (impl UserCommonServiceImpl) BuildRoleFilterForAllTypes(roleFilterMap map[string]*bean.RoleFilter, role repository.RoleModel, key string) {
619-
switch role.Entity {
635+
func (impl UserCommonServiceImpl) BuildRoleFilterForAllTypes(roleFilterMap map[string]*bean.RoleFilter, entityProcessor EntityKeyProcessor, key string, basetoConsider bean2.MergingBaseKey) {
636+
switch entityProcessor.GetEntity() {
620637
case bean2.CLUSTER_ENTITIY:
621638
{
622-
BuildRoleFilterKeyForCluster(roleFilterMap, role, key)
639+
BuildRoleFilterKeyForCluster(roleFilterMap, entityProcessor, key)
623640
}
624641
case bean2.EntityJobs:
625642
{
626-
BuildRoleFilterKeyForJobs(roleFilterMap, role, key)
643+
BuildRoleFilterKeyForJobs(roleFilterMap, entityProcessor, key, basetoConsider)
627644
}
628645
default:
629646
{
630-
BuildRoleFilterKeyForOtherEntity(roleFilterMap, role, key)
647+
BuildRoleFilterKeyForOtherEntity(roleFilterMap, entityProcessor, key, basetoConsider)
631648
}
632649
}
633650
}
634651

635-
func BuildRoleFilterKeyForCluster(roleFilterMap map[string]*bean.RoleFilter, role repository.RoleModel, key string) {
652+
func BuildRoleFilterKeyForCluster(roleFilterMap map[string]*bean.RoleFilter, entityProcessor EntityKeyProcessor, key string) {
636653
namespaceArr := strings.Split(roleFilterMap[key].Namespace, ",")
637654
if containsArr(namespaceArr, AllNamespace) {
638655
roleFilterMap[key].Namespace = AllNamespace
639-
} else if !containsArr(namespaceArr, role.Namespace) {
640-
roleFilterMap[key].Namespace = fmt.Sprintf("%s,%s", roleFilterMap[key].Namespace, role.Namespace)
656+
} else if !containsArr(namespaceArr, entityProcessor.GetNamespace()) {
657+
roleFilterMap[key].Namespace = fmt.Sprintf("%s,%s", roleFilterMap[key].Namespace, entityProcessor.GetNamespace())
641658
}
642659
groupArr := strings.Split(roleFilterMap[key].Group, ",")
643660
if containsArr(groupArr, AllGroup) {
644661
roleFilterMap[key].Group = AllGroup
645-
} else if !containsArr(groupArr, role.Group) {
646-
roleFilterMap[key].Group = fmt.Sprintf("%s,%s", roleFilterMap[key].Group, role.Group)
662+
} else if !containsArr(groupArr, entityProcessor.GetGroup()) {
663+
roleFilterMap[key].Group = fmt.Sprintf("%s,%s", roleFilterMap[key].Group, entityProcessor.GetGroup())
647664
}
648665
kindArr := strings.Split(roleFilterMap[key].Kind, ",")
649666
if containsArr(kindArr, AllKind) {
650667
roleFilterMap[key].Kind = AllKind
651-
} else if !containsArr(kindArr, role.Kind) {
652-
roleFilterMap[key].Kind = fmt.Sprintf("%s,%s", roleFilterMap[key].Kind, role.Kind)
668+
} else if !containsArr(kindArr, entityProcessor.GetKind()) {
669+
roleFilterMap[key].Kind = fmt.Sprintf("%s,%s", roleFilterMap[key].Kind, entityProcessor.GetKind())
653670
}
654671
resourceArr := strings.Split(roleFilterMap[key].Resource, ",")
655672
if containsArr(resourceArr, AllResource) {
656673
roleFilterMap[key].Resource = AllResource
657-
} else if !containsArr(resourceArr, role.Resource) {
658-
roleFilterMap[key].Resource = fmt.Sprintf("%s,%s", roleFilterMap[key].Resource, role.Resource)
674+
} else if !containsArr(resourceArr, entityProcessor.GetResource()) {
675+
roleFilterMap[key].Resource = fmt.Sprintf("%s,%s", roleFilterMap[key].Resource, entityProcessor.GetResource())
659676
}
660677
}
661678

662-
func BuildRoleFilterKeyForJobs(roleFilterMap map[string]*bean.RoleFilter, role repository.RoleModel, key string) {
663-
envArr := strings.Split(roleFilterMap[key].Environment, ",")
664-
if containsArr(envArr, AllEnvironment) {
665-
roleFilterMap[key].Environment = AllEnvironment
666-
} else if !containsArr(envArr, role.Environment) {
667-
roleFilterMap[key].Environment = fmt.Sprintf("%s,%s", roleFilterMap[key].Environment, role.Environment)
668-
}
669-
entityArr := strings.Split(roleFilterMap[key].EntityName, ",")
670-
if containsArr(entityArr, bean2.EmptyStringIndicatingAll) {
671-
roleFilterMap[key].EntityName = bean2.EmptyStringIndicatingAll
672-
} else if !containsArr(entityArr, role.EntityName) {
673-
roleFilterMap[key].EntityName = fmt.Sprintf("%s,%s", roleFilterMap[key].EntityName, role.EntityName)
679+
func BuildRoleFilterKeyForJobs(roleFilterMap map[string]*bean.RoleFilter, entityProcessor EntityKeyProcessor, key string, baseToConsider bean2.MergingBaseKey) {
680+
switch baseToConsider {
681+
case bean2.ApplicationBasedKey:
682+
envArr := strings.Split(roleFilterMap[key].Environment, ",")
683+
if containsArr(envArr, AllEnvironment) {
684+
roleFilterMap[key].Environment = AllEnvironment
685+
} else if !containsArr(envArr, entityProcessor.GetEnvironment()) {
686+
roleFilterMap[key].Environment = fmt.Sprintf("%s,%s", roleFilterMap[key].Environment, entityProcessor.GetEnvironment())
687+
}
688+
case bean2.EnvironmentBasedKey:
689+
entityArr := strings.Split(roleFilterMap[key].EntityName, ",")
690+
if containsArr(entityArr, bean2.EmptyStringIndicatingAll) {
691+
roleFilterMap[key].EntityName = bean2.EmptyStringIndicatingAll
692+
} else if !containsArr(entityArr, entityProcessor.GetEntityName()) {
693+
roleFilterMap[key].EntityName = fmt.Sprintf("%s,%s", roleFilterMap[key].EntityName, entityProcessor.GetEntityName())
694+
}
695+
default:
696+
envArr := strings.Split(roleFilterMap[key].Environment, ",")
697+
if containsArr(envArr, AllEnvironment) {
698+
roleFilterMap[key].Environment = AllEnvironment
699+
} else if !containsArr(envArr, entityProcessor.GetEnvironment()) {
700+
roleFilterMap[key].Environment = fmt.Sprintf("%s,%s", roleFilterMap[key].Environment, entityProcessor.GetEnvironment())
701+
}
702+
entityArr := strings.Split(roleFilterMap[key].EntityName, ",")
703+
if containsArr(entityArr, bean2.EmptyStringIndicatingAll) {
704+
roleFilterMap[key].EntityName = bean2.EmptyStringIndicatingAll
705+
} else if !containsArr(entityArr, entityProcessor.GetEntityName()) {
706+
roleFilterMap[key].EntityName = fmt.Sprintf("%s,%s", roleFilterMap[key].EntityName, entityProcessor.GetEntityName())
707+
}
674708
}
675709
workflowArr := strings.Split(roleFilterMap[key].Workflow, ",")
676710
if containsArr(workflowArr, AllWorkflow) {
677711
roleFilterMap[key].Workflow = AllWorkflow
678-
} else if !containsArr(workflowArr, role.Workflow) {
679-
roleFilterMap[key].Workflow = fmt.Sprintf("%s,%s", roleFilterMap[key].Workflow, role.Workflow)
712+
} else if !containsArr(workflowArr, entityProcessor.GetWorkflow()) {
713+
roleFilterMap[key].Workflow = fmt.Sprintf("%s,%s", roleFilterMap[key].Workflow, entityProcessor.GetWorkflow())
680714
}
681715
}
682716

683-
func BuildRoleFilterKeyForOtherEntity(roleFilterMap map[string]*bean.RoleFilter, role repository.RoleModel, key string) {
684-
envArr := strings.Split(roleFilterMap[key].Environment, ",")
685-
if containsArr(envArr, AllEnvironment) {
686-
roleFilterMap[key].Environment = AllEnvironment
687-
} else if !containsArr(envArr, role.Environment) {
688-
roleFilterMap[key].Environment = fmt.Sprintf("%s,%s", roleFilterMap[key].Environment, role.Environment)
689-
}
690-
entityArr := strings.Split(roleFilterMap[key].EntityName, ",")
691-
if containsArr(entityArr, bean2.EmptyStringIndicatingAll) {
692-
roleFilterMap[key].EntityName = bean2.EmptyStringIndicatingAll
693-
} else if !containsArr(entityArr, role.EntityName) {
694-
roleFilterMap[key].EntityName = fmt.Sprintf("%s,%s", roleFilterMap[key].EntityName, role.EntityName)
717+
func BuildRoleFilterKeyForOtherEntity(roleFilterMap map[string]*bean.RoleFilter, entityProcessor EntityKeyProcessor, key string, baseToConsider bean2.MergingBaseKey) {
718+
switch baseToConsider {
719+
case bean2.ApplicationBasedKey:
720+
envArr := strings.Split(roleFilterMap[key].Environment, ",")
721+
if containsArr(envArr, AllEnvironment) {
722+
roleFilterMap[key].Environment = AllEnvironment
723+
} else if !containsArr(envArr, entityProcessor.GetEnvironment()) {
724+
roleFilterMap[key].Environment = fmt.Sprintf("%s,%s", roleFilterMap[key].Environment, entityProcessor.GetEnvironment())
725+
}
726+
case bean2.EnvironmentBasedKey:
727+
entityArr := strings.Split(roleFilterMap[key].EntityName, ",")
728+
if containsArr(entityArr, bean2.EmptyStringIndicatingAll) {
729+
roleFilterMap[key].EntityName = bean2.EmptyStringIndicatingAll
730+
} else if !containsArr(entityArr, entityProcessor.GetEntityName()) {
731+
roleFilterMap[key].EntityName = fmt.Sprintf("%s,%s", roleFilterMap[key].EntityName, entityProcessor.GetEntityName())
732+
}
733+
default:
734+
envArr := strings.Split(roleFilterMap[key].Environment, ",")
735+
if containsArr(envArr, AllEnvironment) {
736+
roleFilterMap[key].Environment = AllEnvironment
737+
} else if !containsArr(envArr, entityProcessor.GetEnvironment()) {
738+
roleFilterMap[key].Environment = fmt.Sprintf("%s,%s", roleFilterMap[key].Environment, entityProcessor.GetEnvironment())
739+
}
740+
entityArr := strings.Split(roleFilterMap[key].EntityName, ",")
741+
if containsArr(entityArr, bean2.EmptyStringIndicatingAll) {
742+
roleFilterMap[key].EntityName = bean2.EmptyStringIndicatingAll
743+
} else if !containsArr(entityArr, entityProcessor.GetEntityName()) {
744+
roleFilterMap[key].EntityName = fmt.Sprintf("%s,%s", roleFilterMap[key].EntityName, entityProcessor.GetEntityName())
745+
}
695746
}
696747
}
697-
func (impl UserCommonServiceImpl) GetUniqueKeyForAllEntity(role repository.RoleModel) string {
748+
func (impl UserCommonServiceImpl) GetUniqueKeyForAllEntity(entityProcessor EntityKeyProcessor, baseToConsider bean2.MergingBaseKey) string {
698749
key := ""
699-
if len(role.Team) > 0 && role.Entity != bean2.EntityJobs {
700-
key = fmt.Sprintf("%s_%s_%s_%s", role.Team, role.Environment, role.Action, role.AccessType)
701-
} else if role.Entity == bean2.EntityJobs {
702-
key = fmt.Sprintf("%s_%s_%s_%s_%s", role.Team, role.Environment, role.Action, role.AccessType, role.Entity)
703-
} else if len(role.Entity) > 0 {
704-
if role.Entity == bean2.CLUSTER_ENTITIY {
705-
key = fmt.Sprintf("%s_%s_%s_%s_%s", role.Entity, role.Action, role.Cluster,
706-
role.Group, role.Kind)
750+
if len(entityProcessor.GetTeam()) > 0 && entityProcessor.GetEntity() != bean2.EntityJobs {
751+
switch baseToConsider {
752+
case bean2.EnvironmentBasedKey:
753+
key = fmt.Sprintf("%s_%s_%s_%s", entityProcessor.GetTeam(), entityProcessor.GetEnvironment(), entityProcessor.GetAction(), entityProcessor.GetAccessType())
754+
case bean2.ApplicationBasedKey:
755+
key = fmt.Sprintf("%s_%s_%s_%s", entityProcessor.GetTeam(), entityProcessor.GetEntityName(), entityProcessor.GetAction(), entityProcessor.GetAccessType())
756+
default:
757+
key = fmt.Sprintf("%s_%s_%s", entityProcessor.GetTeam(), entityProcessor.GetAction(), entityProcessor.GetAccessType())
758+
}
759+
} else if entityProcessor.GetEntity() == bean2.EntityJobs {
760+
switch baseToConsider {
761+
case bean2.EnvironmentBasedKey:
762+
key = fmt.Sprintf("%s_%s_%s_%s_%s", entityProcessor.GetTeam(), entityProcessor.GetEnvironment(), entityProcessor.GetAction(), entityProcessor.GetAccessType(), entityProcessor.GetEntity())
763+
case bean2.ApplicationBasedKey:
764+
key = fmt.Sprintf("%s_%s_%s_%s_%s", entityProcessor.GetTeam(), entityProcessor.GetEntityName(), entityProcessor.GetAction(), entityProcessor.GetAccessType(), entityProcessor.GetEntity())
765+
default:
766+
key = fmt.Sprintf("%s_%s_%s_%s", entityProcessor.GetTeam(), entityProcessor.GetAction(), entityProcessor.GetAccessType(), entityProcessor.GetEntity())
767+
}
768+
} else if len(entityProcessor.GetEntity()) > 0 {
769+
if entityProcessor.GetEntity() == bean2.CLUSTER_ENTITIY {
770+
key = fmt.Sprintf("%s_%s_%s_%s_%s", entityProcessor.GetEntity(), entityProcessor.GetAction(), entityProcessor.GetCluster(),
771+
entityProcessor.GetGroup(), entityProcessor.GetKind())
707772
} else {
708-
key = fmt.Sprintf("%s_%s", role.Entity, role.Action)
773+
key = fmt.Sprintf("%s_%s", entityProcessor.GetEntity(), entityProcessor.GetAction())
709774
}
710775
}
711776
return key
@@ -753,3 +818,60 @@ func (impl UserCommonServiceImpl) DeleteUserForRoleFromCasbin(mappings map[strin
753818
}
754819
return successful
755820
}
821+
822+
func (impl UserCommonServiceImpl) BuildRoleFiltersAfterMerging(entityProcessors []EntityKeyProcessor, baseKey bean2.MergingBaseKey) []bean.RoleFilter {
823+
roleFilterMap := make(map[string]*bean.RoleFilter, len(entityProcessors))
824+
roleFilters := make([]bean.RoleFilter, 0, len(entityProcessors))
825+
for _, entityProcessor := range entityProcessors {
826+
key := impl.GetUniqueKeyForAllEntity(entityProcessor, baseKey)
827+
if _, ok := roleFilterMap[key]; ok {
828+
impl.BuildRoleFilterForAllTypes(roleFilterMap, entityProcessor, key, baseKey)
829+
} else {
830+
roleFilterMap[key] = &bean.RoleFilter{
831+
Entity: entityProcessor.GetEntity(),
832+
Team: entityProcessor.GetTeam(),
833+
Environment: entityProcessor.GetEnvironment(),
834+
EntityName: entityProcessor.GetEntityName(),
835+
Action: entityProcessor.GetAction(),
836+
AccessType: entityProcessor.GetAccessType(),
837+
Cluster: entityProcessor.GetCluster(),
838+
Namespace: entityProcessor.GetNamespace(),
839+
Group: entityProcessor.GetGroup(),
840+
Kind: entityProcessor.GetKind(),
841+
Resource: entityProcessor.GetResource(),
842+
Workflow: entityProcessor.GetWorkflow(),
843+
}
844+
}
845+
}
846+
for _, v := range roleFilterMap {
847+
if v.Action == bean2.SUPER_ADMIN {
848+
continue
849+
}
850+
roleFilters = append(roleFilters, *v)
851+
}
852+
for index, roleFilter := range roleFilters {
853+
if roleFilter.Entity == "" {
854+
roleFilters[index].Entity = bean2.ENTITY_APPS
855+
}
856+
if roleFilter.Entity == bean2.ENTITY_APPS && roleFilter.AccessType == "" {
857+
roleFilters[index].AccessType = bean2.DEVTRON_APP
858+
}
859+
}
860+
return roleFilters
861+
}
862+
863+
func ConvertRoleFiltersToEntityProcessors(filters []bean.RoleFilter) []EntityKeyProcessor {
864+
processors := make([]EntityKeyProcessor, len(filters))
865+
for i, filter := range filters {
866+
processors[i] = filter // Each RoleFilter is an EntityKeyProcessor
867+
}
868+
return processors
869+
}
870+
871+
func ConvertRolesToEntityProcessors(roles []*repository.RoleModel) []EntityKeyProcessor {
872+
processors := make([]EntityKeyProcessor, len(roles))
873+
for i, filter := range roles {
874+
processors[i] = filter // Each role is an EntityKeyProcessor
875+
}
876+
return processors
877+
}

0 commit comments

Comments
 (0)