Skip to content

Commit c869fce

Browse files
fix: user flows permissions fix (#5917)
* fix user flows * comment * fixed flows * generics * refactored rest handler * review comments * manager access
1 parent de19970 commit c869fce

File tree

9 files changed

+239
-150
lines changed

9 files changed

+239
-150
lines changed

api/auth/user/UserRestHandler.go

Lines changed: 113 additions & 137 deletions
Large diffs are not rendered by default.

api/bean/UserRequest.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,47 @@ type BulkDeleteRequest struct {
155155
type UserRoleGroup struct {
156156
RoleGroup *RoleGroup `json:"roleGroup"`
157157
}
158+
159+
type RoleEntity interface {
160+
GetAccessType() string
161+
GetEntity() string
162+
GetTeam() string
163+
GetCluster() string
164+
GetNamespace() string
165+
GetGroup() string
166+
GetKind() string
167+
GetResource() string
168+
}
169+
170+
// For RoleFilter
171+
func (filter RoleFilter) GetAccessType() string {
172+
return filter.AccessType
173+
}
174+
175+
func (filter RoleFilter) GetEntity() string {
176+
return filter.Entity
177+
}
178+
179+
func (filter RoleFilter) GetTeam() string {
180+
return filter.Team
181+
}
182+
183+
func (filter RoleFilter) GetCluster() string {
184+
return filter.Cluster
185+
}
186+
187+
func (filter RoleFilter) GetNamespace() string {
188+
return filter.Namespace
189+
}
190+
191+
func (filter RoleFilter) GetGroup() string {
192+
return filter.Group
193+
}
194+
195+
func (filter RoleFilter) GetKind() string {
196+
return filter.Kind
197+
}
198+
199+
func (filter RoleFilter) GetResource() string {
200+
return filter.Resource
201+
}

cmd/external-app/wire_gen.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/auth/user/RoleGroupService.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package user
1919
import (
2020
"errors"
2121
"fmt"
22+
helper2 "github.com/devtron-labs/devtron/pkg/auth/user/helper"
2223
"github.com/devtron-labs/devtron/pkg/auth/user/repository/helper"
2324
"net/http"
2425
"strings"
@@ -39,7 +40,7 @@ import (
3940
type RoleGroupService interface {
4041
CreateRoleGroup(request *bean.RoleGroup) (*bean.RoleGroup, error)
4142
UpdateRoleGroup(request *bean.RoleGroup, token string, checkRBACForGroupUpdate func(token string, groupInfo *bean.RoleGroup,
42-
eliminatedRoleFilters []*repository.RoleModel) (isAuthorised bool, err error)) (*bean.RoleGroup, error)
43+
eliminatedRoleFilters []*repository.RoleModel, mapOfExistingRoleFilterKey map[string]bool) (isAuthorised bool, err error)) (*bean.RoleGroup, error)
4344
FetchDetailedRoleGroups(req *bean.ListingRequest) ([]*bean.RoleGroup, error)
4445
FetchRoleGroupsById(id int32) (*bean.RoleGroup, error)
4546
FetchRoleGroups() ([]*bean.RoleGroup, error)
@@ -369,7 +370,7 @@ func (impl RoleGroupServiceImpl) CreateOrUpdateRoleGroupForJobsEntity(roleFilter
369370
}
370371

371372
func (impl RoleGroupServiceImpl) UpdateRoleGroup(request *bean.RoleGroup, token string, checkRBACForGroupUpdate func(token string, groupInfo *bean.RoleGroup,
372-
eliminatedRoleFilters []*repository.RoleModel) (isAuthorised bool, err error)) (*bean.RoleGroup, error) {
373+
eliminatedRoleFilters []*repository.RoleModel, mapOfExistingRoleFilterKey map[string]bool) (isAuthorised bool, err error)) (*bean.RoleGroup, error) {
373374
dbConnection := impl.roleGroupRepository.GetConnection()
374375
tx, err := dbConnection.Begin()
375376
if err != nil {
@@ -476,7 +477,13 @@ func (impl RoleGroupServiceImpl) UpdateRoleGroup(request *bean.RoleGroup, token
476477
}
477478

478479
if checkRBACForGroupUpdate != nil {
479-
isAuthorised, err := checkRBACForGroupUpdate(token, request, eliminatedRoleModels)
480+
existingRoleGroupData, err := impl.FetchRoleGroupsById(roleGroup.Id)
481+
if err != nil {
482+
impl.logger.Errorw("error encountered in Update role group", "err", err, "roleGroupId", roleGroup.Id)
483+
return nil, err
484+
}
485+
mapOfExitingRoleFiltersKey := helper2.GetMapOfUniqueKeys(existingRoleGroupData.RoleFilters, util2.GetUniqueKeyForRoleFilter)
486+
isAuthorised, err := checkRBACForGroupUpdate(token, request, eliminatedRoleModels, mapOfExitingRoleFiltersKey)
480487
if err != nil {
481488
impl.logger.Errorw("error in checking RBAC for role group update", "err", err, "request", request)
482489
return nil, err

pkg/auth/user/UserService.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ type UserService interface {
5454
CreateUser(userInfo *bean.UserInfo) ([]*bean.UserInfo, error)
5555
SelfRegisterUserIfNotExists(userInfo *bean.UserInfo) ([]*bean.UserInfo, error)
5656
UpdateUser(userInfo *bean.UserInfo, token string, checkRBACForUserUpdate func(token string, userInfo *bean.UserInfo, isUserAlreadySuperAdmin bool,
57-
eliminatedRoleFilters, eliminatedGroupRoles []*repository.RoleModel) (isAuthorised bool, err error)) (*bean.UserInfo, error)
57+
eliminatedRoleFilters, eliminatedGroupRoles []*repository.RoleModel, mapOfExistingRoleFilter, mapOfExistingUserGroup map[string]bool) (isAuthorised bool, err error)) (*bean.UserInfo, error)
5858
GetById(id int32) (*bean.UserInfo, error)
5959
GetAll() ([]bean.UserInfo, error)
6060
GetAllWithFilters(request *bean.ListingRequest) (*bean.UserListingResponse, error)
@@ -572,13 +572,11 @@ func (impl *UserServiceImpl) mergeRoleFilter(oldR []bean.RoleFilter, newR []bean
572572
Resource: role.Resource,
573573
Workflow: role.Workflow,
574574
})
575-
key := fmt.Sprintf("%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s", role.Entity, role.Team, role.Environment,
576-
role.EntityName, role.Action, role.AccessType, role.Cluster, role.Namespace, role.Group, role.Kind, role.Resource, role.Workflow)
575+
key := util3.GetUniqueKeyForRoleFilter(role)
577576
keysMap[key] = true
578577
}
579578
for _, role := range newR {
580-
key := fmt.Sprintf("%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s", role.Entity, role.Team, role.Environment,
581-
role.EntityName, role.Action, role.AccessType, role.Cluster, role.Namespace, role.Group, role.Kind, role.Resource, role.Workflow)
579+
key := util3.GetUniqueKeyForRoleFilter(role)
582580
if _, ok := keysMap[key]; !ok {
583581
roleFilters = append(roleFilters, bean.RoleFilter{
584582
Entity: role.Entity,
@@ -635,7 +633,7 @@ func (impl *UserServiceImpl) mergeUserRoleGroup(oldUserRoleGroups []bean.UserRol
635633
}
636634

637635
func (impl *UserServiceImpl) UpdateUser(userInfo *bean.UserInfo, token string, checkRBACForUserUpdate func(token string, userInfo *bean.UserInfo,
638-
isUserAlreadySuperAdmin bool, eliminatedRoleFilters, eliminatedGroupRoles []*repository.RoleModel) (isAuthorised bool, err error)) (*bean.UserInfo, error) {
636+
isUserAlreadySuperAdmin bool, eliminatedRoleFilters, eliminatedGroupRoles []*repository.RoleModel, mapOfExistingRoleFilter, mapOfExistingUserGroup map[string]bool) (isAuthorised bool, err error)) (*bean.UserInfo, error) {
639637
//checking if request for same user is being processed
640638
isLocked := impl.getUserReqLockStateById(userInfo.Id)
641639
if isLocked {
@@ -802,7 +800,15 @@ func (impl *UserServiceImpl) UpdateUser(userInfo *bean.UserInfo, token string, c
802800
}
803801

804802
if checkRBACForUserUpdate != nil {
805-
isAuthorised, err := checkRBACForUserUpdate(token, userInfo, isUserSuperAdmin, eliminatedRoles, eliminatedGroupRoles)
803+
// get existing permissions for user and ignore rbac for unchanged permissions whether direct permissions or group permissions
804+
existingUserInfo, err := impl.GetById(model.Id)
805+
if err != nil {
806+
impl.logger.Errorw("error while fetching user from db", "error", err)
807+
return nil, err
808+
}
809+
uniqueRolefilterKeyMap := userHelper.GetMapOfUniqueKeys(existingUserInfo.RoleFilters, util3.GetUniqueKeyForRoleFilter)
810+
existingRoleGroupKeyMap := userHelper.GetMapOfUniqueKeys(existingUserInfo.UserRoleGroup, userHelper.GetUniqueKeyForUserGroup)
811+
isAuthorised, err := checkRBACForUserUpdate(token, userInfo, isUserSuperAdmin, eliminatedRoles, eliminatedGroupRoles, uniqueRolefilterKeyMap, existingRoleGroupKeyMap)
806812
if err != nil {
807813
impl.logger.Errorw("error in checking RBAC for user update", "err", err, "userInfo", userInfo)
808814
return nil, err

pkg/auth/user/helper/helper.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,16 @@ func CreateErrorMessageForUserRoleGroups(restrictedGroups []bean2.RestrictedGrou
9393
}
9494
return errorMessageForGroupsWithoutSuperAdmin, errorMessageForGroupsWithSuperAdmin
9595
}
96+
97+
// GetMapOfUniqueKeys takes a slice of any type and a function to extract a unique key, returning a map of unique keys.
98+
func GetMapOfUniqueKeys[T any](items []T, getKeyFunc func(T) string) map[string]bool {
99+
uniqueKeyMap := make(map[string]bool, len(items))
100+
for _, item := range items {
101+
uniqueKeyMap[getKeyFunc(item)] = true
102+
}
103+
return uniqueKeyMap
104+
}
105+
106+
func GetUniqueKeyForUserGroup(group bean2.UserRoleGroup) string {
107+
return fmt.Sprintf("%d-%s", group.RoleGroup.Id, group.RoleGroup.Name)
108+
}

pkg/auth/user/repository/UserAuthRepository.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,39 @@ type RoleModel struct {
110110
sql.AuditLog
111111
}
112112

113+
// For RoleModel
114+
func (model RoleModel) GetAccessType() string {
115+
return model.AccessType
116+
}
117+
118+
func (model RoleModel) GetEntity() string {
119+
return model.Entity
120+
}
121+
122+
func (model RoleModel) GetTeam() string {
123+
return model.Team
124+
}
125+
126+
func (model RoleModel) GetCluster() string {
127+
return model.Cluster
128+
}
129+
130+
func (model RoleModel) GetNamespace() string {
131+
return model.Namespace
132+
}
133+
134+
func (model RoleModel) GetGroup() string {
135+
return model.Group
136+
}
137+
138+
func (model RoleModel) GetKind() string {
139+
return model.Kind
140+
}
141+
142+
func (model RoleModel) GetResource() string {
143+
return model.Resource
144+
}
145+
113146
type RolePolicyDetails struct {
114147
Team string
115148
Env string

pkg/auth/user/util/util.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@
1616

1717
package util
1818

19-
import "strings"
19+
import (
20+
"fmt"
21+
"github.com/devtron-labs/devtron/api/bean"
22+
"strings"
23+
)
2024

2125
const (
2226
ApiTokenPrefix = "API-TOKEN:"
@@ -39,3 +43,9 @@ func CheckIfAdminOrApiToken(email string) bool {
3943
func CheckIfApiToken(email string) bool {
4044
return strings.HasPrefix(email, ApiTokenPrefix)
4145
}
46+
47+
func GetUniqueKeyForRoleFilter(role bean.RoleFilter) string {
48+
key := fmt.Sprintf("%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s", role.Entity, role.Team, role.Environment,
49+
role.EntityName, role.Action, role.AccessType, role.Cluster, role.Namespace, role.Group, role.Kind, role.Resource, role.Workflow)
50+
return key
51+
}

wire_gen.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)