Skip to content

Commit

Permalink
fixed flows
Browse files Browse the repository at this point in the history
  • Loading branch information
Shivam-nagar23 committed Sep 26, 2024
1 parent 277d8c6 commit 21f322e
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 42 deletions.
86 changes: 50 additions & 36 deletions api/auth/user/UserRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -574,24 +574,20 @@ func (handler UserRestHandlerImpl) FetchRoleGroupById(w http.ResponseWriter, r *
// RBAC enforcer applying
token := r.Header.Get("token")
filteredRoleFilter := make([]bean.RoleFilter, 0)
isManagerOfAnyApp := false
if res.RoleFilters != nil && len(res.RoleFilters) > 0 {
for _, filter := range res.RoleFilters {
authPass := true
if len(filter.Team) > 0 {
if ok := handler.enforcer.Enforce(token, casbin.ResourceUser, casbin.ActionGet, filter.Team); !ok {
authPass = false
}
}
if filter.Entity == bean2.CLUSTER_ENTITIY {
if isValidAuth := handler.userCommonService.CheckRbacForClusterEntity(filter.Cluster, filter.Namespace, filter.Group, filter.Kind, filter.Resource, token, handler.CheckManagerAuth); !isValidAuth {
authPass = false
if ok := handler.enforcer.Enforce(token, casbin.ResourceUser, casbin.ActionGet, filter.Team); ok {
isManagerOfAnyApp = true
break
}
}
if authPass {
filteredRoleFilter = append(filteredRoleFilter, filter)
}
}
}
if isManagerOfAnyApp || res.SuperAdmin {
filteredRoleFilter = res.RoleFilters
}
for index, roleFilter := range filteredRoleFilter {
if roleFilter.Entity == "" {
filteredRoleFilter[index].Entity = bean2.ENTITY_APPS
Expand Down Expand Up @@ -1176,7 +1172,7 @@ func (handler UserRestHandlerImpl) checkRBACForUserCreate(token string, requestS
}

func (handler UserRestHandlerImpl) checkRBACForUserUpdate(token string, userInfo *bean.UserInfo, isUserAlreadySuperAdmin bool, eliminatedRoleFilters,
eliminatedGroupRoles []*repository.RoleModel) (isAuthorised bool, err error) {
eliminatedGroupRoles []*repository.RoleModel, mapOfExistingRoleFilter, mapOfExistingUserGroup map[string]bool) (isAuthorised bool, err error) {
isActionUserSuperAdmin := handler.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionGet, "*")
requestSuperAdmin := userInfo.SuperAdmin
if (requestSuperAdmin || isUserAlreadySuperAdmin) && !isActionUserSuperAdmin {
Expand All @@ -1190,6 +1186,10 @@ func (handler UserRestHandlerImpl) checkRBACForUserUpdate(token string, userInfo
if !isAuthorised {
if roleFilters != nil && len(roleFilters) > 0 { //auth check inside roleFilters
for _, filter := range roleFilters {
if _, ok := mapOfExistingRoleFilter[filter.GetUniqueKey()]; ok {
isAuthorised = true
continue
}
switch {
case filter.AccessType == bean.APP_ACCESS_TYPE_HELM || filter.Entity == bean2.EntityJobs:
isAuthorised = isActionUserSuperAdmin
Expand Down Expand Up @@ -1227,41 +1227,51 @@ func (handler UserRestHandlerImpl) checkRBACForUserUpdate(token string, userInfo
}
}
if len(roleGroups) > 0 { // auth check inside groups
groupRoles, err := handler.roleGroupService.FetchRolesForUserRoleGroups(roleGroups)
if err != nil && err != pg.ErrNoRows {
handler.logger.Errorw("service err, UpdateUser", "err", err, "payload", roleGroups)
return false, err
filteredRoleGroupsForRbac := make([]bean.UserRoleGroup, 0, len(roleGroups))
for _, group := range roleGroups {
if _, ok := mapOfExistingUserGroup[group.GetUniqueKey()]; !ok {
filteredRoleGroupsForRbac = append(filteredRoleGroupsForRbac, group)
}
}
if len(groupRoles) > 0 {
for _, groupRole := range groupRoles {
switch {
case groupRole.Action == bean.ACTION_SUPERADMIN:
isAuthorised = isActionUserSuperAdmin
case groupRole.AccessType == bean.APP_ACCESS_TYPE_HELM || groupRole.Entity == bean2.EntityJobs:
isAuthorised = isActionUserSuperAdmin
case len(groupRole.Team) > 0:
isAuthorised = handler.enforcer.Enforce(token, casbin.ResourceUser, casbin.ActionCreate, groupRole.Team)
case groupRole.Entity == bean.CLUSTER_ENTITIY:
isAuthorised = handler.userCommonService.CheckRbacForClusterEntity(groupRole.Cluster, groupRole.Namespace, groupRole.Group, groupRole.Kind, groupRole.Resource, token, handler.CheckManagerAuth)
case groupRole.Entity == bean.CHART_GROUP_ENTITY:
isAuthorised = true
default:
isAuthorised = false
}
if !isAuthorised {
break
if len(filteredRoleGroupsForRbac) == 0 {
groupRoles, err := handler.roleGroupService.FetchRolesForUserRoleGroups(roleGroups)
if err != nil && err != pg.ErrNoRows {
handler.logger.Errorw("service err, UpdateUser", "err", err, "payload", roleGroups)
return false, err
}
if len(groupRoles) > 0 {
for _, groupRole := range groupRoles {
switch {
case groupRole.Action == bean.ACTION_SUPERADMIN:
isAuthorised = isActionUserSuperAdmin
case groupRole.AccessType == bean.APP_ACCESS_TYPE_HELM || groupRole.Entity == bean2.EntityJobs:
isAuthorised = isActionUserSuperAdmin
case len(groupRole.Team) > 0:
isAuthorised = handler.enforcer.Enforce(token, casbin.ResourceUser, casbin.ActionCreate, groupRole.Team)
case groupRole.Entity == bean.CLUSTER_ENTITIY:
isAuthorised = handler.userCommonService.CheckRbacForClusterEntity(groupRole.Cluster, groupRole.Namespace, groupRole.Group, groupRole.Kind, groupRole.Resource, token, handler.CheckManagerAuth)
case groupRole.Entity == bean.CHART_GROUP_ENTITY:
isAuthorised = true
default:
isAuthorised = false
}
if !isAuthorised {
break
}
}
} else {
isAuthorised = false
}
} else {
isAuthorised = false
isAuthorised = true
}
}
}
return isAuthorised, nil
}

func (handler UserRestHandlerImpl) checkRBACForRoleGroupUpdate(token string, groupInfo *bean.RoleGroup,
eliminatedRoleFilters []*repository.RoleModel) (isAuthorised bool, err error) {
eliminatedRoleFilters []*repository.RoleModel, mapOfExitingRoleFiltersKey map[string]bool) (isAuthorised bool, err error) {
isActionUserSuperAdmin := handler.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionGet, "*")
requestSuperAdmin := groupInfo.SuperAdmin
if requestSuperAdmin && !isActionUserSuperAdmin {
Expand All @@ -1272,6 +1282,10 @@ func (handler UserRestHandlerImpl) checkRBACForRoleGroupUpdate(token string, gro
if !isAuthorised {
if groupInfo.RoleFilters != nil && len(groupInfo.RoleFilters) > 0 { //auth check inside roleFilters
for _, filter := range groupInfo.RoleFilters {
if _, ok := mapOfExitingRoleFiltersKey[filter.GetUniqueKey()]; ok {
isAuthorised = true
continue
}
switch {
case filter.Action == bean.ACTION_SUPERADMIN:
isAuthorised = isActionUserSuperAdmin
Expand Down
9 changes: 9 additions & 0 deletions api/bean/UserRequest.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package bean

import (
"encoding/json"
"fmt"
"github.com/devtron-labs/devtron/pkg/auth/user/bean"
"time"
)
Expand Down Expand Up @@ -72,6 +73,10 @@ type RoleFilter struct {
Workflow string `json:"workflow"`
}

func (roleFilter RoleFilter) GetUniqueKey() string {
return fmt.Sprintf("%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s", roleFilter.Entity, roleFilter.Team, roleFilter.EntityName, roleFilter.Environment, roleFilter.Action, roleFilter.AccessType, roleFilter.Cluster, roleFilter.Namespace, roleFilter.Group, roleFilter.Kind, roleFilter.Resource, roleFilter.Workflow)
}

type Role struct {
Id int `json:"id" validate:"number"`
Role string `json:"role" validate:"required"`
Expand Down Expand Up @@ -155,3 +160,7 @@ type BulkDeleteRequest struct {
type UserRoleGroup struct {
RoleGroup *RoleGroup `json:"roleGroup"`
}

func (group UserRoleGroup) GetUniqueKey() string {
return fmt.Sprintf("%d-%s", group.RoleGroup.Id, group.RoleGroup.Name)
}
13 changes: 10 additions & 3 deletions pkg/auth/user/RoleGroupService.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package user
import (
"errors"
"fmt"
helper2 "github.com/devtron-labs/devtron/pkg/auth/user/helper"
"github.com/devtron-labs/devtron/pkg/auth/user/repository/helper"
"net/http"
"strings"
Expand All @@ -39,7 +40,7 @@ import (
type RoleGroupService interface {
CreateRoleGroup(request *bean.RoleGroup) (*bean.RoleGroup, error)
UpdateRoleGroup(request *bean.RoleGroup, token string, checkRBACForGroupUpdate func(token string, groupInfo *bean.RoleGroup,
eliminatedRoleFilters []*repository.RoleModel) (isAuthorised bool, err error)) (*bean.RoleGroup, error)
eliminatedRoleFilters []*repository.RoleModel, mapOfExistingRoleFilterKey map[string]bool) (isAuthorised bool, err error)) (*bean.RoleGroup, error)
FetchDetailedRoleGroups(req *bean.ListingRequest) ([]*bean.RoleGroup, error)
FetchRoleGroupsById(id int32) (*bean.RoleGroup, error)
FetchRoleGroups() ([]*bean.RoleGroup, error)
Expand Down Expand Up @@ -369,7 +370,7 @@ func (impl RoleGroupServiceImpl) CreateOrUpdateRoleGroupForJobsEntity(roleFilter
}

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

if checkRBACForGroupUpdate != nil {
isAuthorised, err := checkRBACForGroupUpdate(token, request, eliminatedRoleModels)
existingRoleGroupData, err := impl.FetchRoleGroupsById(roleGroup.Id)
if err != nil {
impl.logger.Errorw("error encountered in Update role group", "err", err, "roleGroupId", roleGroup.Id)
return nil, err
}
mapOfExitingRoleFiltersKey := helper2.GetMapOfUniqueRoleFilterKey(existingRoleGroupData.RoleFilters)
isAuthorised, err := checkRBACForGroupUpdate(token, request, eliminatedRoleModels, mapOfExitingRoleFiltersKey)
if err != nil {
impl.logger.Errorw("error in checking RBAC for role group update", "err", err, "request", request)
return nil, err
Expand Down
14 changes: 11 additions & 3 deletions pkg/auth/user/UserService.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ type UserService interface {
CreateUser(userInfo *bean.UserInfo) ([]*bean.UserInfo, error)
SelfRegisterUserIfNotExists(userInfo *bean.UserInfo) ([]*bean.UserInfo, error)
UpdateUser(userInfo *bean.UserInfo, token string, checkRBACForUserUpdate func(token string, userInfo *bean.UserInfo, isUserAlreadySuperAdmin bool,
eliminatedRoleFilters, eliminatedGroupRoles []*repository.RoleModel) (isAuthorised bool, err error)) (*bean.UserInfo, error)
eliminatedRoleFilters, eliminatedGroupRoles []*repository.RoleModel, mapOfExistingRoleFilter, mapOfExistingUserGroup map[string]bool) (isAuthorised bool, err error)) (*bean.UserInfo, error)
GetById(id int32) (*bean.UserInfo, error)
GetAll() ([]bean.UserInfo, error)
GetAllWithFilters(request *bean.ListingRequest) (*bean.UserListingResponse, error)
Expand Down Expand Up @@ -635,7 +635,7 @@ func (impl *UserServiceImpl) mergeUserRoleGroup(oldUserRoleGroups []bean.UserRol
}

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

if checkRBACForUserUpdate != nil {
isAuthorised, err := checkRBACForUserUpdate(token, userInfo, isUserSuperAdmin, eliminatedRoles, eliminatedGroupRoles)
// get existing permissions for user and ignore rbac for unchanged permissions whether direct permissions or group permissions
existingUserInfo, err := impl.GetById(model.Id)
if err != nil {
impl.logger.Errorw("error while fetching user from db", "error", err)
return nil, err
}
uniqueRolefilterKeyMap := userHelper.GetMapOfUniqueRoleFilterKey(existingUserInfo.RoleFilters)
existingRoleGroupKeyMap := userHelper.GetMapOfUniqueUserRoleGroup(existingUserInfo.UserRoleGroup)
isAuthorised, err := checkRBACForUserUpdate(token, userInfo, isUserSuperAdmin, eliminatedRoles, eliminatedGroupRoles, uniqueRolefilterKeyMap, existingRoleGroupKeyMap)
if err != nil {
impl.logger.Errorw("error in checking RBAC for user update", "err", err, "userInfo", userInfo)
return nil, err
Expand Down
16 changes: 16 additions & 0 deletions pkg/auth/user/helper/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,19 @@ func CreateErrorMessageForUserRoleGroups(restrictedGroups []bean2.RestrictedGrou
}
return errorMessageForGroupsWithoutSuperAdmin, errorMessageForGroupsWithSuperAdmin
}

func GetMapOfUniqueRoleFilterKey(roleFilters []bean2.RoleFilter) map[string]bool {
uniqueRoleFilterKeyMap := make(map[string]bool, len(roleFilters))
for _, roleFilter := range roleFilters {
uniqueRoleFilterKeyMap[roleFilter.GetUniqueKey()] = true
}
return uniqueRoleFilterKeyMap
}

func GetMapOfUniqueUserRoleGroup(userRoleGroups []bean2.UserRoleGroup) map[string]bool {
uniqueUserRoleGroupKeyMap := make(map[string]bool, len(userRoleGroups))
for _, userRoleGroup := range userRoleGroups {
uniqueUserRoleGroupKeyMap[userRoleGroup.GetUniqueKey()] = true
}
return uniqueUserRoleGroupKeyMap
}

0 comments on commit 21f322e

Please sign in to comment.